136
votes

In the process of answering another question I stumbled upon slightly different wordings for std::vector::erase() and std::deque::erase().

This is what C++14 says about std::deque::erase ([deque.modifiers]/4-6, emphasis mine):

Effects: ...

Complexity: The number of calls to the destructor is the same as the number of elements erased, but The number of calls to the assignment operator is no more than the lesser of the number of elements Before the erased elements and the number of elements after the erased elements.

Throws: Nothing unless an exception is thrown by the copy constructor, move constructor, assignment operator, or move assignment operator of T.

And here is what it says about std::vector::erase ([vector.modifiers]/3-5):

Effects: ...

Complexity: The destructor of T is called the number of times equal to the number of the elements erased, but the move assignment operator of T is called the number of times equal to the number of elements in the vector after the erased elements.

Throws: Nothing unless an exception is thrown by the copy constructor, move constructor, assignment operator, or move assignment operator of T.

As you can see, the exception specifications for both of them are the same, but for std::vector it's explicitly mentioned that move assignment operator is called.

There's also requirement for T to be MoveAssignable for erase() to work with both std::vector and std::deque (Table 100), but this doesn't imply the presence of the move assignment operator: one can define a copy assignment operator, and not define move assignment operator, and this class will be MoveAssignable.

Just in case, I checked with GCC and Clang, and indeed std::vector::erase() calls copy assignment operator if there's no move assignment operator, and std::deque::erase() does the same (DEMO).

So the question is: did I miss something, or this is an (editorial) issue in the standard?

Update: I've submitted an LWG issue #2477.

1
Seems like a defect in the standard.Barry
^ ack. An LWG-issue would be appropriate.Columbo
Usually the draft standard is good enough. This is one of those cases where you should be looking at the real thing.Mark Ransom
@MarkRansom the current source of the standard for std::deque and std::vector is the same as in the question, so the probability that the final version differs is very little.Anton Savin
N4141 has the same wording as N4140.Brian Bi

1 Answers

10
votes

At Lenexa meeting the issue got Immediate status with proposed resolution:

This wording is relative to N4296.

Change 23.3.3.4 [deque.modifiers]/5 to:

-5- Complexity: The number of calls to the destructor of T is the same as the number of elements erased, but the number of calls to the assignment operator of T is no more than the lesser of the number of elements before the erased elements and the number of elements after the erased elements.

Change 23.3.6.5 [vector.modifiers]/4 to:

-4- Complexity: The destructor of T is called the number of times equal to the number of the elements erased, but the move assignment operator of T is called the number of times equal to the number of elements in the vector after the erased elements.

That is, if the resolution is accepted there will be no special mention of the move assignment for std::vector::erase, and also the wording for std::deque::erase will be clarified a bit.