Какие плюсы и минусы make_shared?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Плюсы и минусы make_shared
make_shared — это функция из <memory>, которая создаёт объект и оборачивает его в std::shared_ptr одной операцией. Вот ключевые преимущества и недостатки.
Плюсы make_shared
1. Единая оптимизация выделения памяти При использовании make_shared управляемый блок (control block) и данные объекта выделяются одним сплошным блоком памяти. Это значительно эффективнее обычного конструктора shared_ptr:
// ✅ Одна операция выделения, оптимально
auto ptr1 = std::make_shared<MyClass>(arg1, arg2);
// ❌ Две операции выделения
auto ptr2 = std::shared_ptr<MyClass>(new MyClass(arg1, arg2));
2. Безопасность исключений (exception safety) make_shared гарантирует отсутствие утечек памяти при исключениях на этапе создания:
// ❌ Опасно: если func2() выкидит исключение, память утечёт
func(std::shared_ptr<MyClass>(new MyClass()), func2());
// ✅ Безопасно
func(std::make_shared<MyClass>(), func2());
3. Более компактный код Синтаксис чище и понятнее, нет явного new.
4. Лучшая локальность данных Управляемый блок и объект в одной памяти → меньше кеш-промахов, лучше производительность при обходе структур данных.
Минусы make_shared
1. Невозможность пользовательского удаления (deleter) make_shared использует стандартный удаления. Если нужен кастомный deleter, придётся использовать обычный конструктор:
auto deleter = [](MyClass* p) {
std::cout << "Удаляю объект" << std::endl;
delete p;
};
// ❌ make_shared не поддерживает deleter
// auto ptr = std::make_shared<MyClass>(deleter); // ОШИБКА
// ✅ Только через конструктор
auto ptr = std::shared_ptr<MyClass>(new MyClass(), deleter);
2. Сложнее с массивами (до C++20) В C++20 появился make_shared для массивов, но раньше это было невозможно:
// C++20 и позже
auto arr = std::make_shared<int[]>(100);
// Раньше только так
auto arr = std::shared_ptr<int[]>(new int[100]);
3. Отсроченное удаление объекта Пока существует хотя бы одна копия shared_ptr, объект не будет удалён, даже если больше никто на него не ссылается (out of scope). Иногда это нежелательно для больших объектов:
auto ptr = std::make_shared<LargeClass>();
{
auto copy = ptr; // Ещё одна ссылка
// copy выходит из scope, но объект не удалён!
}
// Объект удалится только здесь, когда удалится последняя копия
4. Проблема со слабыми ссылками (weak_ptr) Если объект имеет циклические ссылки через weak_ptr, и используется make_shared, memory может быть освобождена только когда удалятся все weak_ptr:
auto shared = std::make_shared<Node>();
auto weak = std::weak_ptr<Node>(shared);
// Даже после обнуления shared, память может оставаться,
// если weak_ptr всё ещё существует
5. Невозможность контролировать выравнивание (до C++20) Кастомное выравнивание не поддерживалось в старых стандартах.
Когда использовать что
Используй make_shared:
- Стандартное удаление достаточно
- Нужна производительность и безопасность исключений
- Работаешь с единичными объектами, не с массивами
Используй обычный конструктор shared_ptr:
- Нужен кастомный deleter
- Нужны функции вроде get_deleter()
- Работаешь с массивами (до C++20)
- Есть специфические требования к памяти