Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::string常量的正确用法?_C++_String_Constants - Fatal编程技术网

C++ std::string常量的正确用法?

C++ std::string常量的正确用法?,c++,string,constants,C++,String,Constants,我有一个表示DB对象的映射。我想从中获得“众所周知”的价值观 std::map<std::string, std::string> dbo; ... std::string val = map["foo"]; 在hdr中,但我会得到多个副本 编辑:还没有回答如何声明std::string常量。忽略整个地图、STL等问题。很多代码都是面向std::string的(我的代码当然是这样),并且很自然地需要常量,而不必为内存分配付出太多的代价 编辑2:去掉曼纽尔用PDF回答的第二个问

我有一个表示DB对象的映射。我想从中获得“众所周知”的价值观

 std::map<std::string, std::string> dbo;
 ...
 std::string val = map["foo"];
在hdr中,但我会得到多个副本

编辑:还没有回答如何声明std::string常量。忽略整个地图、STL等问题。很多代码都是面向std::string的(我的代码当然是这样),并且很自然地需要常量,而不必为内存分配付出太多的代价

编辑2:去掉曼纽尔用PDF回答的第二个问题,增加了一个坏习惯用法的例子

编辑3:答案摘要。注意,我没有包括那些建议创建新字符串类的内容。我很失望,因为我希望有一个简单的东西只在头文件中工作(比如constchar*const)。反正

a) 来自马克b

 std::map<int, std::string> dict;
 const int FOO_IDX = 1;
 ....
 dict[FOO_IDX] = "foo";
 ....
 std:string &val = dbo[dict[FOO_IDX]];
c) 罗杰·p

 // really you cant do it
(b) 似乎最接近我想要的,但有一个致命的缺陷。我不能有使用这些字符串的静态模块级代码,因为它们可能尚未构造。我考虑过(a),事实上在序列化对象时使用了类似的技巧,发送索引而不是字符串,但对于一般用途的解决方案来说,这似乎有很多管道。不幸的是,(c)赢了,std:string没有简单的const习惯用法。复制和缺乏“字符串文字优化”正是std::string的工作方式,你无法得到你想要的东西。部分原因是明确避免了虚拟方法和dtor。无论如何,如果没有这些,std::string接口非常复杂

该标准要求std::string和std::map都有一个特定的接口,而这些接口恰好不允许您想要的优化(作为其其他需求的“意外结果”,而不是明确的)。至少,如果你想真正遵循标准的所有细节,他们是不允许的。您确实希望这样做,尤其是在很容易使用不同的字符串类进行特定优化的情况下

然而,这个单独的字符串类可以解决这些“问题”(正如您所说,这很少是一个问题),但不幸的是,世界上已经有
个程序员+1个
。即使考虑到轮子的重新发明,我也发现有一个StaticString类很有用,它有一个std::string接口的子集:使用begin/end、substr、find等。它也不允许修改(并以这种方式与字符串文本相适应),只存储一个字符指针和大小。您必须稍微小心,它只使用字符串文本或其他“静态”数据初始化,但构造接口在某种程度上减轻了这一点:

struct StaticString {
  template<int N>
  explicit StaticString(char (&data)[N]); // reference to char array
  StaticString(StaticString const&); // copy ctor (which is very cheap)

  static StaticString from_c_str(char const* c_str); // static factory function
  // this only requires that c_str not change and outlive any uses of the
  // resulting object(s), and since it must also be called explicitly, those 
  // requirements aren't hard to enforce; this is provided because it's explicit
  // that strlen is used, and it is not embedded-'\0'-safe as the
  // StaticString(char (&data)[N]) ctor is

  operator char const*() const; // implicit conversion "operator"
  // here the conversion is appropriate, even though I normally dislike these

private:
  StaticString(); // not defined
};
请注意,此类的主要优点是显式避免复制字符串数据,因此可以重用字符串文字存储。对于这些数据,在可执行文件中有一个特殊的位置,并且它通常都经过了很好的优化,因为它可以追溯到最早的C和更高版本。事实上,我觉得这个类与C++中的字符串文字应该是接近的,如果不是C兼容性要求的话。 通过扩展,如果这是一个非常常见的场景,那么您还可以编写自己的映射类,这可能比更改字符串类型更容易

  • 当您只需要一个常量字符串时,可以避免创建
    std::string
    的开销。但是您需要为此编写一个特殊的类,因为STL或Boost中没有类似的内容。或者更好的替代方法是使用Chromium的类
    StringPiece
    ,或者LLVM的类
    StringRef
    。有关更多信息,请参见此

  • 如果您决定继续使用
    std::string
    (您可能会这样做),那么另一个好的选择是使用Boost多索引容器,它具有以下功能(引用):

    Boost多索引[…]提供查找功能 接受搜索键的操作 不同于 索引,这是一个特别有用的 设置键类型对象时使用的工具 制作成本很高


  • Andrei Alexandrescu(C/C++Users Journal,2006年2月)的文章与您的问题有关,是一篇非常好的文章。

    问题在于
    std::map
    将键和值复制到它自己的结构中

    您可以使用
    std::map
    ,但必须提供函数对象(或函数)来比较键和值数据,因为此模具用于指针。默认情况下,
    映射将比较指针,而不是指针指向的数据

    取舍是一次性复制(
    std::string
    )与访问比较器(
    constchar*


    另一种选择是编写自己的
    map
    函数。

    正确的习惯用法就是您正在使用的。99.99%的时间不需要担心std::string构造函数的开销


    我想知道std::string的构造函数是否可以被编译器转换成一个内在函数?理论上这可能是可能的,但我上面的评论足以解释为什么没有发生。

    您似乎已经知道运行时字符串文本是什么,因此可以在枚举值和字符串数组之间设置内部映射。然后在代码中使用枚举而不是实际的const char*文本

    enum ConstStrings
    {
        MAP_STRING,
        FOO_STRING,
        NUM_CONST_STRINGS
    };
    
    std::string constStrings[NUM_CONST_STRINGS];
    
    bool InitConstStrings()
    {
        constStrings[MAP_STRING] = "map";
        constStrings[FOO_STRING] = "foo";
    }
    
    // Be careful if you need to use these strings prior to main being called.
    bool doInit = InitConstStrings();
    
    const std::string& getString(ConstStrings whichString)
    {
        // Feel free to do range checking if you think people will lie to you about the parameter type.
        return constStrings[whichString];
    }
    
    然后你会说
    map[getString(map\u STRING)]
    或类似的话

    作为旁白,也可以考虑用const引用存储返回值,而不需要复制,如果不需要修改它:

    const std::string& val = map["foo"];
    
    很简单:使用

    extern const std::string FOO;
    
    在标题中,以及

    const std::string FOO("foo");
    
    在相应的
    .cpp
    文件中。

    在C++14中,您可以执行以下操作

    const std::string FOO = "foo"s;
    

    我想你要找的是“boost::flyweight

    这是对共享字符串值的逻辑常量引用。非常高效的存储和高性能。

    我的解决方案(具有能够使用C++11所没有的功能的优势
    extern const std::string FOO;
    
    const std::string FOO("foo");
    
    const std::string FOO = "foo"s;
    
    #define INTERN(x) ([]() -> std::string const & { \
        static const std::string y = x; \
        return y; \
    }())
    
    my_map[INTERN("key")] = 5;