在他的网站2008年的一篇文章中,Herb Sutter陈述如下:
由于与并发相关的原因,有一个积极的建议是在C ++ 0x中进一步加强这一点,并且需要空终止并且可能禁止写时复制。这是论文:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2534.html。我认为本文中的一个或两个提案很可能会被采纳,但我们会在下一个或两个会议上看到。
我知道C ++ 11现在保证std :: string内容连续存储,但他们是否在最终草案中采用了上述内容?
现在使用像&str[0]
这样的东西是否安全?
答案 0 :(得分:49)
是。根据C ++ 0x FDIS 21.4.7.1/1,std::basic_string::c_str()
必须返回
指针
p
,p + i == &operator[](i)
中每i
个[0,size()]
。
这意味着给定字符串s
,s.c_str()
返回的指针必须与字符串(&s[0]
)中的初始字符的地址相同。
答案 1 :(得分:-2)
尽管 c_str() 返回一个空终止版本的 std::string,但在将 C++ std::string 与 C char* 字符串混合时可能会出现意外。
空字符可能会出现在 C++ std::string 中,这会导致细微的错误,因为 C 函数会看到较短的字符串。
错误代码可能会覆盖空终止符。这会导致未定义的行为。然后,C 函数会读取超出字符串缓冲区的内容,从而可能导致崩溃。
#include <string>
#include <iostream>
#include <cstdio>
#include <cstring>
int main()
{
std::string embedded_null = "hello\n";
embedded_null += '\0';
embedded_null += "world\n";
// C string functions finish early at embedded \0
std::cout << "C++ size: " << embedded_null.size()
<< " value: " << embedded_null;
printf("C strlen: %d value: %s\n",
strlen(embedded_null.c_str()),
embedded_null.c_str());
std::string missing_terminator(3, 'n');
missing_terminator[3] = 'a'; // BUG: Undefined behaviour
// C string functions read beyond buffer and may crash
std::cout << "C++ size: " << missing_terminator.size()
<< " value: " << missing_terminator << '\n';
printf("C strlen: %d value: %s\n",
strlen(missing_terminator.c_str()),
missing_terminator.c_str());
}
输出:
$ c++ example.cpp
$ ./a.out
C++ size: 13 value: hello
world
C strlen: 6 value: hello
C++ size: 3 value: nnn
C strlen: 6 value: nnna�
答案 2 :(得分:-2)
&str[0]
可以安全使用——只要您不假设它指向以空字符结尾的字符串。
从 C++11 开始,要求包括([string.accessors] 部分):
str.data()
和 str.c_str()
指向一个以空字符结尾的字符串。&str[i]
== str.data() + i
,对于 0 <= i <= str.size()
但是,不要求 &str[0] + str.size()
指向空终止符。
当调用 data()
、c_str()
或 operator[](str.size())
时,符合要求的实现必须将空终止符连续放置在存储中;但不需要将其置于任何其他情况下,例如使用其他参数调用 operator[]
。
为了节省您阅读下面冗长的聊天讨论: 有人提出反对意见,即如果 c_str()
写入空终止符,则会导致 {{3 }};我不同意这将是一场数据竞赛。