问题描述
||
我有一堂课:
class A
{
public:
A()
{
std::cout << \"Constructor called\" << std::endl;
}
~A()
{
std::cout << \"Destructor called\" << std::endl;
}
A(const A& another)
{
std::cout << \"Copy constructor called\" << std::endl;
}
A& operator=(const A& another)
{
std::cout << \"Assignment operator= called\" << std::endl;
}
};
在我非常复杂的项目中,启动应用程序后,得到以下输出:
Constructor called
但是当我按Ctrl + C终止我的应用程序时:
Destructor called
Destructor called
在整个过程中,没有调用复制构造函数或赋值运算符。
我的类A
具有动态内存分配,因此我必须在析构函数中释放它,但是析构函数以某种方式被调用了两次,这非常糟糕。
我不知道什么可能导致此问题。
我用谷歌搜索了很多。关于“两次调用析构函数”的很多问题是由于复制构造函数(赋值运算符)的隐式调用。
谢谢。
彼得
解决方法
如果您以某种方式两次调用了析构函数,则可能有两个对象认为它们通过指针拥有了它。
如果确实有两个认为自己拥有该对象的对象,请考虑使用引用计数的指针,例如Boost :: shared_ptr或tr1 :: shared_ptr来包含它。这样,您不必担心谁最终会调用析构函数。
除了调试器之外,您还可以尝试Valgrind(memcheck)查找程序在何处删除已释放的对象。在这种情况下,它可能不会提供比调试器更多的详细信息,但您应该早晚学习使用Valgrind(memcheck)。
另一种偏执策略是确保在删除内部指针后将其设置为NULL。
, 很可能您有一个没有显示的构造函数,或者您多次或通过显式或通过
delete
调用析构函数。
在这种情况下,调试器或附加的cout
会比我们更有用。
, 在析构函数中放置一个断点。然后,无论何时调用它,您都可以获取堆栈跟踪并查看从何处调用它。
编辑:
您可以期望复制省略号对此类琐碎的调试语句造成严重破坏。
, 就我而言,我没有使用任何指针,但是析构函数仍然被调用两次。我要解决的问题是重写副本分配运算符MyClass& operator=(const MyClass& other)
。不太确定为什么自动生成的运算符会引起问题,但看起来确实会引起问题。