shared_ptr и нарезка - PullRequest
       1

shared_ptr и нарезка

9 голосов
/ 22 июля 2010

Кто-то, с кем я когда-то работал, сказал, что shared_ptr небезопасен и будет нарезаться при преобразовании из производного класса в базовый класс (то есть, апскейтинг). Например, если было 2 класса A и B, где B получено из A, то

shared_ptr<A> a(new B)

будет нарезать. Я указал ему на http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/shared_ptr.htm где написано

shared_ptr<T> может быть неявно преобразовано в shared_ptr<U> всякий раз, когда T* может быть неявно преобразовано в U*.

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

Ответы [ 2 ]

12 голосов
/ 22 июля 2010

Если кто-то не прав, нарезка объектов не относится к указателям. То, что использование указателя обернуто в shared_ptr, не меняет этого - здесь не происходит никакой особой магии, оно инициализирует внутренний указатель значением, переданным его конструктору.

Упрощенно это может выглядеть, например, вот так для целей этого вопроса:

template<class T> struct ptr {
    T* t;
    ptr(T* t) : t(t) {}
    // ...
};

Вы теряете статическую информацию типа B, да, но ничего не меняется в отношении объекта, на который указывает.

0 голосов
/ 20 мая 2016

Это правда, что срезы объектов не применяются к указателям

Указатели - это POD (только для записи: shared_ptr s - нет).

Цитаты вопроса:

shared_ptr может быть неявно преобразован в shared_ptr всякий раз, когда T * может быть неявно преобразован в U *.

Речь идет о преобразовании из одного типа в другой, который отличается от выгрузки,Нет никаких отношений наследования между shared_ptr<A> и shared_ptr<B>, независимо от того, является ли A производным от B или наоборот.Это причина того, что сам объект shared_ptr не разрезает.

Неверно, что разделение объектов не может быть проблемой

Рассмотрим иерархию классов A, B без виртуальных деструкторов.

std::shared_ptr<A> a(new B);
auto a = std::make_shared<B>();

захватит де-локатор B, а затем при необходимости вызовет деструктор B.

std::shared_ptr<A> a((A*)(new B));

не сделает ничего подобного и вызовет проблемы с нарезкой в ​​указанном объекте.

Неправда, что ничего не изменилось из-за того, что использование указателя заключено в умный указатель

Например, использование unique_ptr имеет другое поведение:

std::unique_ptr<A> a(new B);
std::unique_ptr<A> a((A*)(new B));
*У 1034 * будут проблемы с нарезкой, а у
auto a = std::make_unique<B>();

нет.

Использование простого указателя также не поможет:

A* a = new B{};
delete a;

- рецептдля бедствия.

Пример кода доступен здесь .

...