2177. Requirements on Copy/MoveInsertable

Section: 23.2.2 [container.requirements.general] Status: C++14 Submitter: Loïc Joly Opened: 2012-08-10 Last modified: 2017-09-07

Priority: Not Prioritized

View other active issues in [container.requirements.general].

View all other issues in [container.requirements.general].

View all issues with C++14 status.

Discussion:

See also discussion following c++std-lib-32883 and c++std-lib-32897.

The requirements on CopyInsertable and MoveInsertable are either incomplete, or complete but hard to figure out.

From e-mail c++std-lib-32897:

Pablo Halpern:

I agree that we need semantic requirements for all of the *Insertable concepts analogous to the requirements we have on similar concepts.

Howard Hinnant:

I've come to believe that the standard is actually correct as written in this area. But it is really hard to read. I would have no objection whatsoever to clarifications to CopyInsertable as you suggest (such as the post-conditions on v). And I do agree with you that the correct approach to the clarifications is to confirm that CopyInsertable implies MoveInsertable.

[2012, Portland: Move to Tentatively Ready]

Move to Tentatively Ready by unanimous consent.

[2013-04-20 Bristol]

Proposed resolution:

This wording is relative to N3376.

  1. Edit 23.2.2 [container.requirements.general] p13 as indicated:

    -13- […] Given a container type X having an allocator_type identical to A and a value_type identical to T and given an lvalue m of type A, a pointer p of type T*, an expression v of type (possibly const) T, and an rvalue rv of type T, the following terms are defined. If X is not allocator-aware, the terms below are defined as if A were std::allocator<T> — no allocator object needs to be created and user specializations of std::allocator<T> are not instantiated:

    • T is DefaultInsertable into X means that the following expression is well-formed:

      allocator_traits<A>::construct(m, p);
      
    • An element of X is default-inserted if it is initialized by evaluation of the expression

      allocator_traits<A>::construct(m, p);
      

      where p is the address of the uninitialized storage for the element allocated within X.

    • T is CopyMoveInsertable into X means that the following expression is well-formed:

      allocator_traits<A>::construct(m, p, rv);
      

      and when evaluated the following postconditions hold: The value of *p is equivalent to the value of rv before the evaluation. [Note: rv remains a valid object. Its state is unspecified — end note]

    • T is MoveCopyInsertable into X means that, in addition to satisfying the MoveInsertable requirements, the following expression is well-formed:

      allocator_traits<A>::construct(m, p, rv);
      

      and when evaluated the following postconditions hold: The value of v is unchanged and is equivalent to *p.

    • T is EmplaceConstructible into X from args, for zero or more arguments args, means that the following expression is well-formed:

      allocator_traits<A>::construct(m, p, args);
      
    • T is Erasable from X means that the following expression is well-formed:

      allocator_traits<A>::destroy(m, p);
      

    [Note: A container calls allocator_traits<A>::construct(m, p, args) to construct an element at p using args. The default construct in std::allocator will call ::new((void*)p) T(args), but specialized allocators may choose a different definition. — end note]