析构函数被调用两次,而没有复制构造函数或赋值运算符被调用

时间:2011-05-31 18:42:28

标签: c++ destructor

我有一个班级:

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有动态内存分配,我必须在析构函数中释放它,但析构函数会以某种方式被调用两次,这非常糟糕。

我不知道是什么原因导致这个问题。

我用Google搜索并搜索了很多内容。关于“析构函数被调用两次”的许多问题都是因为隐式调用了复制构造函数(赋值运算符)。

感谢。

彼得

4 个答案:

答案 0 :(得分:4)

如果你以某种方式调用析构函数两次,也许你有两个对象认为它们通过指针拥有它。

如果您确实有两个认为他们拥有此对象的对象,请考虑使用引用计数指针(如Boost :: shared_ptr或tr1 :: shared_ptr)来包含它。这样你就不必担心谁最终会调用析构函数。

除了调试器之外,您还可以尝试使用Valgrind(memcheck)来查找程序删除已释放对象的位置。在这种情况下,它可能不会提供比调试器更多的细节,但你应该学习迟早使用Valgrind(memcheck)。

另一个偏执策略是确保在删除它们之后将任何内部指针设置为NULL。

答案 1 :(得分:2)

最有可能是你有另一个你没有显示的构造函数,或者你是在显式地或通过delete多次调用析构函数。

调试器或其他cout将比我们在这种情况下更有帮助。

答案 2 :(得分:1)

在析构函数中粘贴一个断点。然后无论何时调用它,您都可以获取堆栈跟踪并查看它的调用位置。

编辑:

答案 3 :(得分:1)

在我的情况下,我没有使用指针,但析构函数仍然被调用了两次。我为解决问题所做的是覆盖复制赋值运算符MyClass& operator=(const MyClass& other)。不太确定为什么自动生成的运算符会导致问题,但显然会出现问题。