char * vs std :: string在C ++中[关闭]


81

什么时候应该使用std::string,什么时候应该使用C ++char*管理chars的数组?

似乎您应该使用char*性能(速度)是否至关重要,并且由于内存管理,您愿意接受一些冒险的业务。

还有其他情况要考虑吗?

Answers:


56

您可以通过引用传递std :: strings(如果它们很大以避免复制)或指向该实例的指针,因此我看不到使用char指针有什么真正的好处。

我将std :: string / wstring用于或多或少是实际文本的所有内容。char *但是对于其他类型的数据很有用,并且您可以确保将其按应有的方式释放。否则,std :: vector是要走的路。

所有这些可能都有例外。


8
两者之间在性能上有区别吗?
vtd-xml-author

3
@ vtd-xml-author:也许有些。直行char *几乎没有开销。std::string我不知道确切的开销,这可能取决于实现。我几乎不希望开销比裸char指针大得多。由于我没有该标准的副本,因此我无法详细说明该标准所作的任何保证。任何性能差异都可能取决于要执行的操作。std::string::size可以将大小存储在字符数据旁边,因此比strlen
Skurmedel

2
为什么不对非文本数据使用std :: string?它们不是以null结尾的,因此您应该能够在其中存储任何内容。
Casey Rodarmor 2012年

1
@rodarmor您可以存储所需的任何内容,尽管它具有一定的风险,因为该字符串是为以null终止的字符串设计的。你必须小心,只使用二进制安全的操作,例如append(const string&)append(const char*, size_t)替代的operator+=()
boycy

6
你确定吗?我知道很多操作都假定char *是一个以null终止的字符串,但是我想不出任何假设std :: string不包含任何null的字符串。
Casey Rodarmor 2012年

57

我的观点是:

  • 如果不调用“ C”代码,切勿使用char *。
  • 始终使用std :: string:它更容易,更友好,经过优化,是标准的,它将防止您遇到错误,并且已经过检查并证明可以工作。

13

原始字符串用法

是的,有时候您确实可以做到这一点。当使用const char *,在堆栈上分配的char数组和字符串文字时,您可以用完全没有内存分配的方式来实现。

编写这样的代码通常比使用字符串或向量需要更多的思考和关怀,但是使用适当的技术就可以做到。使用适当的技术,代码可以很安全,但是在复制到char []时,您始终需要确保对复制的字符串的长度有一定的保证,或者可以优雅地检查和处理超大的字符串。不这样做就是给strcpy功能系列以不安全的声誉。

模板如何帮助编写安全的char缓冲区

至于char []缓冲区的安全性,模板可以提供帮助,因为它们可以创建封装来为您处理缓冲区大小。像这样的模板是由Microsoft实施的,以提供strcpy的安全替代品。这里的示例是从我自己的代码中提取的,真实的代码有很多方法,但这足以传达基本思想:

template <int Size>
class BString
{
  char _data[Size];

  public:
  BString()
  {
    _data[0]=0;
    // note: last character will always stay zero
    // if not, overflow occurred
    // all constructors should contain last element initialization
    // so that it can be verified during destruction
    _data[Size-1]=0;
  }
  const BString &operator = (const char *src)
  {
    strncpy(_data,src,Size-1);
    return *this;
  }

  operator const char *() const {return _data;}
};

//! overloads that make conversion of C code easier 
template <int Size>
inline const BString<Size> & strcpy(BString<Size> &dst, const char *src)
{
  return dst = src;
}

1
+1表示“使用const char *时,在堆栈上分配的char数组和字符串文字可以完全不分配内存的方式来实现。” 人们忘记了堆栈的“分配”要比堆快得多。
NoSenseEtAl 2011年

char*字符串并不总是在堆栈上。char *str = (char*)malloc(1024); str[1024] = 0;
科尔·约翰逊

@ColeJohnson我并不是要声明这一点,我只是说,如果您想对字符串进行堆栈分配,则需要将const char *与字符串文字结合使用,而不是std :: string。
Suma 2013年

9

您必须使用char*而不std::string应该使用的一种情况是需要静态字符串常量。这样做的原因是,您无法对订单模块初始化其静态变量进行任何控制,并且来自其他模块的另一个全局对象可能在初始化之前引用了您的字符串。http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Static_and_Global_Variables

std::string 优点:

  • 为您管理内存(字符串可以增长,实现将为您分配更大的缓冲区)
  • 更高级别的编程接口可与STL的其余部分很好地配合。

