为什么要在C ++中使用C字符串?
现在是否有充分的理由在C ++中使用C字符串?我的教科书有时在示例中使用它们,我真的觉得仅使用std :: string会更容易。
解决方案
因为这就是它们来自众多API /库的原因?
STL字符串肯定更容易使用,我看不出没有理由不使用它们。
如果需要与仅使用C样式字符串作为参数的库进行交互,则始终可以调用字符串类的c_str()方法。
我不得不使用它们的唯一原因是在与使用C样式字符串的第三方库进行接口时。在某些情况下,出于性能原因,我们可能会使用C样式字符串,但在很多情况下,由于内联和特殊化等原因,在C ++字符串上使用方法可能会更快。
在使用这类API的许多情况下,我们可以使用c_str()
方法,但是我们应该知道返回的char *是const,并且不应通过该指针修改字符串。在这种情况下,我们仍然可以使用vector <char>代替,至少可以从简化的内存管理中受益。
假设代码中有一些字符串常量,这是很常见的需求。最好将它们定义为C字符串,而不是C ++对象-更轻量,更可移植等。现在,如果要将这些字符串传递给各种函数,那么这些函数接受C字符串而不是C ++会很好。字符串对象。
当然,如果字符串是可变的,那么使用C ++字符串对象会更加方便。
如果C ++代码"很深"(靠近内核,在很大程度上依赖于C库等),则我们可能希望显式使用C字符串,以避免大量的进出std :: string的转换。当然,如果我们要与其他语言域(Python,Ruby等)交互,则可能出于相同的原因。否则,请使用std :: string。
如果一个函数需要一个常量字符串,即使程序使用std :: string,CString,EString或者其他函数,我仍然更喜欢使用'const char *'(或者const wchar_t *)。
在大型代码库中,有太多的字符串源来确保调用者将字符串作为std :: string来使用,并且'const char *'是最低的公分母。
有了选择,通常没有理由选择原始C字符串(char *)而不是C ++字符串(std :: string)。但是,通常我们没有选择的余地。例如,出于历史原因,std :: fstream
的构造函数采用C字符串。另外,C库(我们猜对了!)使用C字符串。
在我们自己的C ++代码中,最好使用std :: string
并通过使用std :: string
的c_str()
函数根据需要提取对象的C字符串。
教科书使用老式的C字符串,因为许多基本功能仍然期望它们作为参数或者返回它们。此外,它还可以深入了解内存中字符串的基本结构。
这取决于我们使用的库。例如,在使用MFC时,在使用Windows API的各个部分时通常更容易使用CString。在Win32应用程序中,它的性能似乎也比std :: string好。
但是,std :: string是C ++标准的一部分,因此,如果要更好的可移植性,请使用std :: string。
对于诸如大多数嵌入式平台这样的应用程序,在这些应用程序中我们没有足够的堆来存储要操作的字符串,并且需要确定性地预先分配字符串缓冲区。
c字符串不承担成为类的开销。
c字符串通常可以更快地执行代码,因为它们更接近机器级别
这并不是说,我们不能用它们编写错误的代码。像其他所有构造一样,它们也可能被滥用。
出于历史原因,有很多要求他们使用的图书馆呼吁。
学习使用c字符串和stl字符串,并在合理的情况下使用它们。
通常这样做的原因是我们喜欢在字符串处理中编写缓冲区溢出。计数的字符串比终止的字符串好得多,很难理解为什么C设计人员曾经使用终止的字符串。那时,这是一个错误的决定;现在这是一个错误的决定。
内存控制。我最近不得不在大型多线程应用程序中处理大小约为200-300 MB的字符串(实际上是数据库中的blob)。在这种情况下,字符串的一个或者多个副本可能会破坏32位地址空间。我必须确切知道该字符串存在多少个副本。尽管我是STL的传播者,但是我使用char *,因为它可以确保没有分配额外的内存,甚至没有额外的副本。我确切知道需要多少空间。
除此之外,标准的STL字符串处理错过了一些用于字符串处理/解析的出色C函数。值得庆幸的是,std :: string具有c_str()方法,用于对内部缓冲区的const访问。要使用printf(),我们仍然必须使用char *(这是C ++团队的疯狂想法,不包括类似于printf的功能,这是C中有史以来最有用的功能之一。我希望boost :: format将不久将包含在STL中。
还有更多的内存控制注意事项:
C字符串是POD类型,因此可以在应用程序的只读数据段中分配它们。如果我们在命名空间范围内声明并定义std :: string
常量,则编译器将生成在main()
之前运行的其他代码,该代码为每个常量调用std :: string
构造函数。如果应用程序有许多常量字符串(例如,如果我们生成了使用常量字符串的C ++代码),则在这种情况下C字符串可能更可取。
std :: string的某些实现支持称为SSO("短字符串优化"或者"小字符串优化")的功能,其中std :: string类包含用于存储一定长度字符串的功能。这增加了std :: string的大小,但通常会大大减少免费存储分配/取消分配的频率,从而提高性能。如果std :: string
实现不支持SSO,那么在堆栈上构造一个空的std :: string
仍将执行免费存储分配。在这种情况下,对于使用字符串的性能至关重要的代码,使用临时堆栈分配的C字符串可能会有所帮助。当然,在执行此操作时,请务必小心,不要向自己的脚开枪。
一些帖子提到了内存问题。这可能是避免std :: string的好理由,但是char *可能不是最好的替代方法。它仍然是一种面向对象的语言。我们自己的字符串类可能比char *好。例如,我们可以应用小字符串优化,甚至可能更高效。
以我为例,我试图从2GB的文件中获取大约1GB的字符串,将它们填充到具有约60个字段的记录中,然后对它们进行7次不同字段的排序。我的前任代码使用char *花费了25个小时,而我的代码运行了1个小时。
1)"字符串常量"是一个C字符串(const char *),将其转换为const std :: string&是运行时进程,不一定是简单的或者优化的。
2)fstream库使用c样式的字符串传递文件名。
我的经验法则是,如果我无论如何都要将数据用作std :: string(例如,当我将它们存储在矢量中时),则传递const std :: string&;在其他情况下,则传递const char *。
在花费了太多,太多的时间调试初始化规则以及在多个平台上的每种可能的字符串实现之后,我们要求静态字符串为const char *。
在花费了太多,太多的时间调试错误的char *代码和内存泄漏之后,我建议所有非静态字符串都是某种类型的字符串对象...直到性能分析表明我们可以并且应该做得更好;-)