String pooling / interning - 这是一个好习惯吗?

时间:2014-09-02 11:00:02

标签: c++

作为一个例子,我有一个类,我在二进制文件中存储一些信息:

class car {
    char car_manufacturer;
    //other stuff
};

car_manufacturer的值是以下值之一:

enum car_manufacturers : char {
    VOLVO = 0,
    AUDI,
    MERCEDES
};

现在在这个示例应用程序中,用户将需要其汽车制造商的字符串表示而不是数字,因此我创建了一个数组,其中包含枚举的字符串表示形式,其中数组的顺序与枚举,因此car_manufacturer可以用作数组索引

std::string car_manufacturers_strings[MERCEDES + 1] = {
    "Volvo",
    "Audi",
    "Mercedes"
};

所以现在加载文件并从数据中创建car对象后,我可以简单地通过car_manufacturers_strings[car.car_manufacturer];

获取汽车的品牌。

这样做的好处是,在文件中我不必存储一堆重复的字符串,如果汽车是相同的,那么我节省了大量的空间。但缺点是代码稍微复杂一些。

这是好事还是坏事?

2 个答案:

答案 0 :(得分:2)

这是非常标准的做法,可以将枚举数的字符串表示形式提供为数组。

有一点是:

std::string car_manufacturers_strings[MERCEDES + 1] = {
    "Volvo",
    "Audi",
    "Mercedes"
};

在二进制文件中存储字符串文字,并在动态初始化阶段将这些文字的副本创建为std::string个对象。

您可能希望将其更改为:

char const* const car_manufacturers_strings[MERCEDES + 1] = {
    "Volvo",
    "Audi",
    "Mercedes"
};

这样就不会不必要地创建这些副本。

答案 1 :(得分:1)

我通常使用函数来执行此操作,如下所示:

char const * to_string(car_manufacturers cm) {
    switch (cm) {
        #define CASE(CM) case CM: return #CM;
        CASE(Volvo)
        CASE(Audi)
        CASE(Mercedes)
        #undef CASE
    }
    return "Unknown";  // or throw, or whatever
}

优点:

  • 无需将参数转换为数字索引,因此它可以使用范围枚举,而无需进行可怕的转换;
  • 如果我在没有更新函数的情况下添加枚举器,我的编译器会发出警告(不如删除重复,但至少强制执行一致性)

缺点:

  • switch可能(或可能不)效率低于数组查找
  • 枚举器的大写必须与字符串匹配,因此您必须放弃对SHOUTY_CAPS的迷信。有人会说这是件好事;他们当然伤害了我的眼睛。
  • Ewwww!宏!