c++ std::string reserve是否为null分配额外的字节?

4ioopgfo  于 2023-06-25  发布在  其他
关注(0)|答案(3)|浏览(151)

这个问题是由以下来自how to pre-allocate memory for a std::string object?的代码片段引起的

  1. file.seekg(0, std::ios::end);
  2. s4.resize(file.tellg());
  3. file.seekg(0, std::ios::beg);
  4. file.read(&s4[0], s4.length());

在我看来,只有resize()首先为null分配了一个额外的字节,才能保证正确(后续s4.data()将返回长度为N,总大小为N+1字节的以null结尾的字符串)和有效(s4.data()不需要进行额外的重新分配/复制)。
它确实这样做了吗?

j0pj023g

j0pj023g1#

C++标准([basic.string])规定,对于std::basic_string<charT>
data() + size()指向具有值charT()的对象(“空终止符”),
此外,数据必须是连续的。因此,是的。在字符串数据之后总是分配一个终止字符,以使其成为有效的C字符串。

qlvxas9a

qlvxas9a2#

如果你在libstdc中查看basic_string的源代码,你可以看到这是在_M_create函数中完成的:

  1. // NB: Need an array of char_type[__capacity], plus a terminating
  2. // null char_type() element.
  3. return _S_allocate(_M_get_allocator(), __capacity + 1);

所以对于libstdc,是的,这已经完成了。
但是否需要这样做完全取决于底层实现如何处理内存。例如,如果底层OS已经保证对于给定指针,在分配的存储器之后的访问将总是导致\0,则这将不是必需的。
附带说明:
实现可以(并且这也是AFAIK针对小字符串优化部分完成的)使用包含关于字符串长度的信息的存储器,也用于空终止部分。
所以你可以有这样的东西:

  1. struct string {
  2. size_t capacity;
  3. char* data;
  4. }

数据可能是这样的:
[number of bytes equal to capacity][bytes required for storing length]
长度存储为max_capacity-lenght_of_string,因此如果字符串达到最大容量,则存储长度的字节将为0,然后可以用作空终止,因此不需要为\0分配额外的字节(仅为长度的字节)。

展开查看全部
r8xiu3jd

r8xiu3jd3#

终止符不算作std::string中的元素
你也可以用正确的大小来初始化字符串

  1. size_t = file.tellg();
  2. std::string str(size, '\0');
  3. file.seekg(0);
  4. file.read(&str[0], size);

https://en.cppreference.com/w/cpp/io/basic_istream/read

相关问题