Search code examples
c++shared-ptrnew-operator

Who allocates the memory for control block of shared_ptr when using custom new() operator with a class


Suppose I have a code like this:

class Foo
{
private:
    int x;
public:
    void* operator new(size_t size);
    void operator delete(void* p);
};


int main() {
    auto ptr = std::shared_ptr<Foo>(new Foo());
    return 0; 
}

The shared_ptr will create separate control-block and object-block. I suppose the memory for the object block will be created using the Foo::operator new(). Is the memory for the control-block created using ::operator new() or Foo::operator new()? And in case of make_shared, would the entire single-block of memory be allocated using Foo::operator new()?


Solution

  • The shared_ptr will create separate control-block and object-block. I suppose the memory for the object block will be created using the Foo::operator new().

    Nope. You already passed in the pointer to the object, so it only needs a control block. In fact, I believe no shared_ptr construction allocates a single object-block, they never need it.

    Is the memory for the control-block created using ::operator new() or Foo::operator new()?

    C++ spec doesn't specify, but the sane thing for an implementation to do is rebind the allocator to an Allocator<ControlBlock> and use its allocate member, which will almost certainly use ::operator new(). It's allocating a ControlBlock, not a Foo.

    And in case of make_shared, would the entire single-block of memory be allocated using Foo::operator new()?

    The C++ spec does specify this one:

    3.11.3.6 ... The allocate_shared templates use a copy of a (rebound for an unspecified value_type) to allocate memory...

    7 Remarks: (7.1) — Implementations should perform no more than one memory allocation. [ Note: This provides efficiency equivalent to an intrusive smart pointer. — end note ]>

    In this case, the implementation will rebind the allocator to an Allocator<ControlAndObjectBlock> and use its allocate member, which will almost certainly again use ::operator new(), since it's allocating a ControlAndObjectBlock instead of a Foo.

    summary: Since shared_ptr never actually allocates an object block by itself, it'll never use Foo::operator new. However, your std::shared_ptr<Foo>(new Foo()) expression allocates a Foo using Foo::operator new, and then constructs a std::shared_ptr<Foo> from that pointer.