Проблема деструктора C ++ с boost :: scoped_ptr - PullRequest
2 голосов
/ 16 июня 2010

У меня вопрос по поводу следующего кода:

#include <iostream>
#include <boost/scoped_ptr.hpp>

class Interface
{
};

class A : public Interface
{
    public:
        A() { std::cout << "A()" << std::endl; }
        virtual ~A() { std::cout << "~A()" << std::endl; }
};


Interface* get_a()
{
    A* a = new A;
    return a;
}

int main()
{
    {
        std::cout << "1" << std::endl;
        boost::scoped_ptr<Interface> x(get_a());
        std::cout << "2" << std::endl;
    }
    std::cout << "3" << std::endl;
}

Он создает следующий вывод:

1
A()
2
3

Как видите, он не вызывает деструктор AЕдинственный способ, которым я вижу, чтобы вызвать деструктор вызываемого A, это добавить деструктор для класса Interface следующим образом:

virtual ~Interface() { }

Но я действительно хочу избежать любой реализации в моем классе Interface и virtual ~Interface() = 0; не работает (выдает некоторые ошибки компоновщика с жалобами на несуществующую реализацию ~Interface().

Итак, мой вопрос: что я должен изменить, чтобы вызвать деструктор, но (если возможно) оставить интерфейс как интерфейс (только абстрактные методы).

Ответы [ 3 ]

5 голосов
/ 16 июня 2010

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

И что более важно, вы получаете неопределенное поведение в противном случае; §5.3.5 / 3:

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

Акцент на шахте.


Я бы сказал, что лучше всего это:

class Interface
{
public:
    virtual ~Interface(void) = 0;
};

inline Interface::~Interface(void) {}

Компилятор может легко встроить это, в отличие от решения, в котором реализация находится в исходном файле. (Говоря об этом, это решение даже не требует от вас его наличия.) Оно также оставляет класс чисто виртуальным.

2 голосов
/ 16 июня 2010

Вам нужно определить чисто виртуальную версию деструктора интерфейса, но вам также нужно определить тело деструктора.Это своего рода странный случай в C ++, где, хотя функция является виртуальной, ее необходимо определить, поскольку после вызова деструктора A также будет вызван деструктор Instance.

Таким образом, правильный ответ:*

virtual ~Interface() = 0;

И позже, в файле cpp:

Interface::~Interface() {}
2 голосов
/ 16 июня 2010

Вы должны объявить деструктор virtual, если вы хотите удалить объекты производного класса через указатель на тип интерфейса базового класса, и этот деструктор должен иметь реализацию.виртуальный, хотя:

class Interface
{
public:
    virtual ~Interface() = 0;
};

inline Interface::~Interface() { }
...