Деструктор вызывается дважды, в то время как конструктор копирования или оператор присваивания не вызывается

у меня есть класс:

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 имеет динамическое выделение памяти, и я должен освободить его в деструкторе, но деструктор вызывается дважды, что очень плохой.

Я не знаю, что могло вызвать эту проблему.

Я много искал и гуглил. Много вопросов о "деструкторе, вызываемом дважды", связано с неявным вызовом конструктора копирования (оператора присваивания).

спасибо.

Петр

4 ответов


Если вы как-то вызываете деструктор дважды, возможно, у вас есть два объекта, которые думают, что они владеют им через указатель.

Если у вас действительно есть два объекта, которые думают, что они владеют этим, рассмотрите возможность использования указателя подсчета ссылок, такого как Boost::shared_ptr или tr1::shared_ptr, чтобы содержать его. Таким образом, вам не придется беспокоиться о том, кто в конце концов вызовет деструктор.

помимо отладчика, вы можете попробовать Valgrind (memcheck), чтобы найти, где ваша программа удаляет уже освобожденный объект. В этом случае он, вероятно, не даст больше деталей, чем отладчик, но рано или поздно вы должны научиться использовать Valgrind (memcheck).

еще одна параноидальная стратегия заключается в том, чтобы установить любые внутренние указатели на NULL после их удаления.


скорее всего, у вас есть другой конструктор, который вы не показываете, или вы вызываете деструктор более одного раза, явно или через delete.

отладчик или дополнительные coutS будет более полезным, чем мы можем быть в этом случае.


вставить точку останова в деструкторе. Затем, когда он вызывается, вы можете захватить трассировку стека и посмотреть, откуда он вызывается.

EDIT:

вы can ожидайте, что copy ellision нанесет ущерб таким тривиальным отладочным заявлениям.


в моем случае я не использовал указатели, но деструктор все равно вызывался дважды. То, что я сделал, чтобы решить проблему, - это переопределить оператор присваивания копирования MyClass& operator=(const MyClass& other). Не совсем уверен, почему автоматически сгенерированный оператор вызывает проблемы, но, похоже, это так.