【问题标题】:std::string and const char *std::string 和 const char *
【发布时间】:2015-02-28 16:48:52
【问题描述】:

如果我使用

const char * str = "Hello";

运行时不需要内存分配/释放

如果我使用

const std::string str = "Hello";

是否会在字符串类中通过 new/malloc 进行分配?我可以在汇编中找到它,但我不擅长阅读它。

如果答案是“是的,会有 malloc/new”,为什么?如果我需要编辑编辑字符串,为什么只能传递到 std::string 内的内部 const char 指针并进行实际内存分配?

【问题讨论】:

  • 这不取决于你的实现吗?
  • 请注意,这两个代码示例是不等价的,因为第二个允许修改字符串。想想这些的含义:char str[] = "Hello";const std::string str = "Hello";甚至static const std::string str = "Hello"
  • @NeilKirk 你是对的,我已经编辑了答案

标签: c++ string memory-management


【解决方案1】:

是否会在字符串类中通过 new/malloc 进行分配?

这取决于。 string 对象必须提供一些内存来存储数据,因为这是它的工作。一些实现使用“小字符串优化”,其中对象包含一个小缓冲区,并且仅当字符串太大时才从堆中分配。

如果我需要编辑编辑字符串,为什么只能通过 std::string 内部的内部 const char 指针并进行实际的内存分配?

您所描述的不一定是优化(因为每当您修改字符串时它都需要额外的运行时检查),并且在任何情况下迭代器无效规则都不允许。

有一个string_view 的提议,允许您使用类似const string 的接口访问现有的字符序列,而无需任何内存管理。它还不是标准的,并且不允许您修改字符串。

【讨论】:

  • string_view 看起来很有趣,因为我大部分时间都有 const 字符串 - 填充一次并且几乎从不修改(因为几乎, const char * 对我来说不是最好的解决方案)
【解决方案2】:

std::string 的幼稚实现将需要堆分配,但是如果在运行时未修改初始化的字符串,则允许编译器通过将它们替换为替代实现的对象来优化静态初始化的 std::string 对象。

您可以在实例化不可变字符串时使用const std::string 以确保更好的优化。

【讨论】:

  • 定义“最大优化”。在函数中,static cosnt std::string 会更加“优化”,因为每次函数调用的动态分配可能更少。
  • 你是对的。我的方法是支持堆栈,而不是整个内存空间。
  • 你假设字符串数据会在栈上。
【解决方案3】:

C++ 标准实际上并没有说您不能只存储指向外部字符串(和长度)的指针。但是,这意味着您每次可以修改字符串(例如char& std::string::operator[](size_t index))都必须确保该字符串实际上是可写的。由于大量的字符串使用并不仅仅使用常量字符串来存储字符串,而是确实修改了字符串[或使用了一个不是常量输入的字符串]。

所以,有些问题是;

std::string s = "Hello";
char &c = s[1]; 
c = 'a';    // Should make string to "Hallo". 

如果:

char buffer[1000];
cin.getline(buffer);   // Reads "Hello"
std::string s = buffer;
cin.getline(buffer);   // Reads "World"

s 现在的值是多少?

有很多这样的情况,如果你只是复制原始字符串,会导致更多的问题,而且几乎没有好处。

【讨论】:

  • 因为我的字符串在 90% 的情况下都是只读的(我将它们用作哈希键),所以额外的检查对我来说是可以的。对于您的第二个示例...不是 const char *,因此我希望将复制到 std::string 并且缓冲区未封装在字符串 s
  • 当然可以编写自己的类“const_string”或类似的确实不允许修改的类,并使用指针。考虑到这样一个字符串只允许几个操作,我想写起来不会花那么长时间。