void setQuackBehavior(QuackBehavior & qb) {
quackBehavior = std::move(std::shared_ptr<QuackBehavior> (&qb));
}
Есть метод setQuackBehavior()
, который принимает ссылку на абстрактный класс QuackBehavior
. Этот метод находится в классе, который имеет член std::shared_ptr<QuackBehavior> quackBehavior
.
Может ли код, который приведён выше, иметь право на существование? По-моему тут всё хорошо, но мало ли я что-то не учитываю, и в примере этого кода имеется какая-либо грубая ошибка.
Такой подход имеет ряд недостатков.
1) Когда Вы создаете shared_ptr
, выделяется блок динамической памяти для хранения служебных данных, например, счетчик ссылок, собственный delete'ор и т.д.
Таким образом, у Вас будет одно выделение памяти для создания объекта, и одно для создания этого блока служебных данных. И объект и данные также будут лежать в разных участках памяти, поэтому, такая структура, помимо лишнего выделения памяти может еще быть не дружелюбной к кешу.
Для того, чтобы выделить память под объект и указателя рядом, одним выделением, можно использовать std::make_shared
. Она за одно выделение памяти сделает и указатель и динамический блок с данными.
2) Для данного shared_ptr
не указан пользовательский метод удаления, а значит будет использоваться delete
, поэтому объект должен быть создан с помощью new
.
3) Объект будет автоматически уничтожен при уничтожении последнего умного указателя ссылки на него. Согласитесь, при вызове setQuackBehavior совершенно не очевидно, что внутри на объект создается shared_ptr
.
Derived derived = new Derived;
obj.setQuackBehavior(*derived);
Возможно, когда-нибудь дальше появится что-то вроде delete derived;
или еще-что-нибудь подобное.
4) Это скорее не к конкретно этому коду, а вообще к любому коду с shared_ptr. Если два объекта содержат указатели на друг друга (или более сложная схема), то это приведет к циклическим ссылкам и, фактически, к утечкам.
5) Этот код требует гарантии, что на этот объект более нет умных указателей.
std::shared_ptr<Derived> derived(new Derived);//или make_shared
obj.setQuackBehavior(*derived);//Злостная ошибка
При таком (или подобном) коде на один объект derived
теперь приходится два блока со служебными данными для разных shared_ptr
, а значит у нас и два счетчика ссылок и т.д. Эти указатели теперь живут "раздельно" и не знают о существовании друг друга. Понятное дело, что это приведет к преждевременному удалению объекта, обращению к несуществующим данным, прострелам памяти, двойному удалению и всем-всем прелестям не верной работы с памятью.
Ну и в Вашем коде лишний std::move. Объект и так временный, поэтому будет перемещен, а не скопирован.
Почему бы не сделать так:
void setQuackBehavior(std::shared_ptr<QuackBehavior> const &qb) {
quackBehavior = qb;
}
Сразу очевидно, что работаем с shared_ptr
, код Выше его создает, поэтому он может воспользоваться make_shared
, что положительно скажется на программе, также очевидно, что раз внутри shared_ptr
, то не нужно удалять объект, а также нужно учесть возможность циклических ссылок.
obj.setQuackBehavior(std::make_shared<Derived>());
По-моему, такой код более очевиден и безопасен.
Не очень ясен смысл делать move
для shared_ptr
. Т.к. при обычном копировании вполне нормально инкрементируется счётчик ссылок.
А ошибка может быть в двойном удалении объекта, на который ссылается qb
. Первый раз как обычный объект (надо смотреть код, где создаётся объект исходно), второй - при вызове деструктора последнего объекта std::shared_ptr
.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Событие select_list_currentClick(e) должно переключать класс open для того, чтобы появлялся селект как справа на скрине Но оно почему-то срабатывает очень...
На телефонах owlcarousel показывает все слайды
Есть сайт с записямиПользователю предлагаеться поделиться записью в Фейсбук