为什么这个"三个规则"的失败实际上失败了?

Tom*_*mmy 2 c++

昨天我学到了非常宝贵的一课:遵循三条法则.

我想我会更容易学习它,但错误只出现在删除声明中.这是场景:

foo.h
    class foo{
    public:
        ...
        foo(int *Y); 
        ~foo();  
        int *X;
    }
 foo.cpp
     ...
     (.. constructor sets X to Y..)
     foo:~foo(){
         delete [] X;
     }

main.cpp
    vector<Foo> fooVec;
    { // this is just to demonstrate scope problems more easily.  
         Y = new int[10000];
         (...init Y...)
         fooVec.push(Foo(Y)) // I get it: this calls copy constructor, violating rule of three
         (...forget to delete Y...)
    } 
    // Y is now out of scope so this is a memory leak
    cout << fooVec[0].[X][0] << " " <<  fooVec[0].[X][1] // THIS WORKS AS INTENDED DUE TO MEMORY LEAK
    // program ends, fooVec goes out of scope
Run Code Online (Sandbox Code Playgroud)

哪个炸弹"pointer being freed has not been allocated".我追溯到fooVec超出范围的地步,它调用了foos析构函数,它试图删除X.我的主要问题:为什么删除实际上失败了?我从来没有删除代码中的Y(我得到这是一个内存泄漏),所以我实际上并没有删除指针.而且,记忆显然存在,因为cout线路工作.如果条线路失败了,我会更早地发现问题.

下面的评论似乎表明"当Foo(Y)超出范围时,X被删除".但如果是这样的话,为什么地球上的cout声明有效呢?

注意:我没有复制构造函数和赋值重载,因此"三个失败的规则".由于矢量push_back语句,我得到了我应该拥有的.我问为什么不让他们在这里杀了我,因为我忘了释放Y所以我实际上并没有删除指针两次.

编辑:

感谢大家的帮助.user1158692s的答案总结了一下,但是所有评论中的回答也帮助我弄清楚到底发生了什么,他们坚持为我回答很多问题.如果可以,我会接受两个......

the*_*amb 5

[注意:newFoo不再是原始帖子的一部分,它指的是被推入向量的对象fooVec,现在已在现场完成:foovec.push_back( Foo(Y) )]

does双重删除.首先,当newFoo超出范围时,它会delete[] x(这是第一次删除).你在forget to delete Y这里写的,但Y实际上被删除了newFoo.

第二个删除是删除副本时newFoo(fooVec超出范围时).newFoo的副本也可以delete[] x,因为你没有复制构造函数,x所以newFoo在副本中和副本中都是相同的newFoo,因此它是双重删除.

现在,您将无法轻松解决此问题.因为在你要编写的复制构造函数中,你不知道如何复制x(它有多少个元素?1?100000?).

  • 当你释放内存时,它不会被破坏*.你只是说'这里的这段记忆现在可以用于别的东西了.访问被释放的内存*可能会起作用,或者它可能会对俄罗斯发动核攻击.换句话说,它是*未定义的行为*.`delete [] x`之后的@rubenvb,x是*not*NULL.即使在析构函数中将其设置为NULL也无济于事,因为`newFoo`的副本仍将具有原始指针值,并且它将尝试删除它. (2认同)