Разрушитель вызывается дважды, а конструктор копирования или оператор присваивания не вызывают
У меня есть класс:
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
,
Отладчик или дополнительный cout
s будет более полезным, чем мы можем быть в этом случае.
Вставьте точку останова в деструкторе. Затем, когда бы он ни вызывался, вы можете получить трассировку стека и посмотреть, откуда он вызывается.
РЕДАКТИРОВАТЬ:
Вы можете ожидать, что копия ellision нанесет ущерб с помощью тривиальных отладочных операторов, подобных этим.
В моем случае я не использовал указатели, но деструктор вызывался дважды. Что я сделал, чтобы решить проблему, так это переопределить оператор присваивания копии MyClass& operator=(const MyClass& other)
, Не совсем уверен, почему автоматически сгенерированный оператор вызывает проблемы, но, по-видимому, это так.