Деструктор вызывается дважды, в то время как конструктор копирования или оператор присваивания не вызывается
у меня есть класс:
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 будет более полезным, чем мы можем быть в этом случае.
вставить точку останова в деструкторе. Затем, когда он вызывается, вы можете захватить трассировку стека и посмотреть, откуда он вызывается.
EDIT:
вы can ожидайте, что copy ellision нанесет ущерб таким тривиальным отладочным заявлениям.
в моем случае я не использовал указатели, но деструктор все равно вызывался дважды. То, что я сделал, чтобы решить проблему, - это переопределить оператор присваивания копирования MyClass& operator=(const MyClass& other)
. Не совсем уверен, почему автоматически сгенерированный оператор вызывает проблемы, но, похоже, это так.