【发布时间】:2014-02-21 06:55:36
【问题描述】:
考虑以下示例:
int main()
{
string x = "hello";
//copy constructor has been called here.
string y(x);
//c_str return const char*, but this usage is quite popular.
char* temp = (char*)y.c_str();
temp[0] = 'p';
cout << "x = " << x << endl;
cout << "y = " << y << endl;
cin >> x;
return 0;
}
在 Visual Studio 编译器和 g++ 上运行它。
当我这样做时,我得到了两个不同的结果。
在 g++ 中:
x = pello
y = pello
在视觉工作室 2010 中:
x = hello
y = pello
产生差异的原因很可能是 g++ std::string 实现使用了 COW(写入时复制)技术,而 Visual Studio 没有。
现在 C++ 标准(第 616 页表 64)说明了字符串复制构造函数
basic_string(const basic_string& str):
效果:data() 应该“指向数组的已分配副本的第一个元素,该数组的第一个元素由str.data() 指向”
意思是 COW 是不允许的(至少在我的理解中)。
怎么可能?
g++ 是否满足std::string C++11 的要求?
在 C++11 之前,这并没有造成什么大问题,因为 c_str 没有返回指向字符串对象所保存的实际数据的指针,因此更改它并不重要。但是在更改之后,这种 COW + 返回实际指针的组合可以并且破坏旧的应用程序(由于编码错误而应得的应用程序,但尽管如此)。
你同意我的观点吗?如果是,可以做些什么吗?有没有人知道如何在一个非常大的旧代码环境中处理它(一个发条规则来捕捉这个会很好)。
请注意,即使不强制转换常量,也可能通过调用 c_str、保存指针然后调用非 const 方法(这将导致写入)导致指针无效。
另一个没有抛弃 constness 的例子:
int main()
{
string x = "hello";
//copy constructor has been called here.
string y(x);
//y[0] = 'p';
//c_str return const char*, but this usage is quite popular.
const char* temp = y.c_str();
y[0] = 'p';
//Now we expect "pello" because the standart says the pointer points to the actual data
//but we will get "hello"
cout << "temp = " << temp << endl;
return 0;
}
【问题讨论】:
-
您是说使用指向常量数据的指针(以及非常临时的指针)作为指向非常量数据的指针“非常流行”?我觉得很难相信。事实上,尝试修改常量数据会导致未定义的行为(参见例如this reference)。
-
@buc030 链接的问题完全回答了这个问题;任何 COW 实现都是无效的。没有必要为每个 COW 实现设置单独的问题,尤其是那些将问题与
constUB 违规混淆的问题。 -
这不是“STL 中的错误”。这是 C++ 标准库(称为 libstdc++)的 GNU 实现的一个已知合规性问题。
-
@buc030, C++03 允许
c_str()是一个不同的指针,但也允许它指向实际数据。您没有很好地研究,请阅读您链接到的最佳答案中的 cmets。在 G++ 中,它始终指向实际数据,因此在这方面没有变化。