我应该使用std::string还是const char*来表示字符串常量?

41

我在代码中看到了这两种风格,但不确定哪种更好(它只是一种风格问题吗)?您是否有任何建议,为什么会选择其中一种而不是另一种。

 //Example1
 class Test {

    private:
        static const char* const str;

};

const char* const Test::str = "mystr";

//Example2
class Test {

     private:
         static const std::string str;

};

const std::string Test::str ="mystr";
7个回答

57

通常情况下,你应该优先选择使用std::string而不是简单的char指针。但是,在这里,用字符串字面值初始化的char指针有显著的优势。

静态数据有两种初始化方式。一种称为静态初始化,另一种称为动态初始化。对于那些使用常量表达式初始化且是POD类型(如指针)的对象,C++要求它们的初始化在动态初始化发生之前的最开始时刻就完成。使用std::string进行初始化将会在动态初始化时完成。

如果你有一个类的对象是某个文件中的静态对象,并且在其初始化期间需要访问字符串,则可以依赖于使用const char* const版本时已经设置好了它,而使用未静态初始化的std::string版本时,你不知道是否已经初始化了字符串——因为跨转换单元边界的对象初始化顺序没有定义。


8
+1 我花了很多时间调试一些非常恶心的崩溃问题,结果发现是由于静态实例化的字符串类在初始化顺序出现问题时导致的。避免使用静态实例化的std::string - the_mandrill
1
我对这个答案感到非常惊讶。有没有办法让它与std::string一起工作? - loop
@test: 是的:std :: string const&safe_string_const(){std :: string static const var ="const";返回var;} - Andriy Tylychko
@AndyT 你应该把 static 放在类型前面。它是一个存储类别说明符(例如 extern 或者(对于成员)mutable),不是一个 cv-限定符(constvolatile)。所以 int static i = 0; 确实可以编译,但是 int* static p = 0; 就不行了。(好吧,int static* p 可以,但是请写成 static int* p。非常感谢。) - gx_

4

嗯,std :: string与const char *不同。 我通常倾向于使用std :: string,因为它是一个具有许多附加功能的类,使其更易于使用。

如果性能至关重要,并且您正在使用const char *以提高效率,请选择这种方式。


3

在进行C++编程时,我更倾向于使用std::string而不是char *。主要原因是std::string具有内置的功能,并且方便、安全,不需要处理指针。

然而,正如其他人所提到的,如果您过于关注性能,则const char *版本可能更可取。我记得有个聪明人曾经说过,“过早地优化是万恶之源”(或类似的话)。 :)


2
第一个示例需要更少的开销来管理字符串(即只有指向TEXT部分的指针)。而第二种方法可能还需要进行堆分配,将字符串常量复制到std:string类缓冲区中。因此,您最终会得到两个数据副本。

2
在涉及多平台、多编译器和库、多团队与多人参与的大型项目中,我们反复遇到了静态 std::strings 的问题。在某些平台上,std:string 实现不是线程安全的。在一个平台上,编译器优化的代码跳过了对于全局静态 const 变量初始化本地 std:string 的步骤。在解决了几个这样的问题后,我们只允许全局静态常量用于内置类型。

1
第二个版本的优点在于它具有预先计算的长度和其他完整字符串类的优点。第一个版本的优点在于唯一的初始化只是将指针分配给已经加载到可执行映像中的静态数据,而第二个版本必须从同一指针初始化字符串。

是的,但它是一个O(n)操作,所以根据使用情况,这可能是一个问题。 - Eclipse
但我想这只是关于std::string与char*在一般情况下的好处的辩论。 - Eclipse

1

首先,如果您想要一个 ASCIIZ 字符串,不要使用 char*。直接定义一个:

const char Test::str[] = "mystr";

大多数情况下,这就是我会使用的方式。为什么要浪费时间和内存来处理字符串类的开销呢?

请注意,“sizeof(Test::str)”将准确地给出数组的长度,即字符串的长度,包括终止的 NUL(strlen(str)+1)。


说 std::string 浪费内存有点奇怪,因为你只是把一个完好的 const char[] 复制到另一个 const char[] 中,这样浪费了 sizeof(Test::str) 的内存空间。 - MSalters
谁在复制任何东西?"const int x = 5;" 是否在复制任何东西?只有一个 char[],内在地保存着值 "mystr"; - James Curran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接