a.assign(n, t)
Section: 23.2.4 [sequence.reqmts] Status: New Submitter: Kazutoshi Satoda Opened: 2016-05-08 Last modified: 2020-09-06
Priority: 3
View other active issues in [sequence.reqmts].
View all other issues in [sequence.reqmts].
View all issues with New status.
Discussion:
Please look through the following modifications on a value v
of type vector<T>
:
assert(v.size() > 0); v.push_back(v[0]); v.insert(v.begin(), v[0]); v.resize(v.size() * 2, v[0]); v.assign(v.size() * 2, v[0]);
All of these use an element of itself which may be moved or destroyed by the modification.
From what I see so far, the first three are required to work. Please see library issue 526 for validity of them. But only the last one is undefined because it violates a precondition of a sequence container operation. I think this is too subtle. Should it be like that, really? The precondition is in Table 107 "Sequence container requirements" at the next of 23.2.4 [sequence.reqmts] p3.In Tables 107 and 108,
X
denotes a sequence container class,a
denotes a value ofX
containing elements of typeT
, […]n
denotes a value ofX::size_type
, […]t
denotes an lvalue or aconst
rvalue ofX::value_type
, […][…]
Table 107 — Sequence container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-condition[…]
a.assign(n, t)
void
Requires: T
shall beCopyInsertable
intoX
andCopyAssignable
.
pre:t
is not a reference intoa
.
Replaces elements ina
withn
copies oft
.
I looked into the following implementations:
libc++ relies on the precondition.
It deallocates first onn > capacity()
case,
see here.
libstdc++ doesn't rely on the precondition.
It creates temporaryvector(n, t)
and swap()
on n > capacity()
case, see
here.
MSVC relies on the precondition.
It unconditionally doesclear()
and then insert(begin(), n, t)
.
I looked into my local "%PROGRAMFILES(X86)%/Microsoft Visual Studio 14.0/VC/include/vector
".
One drawback of libstdc++ implementation, I could find so far, is
possibly increased peek memory usage (both old and new buffer exist at
the same time). But, because the same can happen on the most other
modifications, it seems a reasonable trade-off to remove the
precondition to fill the subtle gap. Users who really needs less memory
usage can do clear()
and insert()
by themselves.
basic_string::assign(n, c)
is safe on this point.
At 27.4.3.7.3 [string.assign] p17:
basic_string& assign(size_type n, charT c);Effects: Equivalent to
Returns:assign(basic_string(n, c))
.*this
.
This can be seen as another gap.
Looking back on the history, I found that the definition ofassign(n, t)
was changed at C++14 for library issue 2209. There were more restricting
definitions like this:
void assign(size_type n, const T& t);Effects:
erase(begin(), end()); insert(begin(), n, t);
I think the precondition was probably set to accept this old definition and is not required inherently. And if the less memory usage was really intended, the standard is now underspecifying about that.
[2016-05 Issues Telecon]
Howard believes this should be NAD, but we tabled the discussion.
Previous resolution [SUPERSEDED]:This wording is relative to N4582.
In 23.2.4 [sequence.reqmts], edit Table 107 (Sequence container requirements) as indicated:
Table 107 — Sequence container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-condition[…]
a.assign(n, t)
void
Requires: T
shall beCopyInsertable
intoX
andCopyAssignable
.
pre:t
is not a reference intoa
.
Replaces elements ina
withn
copies oft
.
[2020-04-25, Daniel syncs current wording with recent working draft]
Proposed resolution:
This wording is relative to N4861.
In 23.2.4 [sequence.reqmts], edit Table [tab:container.seq.req] (Sequence container requirements) as indicated:
Table 77 — Sequence container requirements (in addition to container) [tab:container.seq.req] Expression Return type Assertion/note
pre-/post-condition[…]
a.assign(n, t)
void
Preconditions: T
is Cpp17CopyInsertable intoX
and Cpp17CopyAssignable.t
is not a reference intoa
.
Effects: Replaces elements ina
withn
copies oft
.
Invalidates all references, pointers and iterators referring to the elements ofa
.
Forvector
anddeque
, also invalidates the past-the-end iterator.