昨天我学到了非常宝贵的一课:遵循三条法则.
我想我会更容易学习它,但错误只出现在删除声明中.这是场景:
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的答案总结了一下,但是所有评论中的回答也帮助我弄清楚到底发生了什么,他们坚持为我回答很多问题.如果可以,我会接受两个......
[注意: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?).