Нет, это не безопасно. foo
и bar
нужны виртуальные деструкторы, иначе не определено, что произойдет, когда деструктор shared_ptr
удалит указатель, который он держит. Конечно, говорить, что это небезопасно, - это не то же самое, что говорить, что это может привести к сбою.
Кроме того, в shared_ptr
встроена некоторая магия [*], которая означает, что если вы не преобразуете в foo*
, ваш код становится безопасным:
fooptr f(fb1);
barptr b(fb2);
Либо с помощью виртуального деструктора, либо, если вы удалите приведение, когда shared_ptr придет, чтобы удалить указатель, компилятор будет "знать", как вернуть указатель в исходный тип, чтобы вызвать правильные деструкторы и освободить память.
Магия работает только потому, что fb1
имеет тип foobar*
. Без виртуального деструктора следующее по-прежнему небезопасно:
foo *fb = new foobar();
fooptr f(fb);
Если вы используете shared_ptr
, как это, то нет риска сделать это:
fooptr f(new foobar());
Вы также можете избежать проблемы, заключающейся в том, что в вашем коде, если при втором вызове new foobar()
возникает исключение, первый объект пропускается. Если вы собираетесь использовать shared_ptr
для управления памятью, вам нужно как можно быстрее получить управление памятью:
fooptr f(new foobar());
barptr b(new foobar());
Теперь, если выбрасывается вторая строка, f
будет должным образом разрушен и удалит объект.
[*] "magic" = шаблон конструктора, который хранит в shared_ptr
указатель на функцию, которая преобразует сохраненный указатель обратно в правильный тип и затем удаляет его.