std::vector
Section: 23.3.11.3 [vector.capacity] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-05-08 Last modified: 2022-11-06
Priority: 3
View other active issues in [vector.capacity].
View all other issues in [vector.capacity].
View all issues with Open status.
Discussion:
There are various operations on std::vector
that can cause elements of the vector to be
moved from one location to another. A move operation can use either rvalue or const lvalue as
argument; the choice depends on the value of !is_nothrow_move_constructible<T>::value &&
is_copy_constructible<T>::value
, where T
is the element type. Thus, some operations
on std::vector
(e.g. 'resize' with single parameter, 'reserve', 'emplace_back') should have
conditional requirements. For example, let's consider the requirement for 'reserve' in N3376 –
23.3.11.3 [vector.capacity]/2:
Requires:
T
shall beMoveInsertable
into*this
.
This requirement is not sufficient if an implementation is free to select copy constructor when
!is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value
evaluates to true. Unfortunately, is_copy_constructible
cannot reliably determine whether
T
is really copy-constructible. A class may contain public non-deleted copy constructor whose
definition does not exist or cannot be instantiated successfully (e.g.,
std::vector<std::unique_ptr<int>>
has copy constructor, but this type is not
copy-constructible). Thus, the actual requirements should be:
if !is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value
then T
shall be CopyInsertable
into *this
;
otherwise T
shall be MoveInsertable
into *this
.
Maybe it would be useful to introduce a new name for such conditional requirement (in addition to
"CopyInsertable
" and "MoveInsertable
").
[2016-08 Chicago]
The problem does not appear to be as severe as described. The MoveInsertable
requirements are consistently correct, but an issue may arise on the
exception-safety guarantees when we check for
is_copy_constructible_v<T>
. The problem, as described, is
typically for templates that appear to have a copy constructor, but one that
fails to compile once instantiated, and so gives a misleading result for the
trait.
In general, users should not provide such types, and the standard would not
serve users well by trying to address support for such types. However, the
standard should not be providing such types either, such as
vector<unique_ptr<T>>
. A possible resolution would be
to tighten the constraints in Table 80 — Container Requirements, so that if
the Requirements for the copy constructor/assingment operator of a container
are not satisfied, that operation shall be deleted.
A futher problem highlighted by this approach is that there are no constraints on
the copy-assignment operator, so that vector<unique_ptr<T>>
should be CopyAssignable
! However, we can lift the equivalent constraints from
the Allocator-aware container requirements.
[08-2016, Chicago]
Fri PM: Move to Open
[2017-11 Albuquerque Saturday issues processing]
There's a bunch of uses of "shall" here that are incorrect. Also, CopyInsertable contains some semantic requirements, which can't be checked at compile time, so 'ill-formed' is not possible for detecting that.
[2018-06 Rapperswil Wednesday issues processing]
Daniel to provide updated wording.
[2018-06-12, Daniel provides revised wording]
Previous resolution [SUPERSEDED]:
This wording is relative to N4606.
23.2.2 [container.requirements.general] Table 80 — Container requirements Expression Return type Operational semantics Assertion/note/pre-/post-condition Complexity X(a)
Requires: T
isCopyInsertable
intoX
(see below)., otherwise this expression shall be ill-formed.
post:a == X(a)
.linear X u(a)
X u = a;
Requires: T
isCopyInsertable
intoX
(see below)., otherwise this expression shall be ill-formed.
post:u == a
.linear ... ... ... ... ... r = a
X&
Requires: T
isCopyInsertable
intoX
andCopyAssignable
, otherwise this expression shall be ill-formed.
post:r == a
.linear
23.2.2 [container.requirements.general] Table 83 — Allocator-aware container requirements Expression Return type Operational semantics Assertion/note/pre-/post-condition Complexity a = t
X&
Requires: T
isCopyInsertable
intoX
andCopyAssignable
., otherwise this expression shall be ill-formed
post:r == a
.linear
[2018-08-23 Batavia Issues processing. Priority to 3]
Changed CopyInsertable
-> Cpp17CopyInsertable
in the resolution.
Tim says that the wording is not quite right — it imposes additional requirements.
[2022-11-06; Daniel comments]
This issue has considerable overlap with LWG 3758.
Proposed resolution:
This wording is relative to N4750.
The revised wording below uses the new Mandates: element introduced by adopting P0788R3 at the Rapperswil meeting 2018 and which will become a new term of art with Jonathan's omnibus paper throughout the Standard Library.
Expression | Return type | Operational semantics | Assertion/note/pre-/post-condition | Complexity |
X(a) |
Mandates: Syntactic requirements of T is Cpp17CopyInsertable into X (see below).Requires: T is Cpp17CopyInsertable into
X post: a == X(a) .
|
linear | ||
X u(a) X u = a; |
Mandates: Syntactic requirements of T is Cpp17CopyInsertable into X (see below).Requires: T is Cpp17CopyInsertable into
X post: u == a .
|
linear | ||
... | ... | ... | ... | ... |
r = a |
X& |
Mandates: Syntactic requirements of T is Cpp17CopyInsertable into X (see below) and
CopyAssignable .Requires: T is Cpp17CopyInsertable into X
and CopyAssignable .post: r == a . |
linear |
Expression | Return type | Operational semantics | Assertion/note/pre-/post-condition | Complexity |
a = t |
X& |
Mandates: Syntactic requirements of T isCpp17CopyInsertable into X and CopyAssignable .Requires: T is Cpp17CopyInsertable into X and
CopyAssignable .post: r == a . |
linear |