C++ - make_shared when custom new and delete operators are defined

653 Views Asked by At

Regarding the book "Effective Modern C++" from Scot Meyers, and the 21st item: "Prefer std::make_unique and std::make_shared to direct use of new":

"Some classes define their own versions of operator new and operator delete. Often, class-specific routines are designed only to allocate and deallocate chunks of memory of precisely the size of objects of the class. Such routines are a poor fit for std::shared_ptr’s support for custom allocation (via std::allocate_shared) and deallocation (via custom deleters), because the amount of memory that std::allocate_shared requests isn’t the size of the dynamically allocated object, it’s the size of that object plus the size of a control block. Consequently, using make functions to create objects of types with class-specific versions of operator new and operator delete is typically a poor idea."

Why is this a problem for allocate_shared/make_shared, if custom new and delete are called on same places as standard new and delete?

Construction: Operator new is used just to construct the resource object, but make_shared/allocate_shared construct the constrol block.

Destruction: With or without a custom deleter function specified, when delete is called, just the resource object should be removed. Cntrol block depends on reference and weak counts.

Why then the sentence: "Such routines are a poor fit for std::shared_ptr’s support for custom allocation (via std::allocate_shared) and deallocation (via custom deleters), because the amount of memory that std::allocate_shared requests isn’t the size of the dynamically allocated object, it’s the size of that object plus the size of a control block."?

1

There are 1 best solutions below

0
Marek R On

std::make_unique is fine, since it doesn't need any extra data (in general case).

Problem is std::make_shared. To make std::shared_ptr work some extra data are needed: strong reference counter, weak reference counter, deleter function pointer.

This means that when you do: std::shared_ptr<Foo>{raw_pointer}, std::shared_ptr will allocate own buffer to keep this data. Now allocation is quite expensive so std::make_shared was introduced to optimize use of heap. It allocates memory which will hold shared_ptr data and pointed item side by side in single chunk of memory. It constructs pointed object in place.

So when you have custom operator new for some class, std::make_shared will not use it. On other head if you pass raw pointer to std::shared_ptr then you will have two blocks of memory.