5

You are expected to use std::make_shared to ensure that block with counters is stored next to data. Unfortunately internally std::make_shared<T> uses zero initialization for T (i.e. uses T() to initialize data block). Is there any way to trick it into using default initialization? I know I can use std::shared_ptr<T>( new T, [](auto p){delete p;}), but I'll end up with two allocations here (data and counter blocks won't be next to each other).

Shreevardhan
  • 12,233
  • 3
  • 36
  • 50
C.M.
  • 3,071
  • 1
  • 14
  • 33

1 Answers1

9

Create a derived class to enforce trivial construction.

struct D : T {
    D() {} // Non-trivial constructor. Default-initialize T, which may be trivial.
};

Construct the derived class but assign it to the shared pointer you want.

std::shared_ptr< T > p = std::make_shared< D >();

Demo.

Note that this is type-safe with respect to the destructor. shared_ptr always performs type erasure and uses dynamic dispatch before the destructor call, even for simple POD objects.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • @Potatoswatter Genius... I have no idea how I didn't come up with this. – C.M. Feb 02 '17 at 03:23
  • Yeah... Type erasure is something I don't really appreciate in std::shared_ptr. But I deal with large old codebase that has like 4 different homegrown smart pointers -- regardless how you look at it std::shared_ptr is better than any of them :-) – C.M. Feb 02 '17 at 03:25
  • Yum: `template ListInit(Args&&...args):T{std::forward(args)...}{}` – Yakk - Adam Nevraumont Feb 02 '17 at 15:10
  • @Yakk Use inheriting constructors. (Edit: Or just don't construct the derived class for cases of nontrivial construction. It's a bit of a corner case that trivial constructors are allowed to overload user-defined ones…) – Potatoswatter Feb 03 '17 at 08:54
  • even better solution -- [lambda](https://stackoverflow.com/questions/45345175/avoiding-extra-move-in-make-unique-make-shared-emplace-etc-for-structures-that-u)! – C.M. Aug 05 '17 at 09:44