2011-07-09 1 views
12

Поскольку boost::/std::shared_ptr имеет преимущество типа стирания их Deleter, вы можете делать хорошие вещи, какВиртуальный деструктор, необходимый для вашего интерфейса, если вы всегда храните его в shared_ptr?

#include <memory> 

typedef std::shared_ptr<void> gc_ptr; 

int main(){ 
    gc_ptr p1 = new int(42); 
    gc_ptr p2 = new float(3.14159); 
    gc_ptr p3 = new char('o'); 
} 

И это будет правильно удалить все указатели благодаря правильной Deleter сохранения.

Если вы гарантируете, что каждая реализация вашего интерфейса всегда создается с помощью shared_ptr<Interface> (или make_shared<Interface>), вам действительно нужен деструктор virtual? Я бы объявил это virtual в любом случае, но я просто хочу знать, так как shared_ptr всегда будет удалять тип, в котором он был инициализирован (если не указан другой пользовательский отладчик).

+1

Возможный дубликат [shared_ptr magic:]] (http://stackoverflow.com/questions/3899790/shared-ptr-magic) –

+0

@Armen: Это не дубликат, он не спрашивает, как 'shared_ptr' делает это, но нужно ли вам использовать виртуальный деструктор *, знающий *, что 'shared_ptr' делает эту магию. –

+1

@ Давид: Нет, он этого не делает. Он говорит, что в любом случае он будет использовать виртуальный деструктор. Он спрашивает, нормально ли, чтобы он не был. Так что это дубликат –

ответ

12

Я бы по-прежнему следовать общему правилу для классов, которые призваны быть получено:

Обеспечивает как публичный виртуальный деструктор или защищенного невиртуальном деструктор

Причина заключается в том, что вы не может контролировать все виды использования, и это простое правило означает, что компилятор будет отмечать, если вы попытаетесь выполнить delete через неправильный уровень в иерархии. Учтите, что shared_ptr не гарантирует, что он будет вызывать соответствующий деструктор, только то, что он будет вызывать деструктор статического типа, который был использован в качестве аргумента:

base* foo(); 
shared_ptr<base> p(foo()); 

Если base имеет публичный невиртуальный деструктор и foo возвращается тип, который происходит от base, то shared_ptr не сможет назвать правильный деструктор. Если деструктор base является виртуальным, все будет хорошо, если он защищен, компилятор скажет вам, что там есть ошибка.

+0

«Я бы объявил, что это виртуально, [...]». :) Хороший вопрос о невозможности контролировать все точки создания. Хотя, вы всегда можете делать с именованным конструктором, но это, вероятно, выглядит не так хорошо. – Xeo

+1

Предупреждение. Защищенные деструкторы в настоящее время не отвечают true для 'is_nothrow_destructible :: value', даже если они не генерируют исключение. По этой причине я бы предпочел публичный вариант. –

+0

@Howard: спасибо за информацию о 'is_nothrow_destructible'. Кажется, что это правильно. Почему вы позволили бы утверждать, что он в настоящее время правильно сообщает «не разрушаемый» для неразрушаемой вещи, заставляя вас изменить вещь на разрушаемую? –