Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Нужен ли виртуальный деструктор для вашего интерфейса, если вы всегда храните его в shared_ptr?

Автор вопроса: XeoОтветов: 1

Поскольку boost::/std::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');
}

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

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

  • возможный дубликат магии shared_ptr :) Armen Tsirunyan 09.07.2011
  • @Armen: Это не дубликат, он не спрашивает, как shared_ptr это делает, а нужно ли использовать виртуальный деструктор зная, что shared_ptr творит магию. David Rodríguez - dribeas 09.07.2011
  • @ Дэвид: Нет, он этого не делает. Он говорит, что все равно будет использовать виртуальный деструктор. Он спрашивает, нормально ли не иметь такой. Так это дубликат Armen Tsirunyan 09.07.2011
  • Да, это правда. Однако лично я бы побеспокоился об этом. Однажды я решу, что shared_ptr не нужен, я просто использую указатель на базовый класс, и все незаметно ломается. Я бы расценил это как хрупкий код, который внешний код, делающий разумные предположения о том, как реализованы классы, может легко сломаться, и не сделаю этого, если я не смогу доказать, что существует требование, которое может быть выполнено только таким образом. jcoder 09.07.2011
  • Что ж ... если у вас есть shared_ptr экземпляры, которые могут указывать на производный тип, тогда вы почти наверняка используете virtual функции-члены, верно? Иначе какой смысл? Так что в этом случае создание виртуального деструктора ничего не стоит ... кроме, может быть, небольшого дополнительного набора текста :) Karl Knechtel 09.07.2011
  • Действительно ли в вашем примере нетривиально используется стирание типа shared_ptr? Удаление во всех трех случаях равно delete(void*). Я не вижу связи между настраиваемым средством удаления и указателем на удаление через базовый указатель. Kerrek SB 09.07.2011

c++boostshared-ptrc++11virtual-destructor

Ответы

Ответ 1 · рейтинг 14 · David Rodríguez - dribeas

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

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

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

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы