Есть ли ситуация, в которой я бы не стал использовать std :: make_shared?

Судя по проведенному мною исследованию, предпочтительным способом является std::make_shared строительства std::shared_ptr. В частности, потому что:

  1. Он выполняет только одно выделение памяти по сравнению с использованием new, которое выполняет как минимум два.
  2. Если ctor перешел в make_shared throws, он не будет протекать, как это будет с new.

Мой вопрос: если мне нужен shared_ptr, должен ли я всегда использовать make_shared, или есть случаи, когда new предпочтительнее?


person Justin R.    schedule 07.10.2013    source источник
comment
shared_ptr<int>(new int) не будет утечки памяти, если shared_ptr конструктор выбросит; что, по-видимому, подразумевает для меня ваш второй пункт.   -  person Simple    schedule 07.10.2013


Ответы (5)


Поскольку счетчик и объект используют одно и то же выделение, они также разделяют одно и то же освобождение.

Счетчик должен сохраняться до тех пор, пока не исчезнут последние shared_ptr и weak_ptr. Если у вас есть большой объект (или много мелких объектов) с длительными weak_ptr, это может вызвать конкуренцию за память, если вы выделяете shared_ptr через make_shared.

Во-вторых, если у вас есть сторонний API, который передает вам указатель или дескриптор ресурса и, возможно, имеет собственную функцию удаления, make_shared не подходит и не может использоваться во всех случаях. Создание ваших собственных make_ функций поможет избавиться от лишних деталей, позволит вам справиться с этой проблемой, а также справится с угловым случаем исключения.

Наконец, хотя общие указатели прекрасны, они также слишком мощны. Довольно часто мне нужен unique_ptr или даже boost::scoped_ptr, или навязчивый указатель подсчета ссылок, или что-то подобное, чтобы представить собственность. shared_ptr следует использовать только тогда, когда ситуация фактически предполагает совместное владение ресурсом: его использование волей-неволей, потому что это «просто», как правило, приводит к ресурсному эквиваленту спагетти-кода.

person Yakk - Adam Nevraumont    schedule 07.10.2013
comment
Бонусные баллы за последний абзац. Хотя это не было затронуто непосредственно в вопросе, в данном контексте об этом нельзя говорить достаточно часто. - person Christian Rau; 08.10.2013

Возможно, вам придется иметь дело с устаревшим кодом, который возвращает динамически выделяемый объект. В этом случае вам нужно будет использовать std::shared_ptr<T> ctor с параметром указателя. Не рекомендуется использовать std::make_shared, но это позволяет вам использовать все std::shared_ptr<T> достоинства с унаследованным кодом.

Я знаю, что это не строго эквивалентно использованию std::shared_ptr<T> ctor напрямую с new, но это допустимый вариант использования std::shared_ptr<T>, где make_shared нельзя использовать.

person Gearoid Murphy    schedule 07.10.2013

Я немного не уверен в интерпретации вашего вопроса. Я предполагаю, что использование shared_ptr<T>; Я могу лишь повторить Yakk причины, по которым вы вообще не хотели бы использовать shared_ptr.

Есть одна ситуация, когда вы не можете использовать make_shared или allocate_shared для создания shared_ptr, но вам нужно использовать соответствующий ctor: если вам нужно передать настраиваемое средство удаления, см. (3) и (4) в ctors shared_ptr.

person Ali    schedule 07.10.2013

Я столкнулся с проблемами при использовании make_shared в классе с частным конструктором (из статического фабричного метода). Я не думаю, что для этого есть простое решение.

person fscan    schedule 07.10.2013
comment
Я думаю, что в этом есть недоработка; можно ли сделать make_shared функцией друга? По стандарту неясно, подойдет он или нет. - person Simple; 07.10.2013
comment
Я сделал обходной путь, который позволяет использовать make_shared с частным конструктором: ideone.com/O93w6o - person Simple; 08.10.2013

должен ли я всегда использовать make_shared, или есть случаи, когда новый предпочтительнее

make_shared не допускается, когда мы храним голый указатель в shared_ptr, выделенном кем-то другим. и он может вызывать только public конструкторы. Однако в некоторых компиляторах есть несколько отчетов о доступе к защищенному конструктору с использованием make_shared как это.

person Sage    schedule 07.10.2013