During a dive into dynamic memory, it occurred to me it appears contradictory how trivial types begin their lifetime. Consider the snippet
void* p = ::operator new(sizeof(int)); // 1
// 2
new (p) int; // 3
When does the int start its lifetime?
Only acquires storage,
::operator newis specified to have the effect (from [new.delete.single])The allocation functions called by a new-expression to allocate size bytes of storage. [...] allocates storage suitably aligned to represent any object of that size provided the object's type does not have new-extended alignment.
Given that acquiring storage is insufficient in creating an object, the
intcannot have begin its lifetime here.At this point, suitbale storage for the
inthas been acquired.The
intis created by placement new. But somehow its lifetime didn't begin here, since from [basic.life][...] An object is said to have non-vacuous initialization if it is of a class or aggregate type and it or one of its subobjects is initialized by a constructor other than a trivial default constructor. The lifetime of an object of type
Tbegins when:storage with the proper alignment and size for type
Tis obtained, andif the object has non-vacuous initialization, its initialization is complete [...]
intis neither a class nor aggregate type, hence it has vacuous initialization. Therefore only the first bullet applies. However, this is clearly not when storage is obtained and therefore cannot be when its lifetime starts.
Some context
Allocators are required to return memory without constructing its elements. Yet this doesn't make sense with trivial types. The effects of a.allocate(n) with a an allocator object for type T is
Memory is allocated for
nobjects of typeTbut objects are not constructed.