std::string缺点:-两个不同的STL字符串实例不能共享相同的基础缓冲区。因此,如果您按值传递,则始终会得到一个新副本。-有一些性能损失,但是我要说,除非您的要求特殊,否则可以忽略不计。


实际上,STL实现通常为std :: string实现写时复制语义,因此按值传递它们根本不会花费太多。尽管如此,还是最好不要依赖它,并且总的来说还是要传递一个引用常量的引用。

1
一些std :: string实现放弃了COW实现。而且,它似乎并不像提供与标准兼容的(POSIX)线程安全类那样简单。见groups.google.fr/group/ifi.test.boa/browse_frm/thread/...groups.google.fr/group/comp.programming.threads/browse_frm/...
吕克Hermitte

8

您应考虑char*在以下情况下使用:

  • 该数组将在参数中传递。
  • 您预先知道了阵列的最大大小(您知道它或您强加了它)。
  • 您将不会对该数组进行任何转换。

实际上,在C ++中,char*通常用于固定小词,例如选项,文件名等。


3
数组未传递,指向数组的指针。这就是指针—指向对象的指针。
科尔·约翰逊

5

何时使用C ++ std :: string:

  • 总体而言,字符串比char *更安全。通常,在使用char *进行操作时,您必须检查所有内容以确保一切正确,在字符串类中,所有这些都为您完成了。
  • 通常,在使用char *时,您将必须释放分配的内存,而不必使用string进行处理,因为它在被破坏时会释放其内部缓冲区。
  • 字符串可以与c ++字符串流一起很好地工作,格式化IO非常容易。

何时使用char *

  • 使用char *可让您更好地控制“幕后”发生的事情,这意味着您可以根据需要调整性能。

3

如果要编写库,请使用(const)char *作为参数。不同编译器之间的std :: string实现不同。


如果您使用C ++编写库,则不必担心std :: string的布局。两种实现之间存在许多潜在的不兼容性。仅在源代码可用或针对您正在使用的确切编译器进行编译时,才使用C ++库。C库通常更可移植,但是在那种情况下,您仍然没有std :: string。
David Thornley,2009年

诚然,std :: string并不是唯一的问题,但得出的结论是“仅在源代码中可用或针对所使用的确切编译器进行编译时,才在C ++中使用库”。有些组件系统可以与不同的编译器(例如COM)配合使用,并且可以将C接口暴露给内部用C ++编写的库(例如Win32 API)
Nemanja Trifunovic

2

如果要使用C库,则必须处理C字符串。如果要将API公开给C,同样适用。


2

您可以期望对std :: string的大多数操作(例如find)应尽可能优化,因此它们的性能至少可能与纯C语言相当。

还值得注意的是,std :: string迭代器经常映射到指向底层char数组的指针。因此,就性能而言,您在迭代器之上设计的任何算法本质上都与char *之上的相同算法相同。

需要注意的事情是operator[]-例如,大多数STL实现不执行边界检查,而应将其转换为对基础字符数组的相同操作。AFAIK STLPort可以选择执行边界检查,这时该运算符会慢一些。

那么使用std :: string有什么好处呢?它使您免于手动内存管理;调整数组大小变得更加容易,并且通常不必考虑释放内存。

如果您担心调整字符串大小时的性能,可以使用一个reserve有用的函数。


1

如果您使用字符数组(如文本等),请使用std :: string更灵活且更易于使用。如果将它用于数据存储等其他内容?使用数组(首选向量)


1

即使性能至关重要,您vector<char>也可以更好地使用它-它可以提前分配内存(reserve()方法),并有助于避免内存泄漏。使用vector :: operator []会导致开销,但是您始终可以提取缓冲区的地址并对其进行完全索引,就像它是char *一样。


但是,最好使用某种典型的字符串功能,并且可以选择指定存储策略。为此,请参阅我的答案中的链接。
匿名

事实并非如此。如果您认为向量将在连续的内存空间中分配,则重新分配(以增加向量的大小)将根本没有效率,因为它暗示了前一个块的副本。
杰罗姆

我误解了您的回答,因为您使用向量而不是char *,而不是字符串...在这种情况下,我同意。
杰罗姆

运算符[]的使用不应有任何开销。参见例如stackoverflow.com/questions/381621/…–
卢克·赫米特

-1

AFAIK内部最std :: string实现写时复制,引用计数语义,以避免开销,即使字符串没有通过引用传递。


5
这不再是正确的,因为写时复制会在多线程环境中引起严重的可伸缩性问题。
苏马

至少对于GCC实施STL而言如此。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.