书中的测验"C++ Strategies and Tactics"
A quiz from the book "C++ Strategies and Tactics"
我正在阅读《c++战略与战术》这本书,对下面的代码感到困惑。作者说,手术可能不安全。但是,我还没有找到原因。你能帮我吗?
#include <iostream>
#include <string.h>
void remove_blanks(char* cp)
{
char*p = cp;
while(*p)
{
if(*p != ' ')
*cp++ = *p;
++p;
}
*cp = ' ';
}
class String
{
public:
String(char* p = " "):str(new char[strlen(p) + 1])
{
strcpy(str,p);
}
~String()
{
delete []str;
}
operator const char* () const
{
return (const char*)str;
}
private:
char* str;
};
int main()
{
String s("hello world");
remove_blanks((char*)(const char*)s);
std::cout << s << ".n";
}
在remove_blanks:
中修改字符串(在链式强制转换之后)是明显未定义的行为:来自7.1.6.1 cv-qualifiers指向cv限定类型的指针或引用实际上不需要指向或引用
指向符合cv条件的对象,但它被视为符合cv条件的对象;一个const限定的访问路径不能用于修改对象,即使引用的对象是非const对象,可以修改通过其他访问路径。[注:cv限定符由类型系统,使它们不能在不强制转换的情况下被破坏(5.2.11)。除了任何被声明为可变的类成员(7.1.1)可以被修改,在
我花了很多时间反复阅读这个循环,但我认为问题在于:
c++类String
拥有其私有成员str
所指向的内存。一旦外部代码段使用类型转换操作符获得该指针的副本,它就没有方法来判断底层缓冲区何时已被delete[]
编辑。
更改str
指向的内存也可能使指向同一缓冲区的任何其他未完成的指针无效。缩短字符串可以使其他指针已经指向字符串的NULL结束符。(虽然在这个特定的例子中,原始的' '仍然存在)。
一旦String
被删除,堆上的其他分配可能会重用那块内存。之后调用remove_blanks()
将导致难以调试的灾难。
可以通过以下方法来避免这种情况:直接用strcpy()
复制字符串,然后使用std::shared_ptr<char *>
,或者将remove_blanks()
作为String
的成员函数,并完全取消这些指针。
谢谢你的回答。一开始,我认为问题是前一个str
是"hello world "
,后一个str
是"helloworld "
,如果delete []str
直到第一个' '
才停止释放内存,就会导致memory leak
。Bug,当我发现"delete operator"
会根据之前的"4 byte int
"释放str
指向的内存时,我意识到我想太多了。现在我认为问题是它可能导致re-delete
内存str指向。