TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #821 5.66K
​​Преимущества std::make_shared
#новичкам

Попсовая тема, которая часто спрашивается на собеседованиях. Краем касались ее в других постах, но пусть будет и отдельно, для удобной пересылки.

Коротко о том, что это за функция.

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );


Это по сути фабрика для создания шаред поинтеров из параметров конструктора разделяемого объекта. Внутри себя она производит аллокацию памяти и вызов конструктора с помощью переданных аргументов на этой памяти.

В чем же преимущества этой функции по сравнению с явным вызовом конструктора shared_ptr?

Ну для начала, она не предполагает явного использования сырых указателей. Никакого вызова new!

Сами по себе сырые указатели - это неплохо. Просто на душе спокойнее, когда их как можно меньше в современном С++ коде.

Но если new не вызывает программист, это не значит, что функция его не вызывает. Еще как вызывает. И в том, как она это делает кроется главное преимущество std::make_shared над явным вызовом конструктора.

ОООчень упрощенно внутреннее устройство std::shared_ptr выглядит вот так:

template <typename T>
struct shared_ptr {
T * obj_ptr;
ControlBlock * block_ptr;
}


Это два указателя: на сам объект и на контрольный блок, в котором находятся счетчики ссылок и некоторая другая информация.

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

std::shared_ptr<Foo> ptr(new Foo(arg1, arg2));


Память под объект Foo выделяется при вызове new, а память под контрольный блок выделяется внутри конструктора shared_ptr.

При явном вызове конструктора невозможно по-другому: будет две аллокации.

Но когда make_shared забирает у пользователя возможность самому вызывать конструктор, у нее появляется уникальная возможность: за один раз выделить один большой кусок памяти, в который влезет и объект, и контрольный блок:

template <typename T, typename... Args>
shared_ptr<T> my_make_shared(Args&&... args) {
// Выделяем память для ControlBlock и объекта T одним блоком
char* memory = new char[sizeof(ControlBlock) + sizeof(T)];

// Инициализируем ControlBlock в начале памяти
ControlBlock* block = new (memory) ControlBlock();

// Инициализируем объект T после ControlBlock
T* object = new (memory + sizeof(ControlBlock)) T(std::forward<Args>(args)...); // Placement new

shared_ptr<T> ptr;
ptr.obj_ptr = object;
ptr.block_ptr = block;

return ptr;


Это очень упрощенная реализация, которая показывает главный принцип: выделяется один кусок памяти под два объекта.

Отсюда повышение производительности за счет уменьшения количества аллокаций и за счет большей локальности данных и кеш-френдли структурой.

Ну и на последок.

std::shared_ptr<Foo> ptr(new Foo(arg1, arg2));


В этой записи два раза повторяется имя класса. В коде могут быть довольно длинные названия сущностей, даже при использовании алиасов. Получается в каком-то смысле явный вызов конструктора приводит к дублированию кода.

Это не происходит с std::make_shared, потому что у нас есть волшебное слово auto:

auto ptr = std::make_shared<Foo>(arg1, arg2);


Есть(было) и еще одно преимущество make_shared. Но его разберем уже отдельно, там ситуация непростая.

А на этом у нас все)

Make better tools. Stay cool.

#cppcore #memory
  • 👍 42
  • ❤ 16
  • 🔥 7
  • 💯 2
  • ❤‍🔥 1
More from @grokaemcpp
  1. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  2. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  3. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  4. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  5. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  6. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →