14

std::string::c_str()返回一个指向数组的指针,该数组包含一个以空字符结尾的字符序列(即一个 C 字符串),表示字符串对象的当前值。

在 C++98 中,要求“程序不得更改此序列中的任何字符”。这是通过返回 const char* 来鼓励的。

在 C++11 中,“返回的指针指向字符串对象当前用于存储符合其值的字符的内部数组”,我相信不修改其内容的要求已被删除。这是真的?

这段代码在 C++11 中可以吗?

#include<iostream>
#include<string>
#include<vector>
using namespace std;

std::vector<char> buf;

void some_func(char* s)
{
    s[0] = 'X'; //function modifies s[0]
    cout<<s<<endl;
}

int main()
{
    string myStr = "hello";
    buf.assign(myStr.begin(),myStr.end());
    buf.push_back('\0');
    char* d = buf.data();   //C++11
    //char* d = (&buf[0]);  //Above line for C++98
    some_func(d);   //OK in C++98
    some_func(const_cast<char*>(myStr.c_str())); //OK in C++11 ?
    //some_func(myStr.c_str());  //Does not compile in C++98 or C++11
    cout << myStr << endl;  //myStr has been modified
    return 0;
}
4

4 回答 4

26

3 要求:程序不得更改存储在字符数组中的任何值。

该要求在 n3337 草案中仍然存在(与已发布的 C++11 标准最相似的工作草案是 N3337

于 2013-08-07T21:00:24.190 回答
5

在 C++11 中,是的,对于的限制c_str()仍然有效。(注意返回类型是const,所以这个函数实际上不需要特别的限制。const_cast你的程序中的 是一个很大的危险信号。)

但至于operator[],它似乎只是由于编辑错误而生效。由于 C++14 的标点符号更改,您可以对其进行修改。所以解释有点取决于你。当然,这样做很常见,以至于没有库实现敢于破坏它。

C++11 语句:

返回: *(begin() + pos) 如果 pos < size(),否则引用类型为 T 且值为 charT() 的对象;不得修改参考值。

C++14 措辞:

返回:*(begin() + pos) 如果 pos < size()。否则,返回对具有值 charT() 的 charT 类型对象的引用,其中修改对象会导致未定义的行为。

您可以将c_str()一个需要 C 字符串的函数作为只读引用传递,正如其签名所暗示的那样。期望读写引用的函数通常期望给定的缓冲区大小,并且能够通过NUL在该缓冲区中写入 a 来调整字符串的大小,而std::string实现实际上并不支持。如果你想这样做,你需要resize在字符串中包含你自己的NUL终止符,然后传递& s[0]它是一个读写引用,然后resize再次删除你的NUL终止符并将终止的责任交还给库。

于 2013-08-08T02:15:00.247 回答
3

我想说如果 c_str() 返回 aconst char *那么它就不行,即使它可以被语言律师认为是一个灰色区域。

我看到它的方式很简单。该方法的签名声明它返回的指针不应用于修改任何内容。

此外,正如其他评论者所指出的,还有其他方法可以做同样的事情而不违反任何合同。所以这样做绝对不行。

也就是说,Borgleader 发现语言仍然说它不是。

于 2013-08-07T21:28:44.283 回答
-2

我已经验证这在已发布的 C++11 标准中

谢谢

&myStr.front() 有什么问题?

string myStr = "hello";
char* p1 = const_cast<char*>(myStr.c_str());
char* p2 = &myStr.front();
p1[0] = 'Y';
p2[1] = 'Z';

看起来指针 p1 和 p2 完全一样。由于“程序不应更改存储在字符数组中的任何值”,因此上面的最后两行似乎都是非法的,并且可能很危险。

在这一点上,我回答自己的问题的方式是将原始 std::string 复制到向量中,然后将指向新数组的指针传递给任何可能更改字符的函数是最安全的。

由于我在原始帖子中给出的原因,我希望在 C++11 中可能不再需要这一步。

于 2013-08-08T01:42:30.480 回答