These requirements are a relationship between a type T
and a container X
. A container has an allocator type, A
, which it uses to allocate the memory for its contained objects.
If m
is one of these allocators, p
a T*
, rv
an rvalue of type T
, and v
an expression of type T
:
CopyInsertable
is defined by the standard with:
T
is CopyInsertable
into X
means that the following expression is well-formed:
allocator_traits<A>::construct(m, p, v);
MoveInsertable
is defined by the standard with:
T
is MoveInsertable
into X
means that the following expression is well-formed:
allocator_traits<A>::construct(m, p, rv);
Now to understand these definitions, we must know what allocator_traits<A>::construct
does. Quite simply, in this case it calls:
m.construct(p, v) // CopyInsertable case
m.construct(p, rv) // MoveInsertable case
v
and rv
still have their respective value categories here because std::forward
is applied to the argument of allocator_traits<A>::construct
.
So what does an allocators construct
member function do? Well, as you might expect, it constructs an object of type T
at the location p
by doing:
::new ((void*)p) T(v) // CopyInsertable case
::new ((void*)p) T(rv) // MoveInsertable case
Again, v
and rv
are std::forward
ed.
Of course, these will invoke the copy or move constructors respectively.
So:
T
is CopyInsertable
into X
: the allocator for X
can placement-new construct an element of T
, passing an expression of type T
T
is MoveInsertable
into X
: the allocator for X
can placement-new construct an element of T
, passing an rvalue of type T
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…