这本书的测验" C ++策略与策略"

时间:2014-05-13 11:22:22

标签: c++

我正在阅读“C ++ Strategies and Tactics”一书,并对以下代码感到困惑。作者说,手术可能不安全。但是,我还没有理由。你能救我吗?

#include <iostream>
#include <string.h>

void remove_blanks(char* cp)
{
    char*p = cp;
    while(*p)
    {
        if(*p != ' ')
            *cp++ = *p;
        ++p;
    }
    *cp = '\0';
}
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";
}

3 个答案:

答案 0 :(得分:6)

在remove_blanks中修改字符串(在链接的强制转换之后)是明确的未定义行为:

来自7.1.6.1 cv-qualifiers 指向cv限定类型的指针或引用无需实际指向或引用

  

到一个cv限定的对象,但它被视为它;一个   const限定访问路径即使不能用于修改对象   引用的对象是非const对象,可以修改   通过其他一些访问路径。 [注意:Cv限定符受到支持   类型系统,以便它们不会在没有铸造的情况下被颠覆   (5.2.11)。 - 结束注释]除了任何类成员声明可变   (7.1.1)可以修改,任何修改const对象的尝试   它的生命周期(3.8)导致未定义的行为。

答案 1 :(得分:0)

我花了很多时间阅读并重新阅读该循环,但我认为问题是:

C ++类String拥有其私有成员str指向的内存。一旦外部代码使用类型转换运算符来获取该指针的副本,它就有 no 方式告知基础缓冲区何时被delete[]编辑。

更改str指向的内存也可能使指向同一缓冲区的任何其他未完成指针无效。缩短字符串可能会使其他指针已经指向字符串的NULL终止符。 (虽然在这个具体的例子中,原作&#39; \ 0&#39;仍然存在)。

删除String后,堆上的不同分配可能会重用该内存。之后调用remove_blanks()将导致难以调试的灾难。

可以通过以下方式直接使用strcpy()创建字符串的新副本,使用std::shared_ptr<char *>,或使remove_blanks()成为String的成员函数并执行此操作来避免这种情况完全放弃这些指针。

答案 2 :(得分:0)

感谢您的回答。 一开始,我认为问题是前一个str"hello world\0"而后一个str"helloworld\0\0",如果delete []str不是'\0'停止释放内存直到第一个memory leak,它将导致"delete operator"。 当我发现str根据&#34; 4 byte int&#34; re-delete释放内存{{1}}时,会发现错误在那段记忆之前,我意识到我已经想得太多了。 现在我认为问题是它可能导致{{1}}内存str指向。