Есть ли причина не использовать std:: make_shared при построении объектов?

Я не могу думать о ситуации, когда

std::shared_ptr<Object> obj(new Object("foo", 1));

было бы предпочтительнее

auto obj = std::make_shared<Object>("foo", 1);

Последнее всегда приводит к лучшей локальности и уменьшает фрагментацию памяти. Есть ли ситуация, когда вы предпочитаете (или должны быть вынуждены) использовать первую форму, за исключением взаимодействия с кодом, возвращающим исходные указатели?

Ответы

Ответ 1

Последнее всегда приводит к лучшей локальности и уменьшает фрагментацию памяти.

Не всегда. Реализация рекомендуется использовать единое распределение для подсчитанного объекта ссылки и счетчика ссылок, но это не требуется для этого.

Почему вы не хотите использовать std::make_shared? Рассмотрим случай, когда у вас есть большой динамически выделенный объект, которым вы хотите принадлежать std::shared_ptr, и вы знаете, что будут слабые ссылки на этот объект, которые могут пережить сильные ссылки на объект (возможно, есть много слабых ссылок и только одна или две недолговечные сильные ссылки).

В этом случае std::make_shared будет плохим выбором, предполагая, что он выделяет один блок, которому принадлежит как объект, так и счетчик ссылок: выделенный блок (который большой, помнит) не может быть уничтожен, пока не будет сильного или слабые ссылки, оставленные объекту.

Если бы вы динамически выделили объект самостоятельно и передали указатель на конструктор std::shared_ptr, память, занятая объектом, могла быть выпущена, как только остались сильные ссылки, даже если все еще есть слабые ссылки.

Ответ 2

Если вы создаете объект, который будет иметь несколько сущностей, совместно используемых в течение жизни объекта, тогда да, вы предпочитаете использовать std:: make_shared, где это возможно. В некоторых местах это может быть невозможно, если вы получаете указатель от кого-то другого; например, factory может возвращать необработанный указатель или std:: unique_ptr, которые вы хотите сохранить в shared_ptr, тем самым предотвращая использование make_shared.

Вопрос в названии немного отличается; есть много причин, по которым вы, возможно, не захотите использовать shared_ptr для своих объектов вообще. Вы должны использовать shared_ptr, если время жизни фактически разделяется несколькими объектами. В противном случае предпочитайте стеки, выделяющие объект, или используя unique_ptr.

Ответ 3

Современные IDE имеют функцию "Найти использование". Если вы используете std::make_shared для построения объекта, при поиске мест, где вызывается конструктор этого объекта, среда IDE не будет отображать места, где используется std::make_shared.