Разрушитель вызывается дважды, а конструктор копирования или оператор присваивания не вызывают

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

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 будет более полезным, чем мы можем быть в этом случае.

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

РЕДАКТИРОВАТЬ:

Вы можете ожидать, что копия ellision нанесет ущерб с помощью тривиальных отладочных операторов, подобных этим.

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

Другие вопросы по тегам