Инициализация переменной-члена shared_ptr, new vs make_shared?

При инициализации переменной-члена shared_ptr:

// .h
class Customer
{
public:
  Customer();

private:
  std::shared_ptr<OtherClass> something_;
}

// .cpp
Customer():
  something_(new OtherClass())
{
}

vs.

Customer():
  something_(std::make_shared<OtherClass>())
{
}

Разрешена ли версия make_shared? Я всегда вижу первую версию, какая предпочтительнее?


person User    schedule 23.04.2012    source источник
comment
Херб Саттер только что написал об этом GOTW. См. это, а также проверьте одна проблема, о которой Херб прямо не говорит.   -  person R Samuel Klatchko    schedule 24.04.2012
comment
@RSamuelKlatchko - обновленная ссылка для первой ссылки, которую вы указали в своем ответе, используйте herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers   -  person Guy Avraham    schedule 29.06.2017


Ответы (2)


Единственными случаями, когда make_shared запрещено, являются:

  1. Если вы получаете голый указатель, выделенный кем-то другим, и сохраняете его в shared_ptr. Это часто бывает при взаимодействии с C API.
  2. Если конструктор, который вы хотите вызвать, не является общедоступным (make_shared может вызывать только общедоступные конструкторы). Это может произойти с фабричными функциями, когда вы хотите заставить пользователей создавать объект из фабрики.

    Однако есть способы обойти это. Вместо частного конструктора используйте общедоступный конструктор. Но сделать так, чтобы конструктор принимал тип with, может быть создан только теми, у кого есть частный доступ к классу. Таким образом, единственными людьми, которые могут вызывать make_shared с этим типом объекта, являются те, у кого есть частный доступ к классу.

Так что да, вы можете это сделать.

person Nicol Bolas    schedule 23.04.2012
comment
Что касается вопроса дружбы, есть ли в Стандарте какое-либо упоминание о конкретной функции, которую можно использовать в качестве друзей? Я вполне мог бы представить некоторую реализацию, делегирующую эту работу вспомогательным функциям... - person Matthieu M.; 24.04.2012
comment
@MatthieuM.: Мне было интересно то же самое, поэтому я сказал, что может. Я спросил на comp.std.c++; посмотрим, что они скажут об этом. Если нет, я думаю, что это могло бы сделать достойный отчет о дефекте. - person Nicol Bolas; 24.04.2012

В этом случае использование make_shared не просто разрешено, а лучше использовать. Если вы используете new, он где-то выделит память для вашего клиента, а затем память для вашего shared_ptr где-то еще, сохраняя как сильные, так и слабые ссылки (для слабых указателей и общих указателей). Если вы используете make_shared, у вас будет только одно место в памяти для всего и, следовательно, только одно новое.

Я не уверен, что я действительно ясно выразился, это была цель GotW #89, прочтите, там это хорошо объяснено.

person Uflex    schedule 25.04.2012