书中的测验"C++ Strategies and Tactics"

A quiz from the book "C++ Strategies and Tactics"

本文关键字:C++ Strategies and Tactics      更新时间:2023-10-16

我正在阅读《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指向。