3

A type X has a non-trivial move-constructor, which is not declared noexcept (ie. it can throw):

#include <iostream>
#include <vector>
#include <memory>


struct X {
    X()=default;
    X(X&&) { std::cout << "X move constructed\n"; } // not 'noexcept'
    X(const X&) { std::cout << "X copy constructed\n"; }
};

struct test {
    X x;
};

int main()
{
    static_assert(std::is_nothrow_move_constructible_v<X> == false);
    static_assert(std::is_nothrow_move_constructible_v<test> == false);

    std::vector<test> v(1);
    v.push_back(test{}); // internal object re-allocation, uses copy-constructor
}

When calling push_back on a vector<test>, internal reallocations cause existing objects to be copied, which is expected. The output is:

X move constructed
X copy constructed

Apparently, the second line is related to internal object reallocation.

Now an unrelated std::unique_ptr<int> is added to test:

struct test {
    std::unique_ptr<int> up;
    X x;
};

The output becomes:

X move constructed
X move constructed

Why is internal reallocation using the move-constructor this time ?
Technically, X(X&&) can still throw an exception; wouldn't that violate the strong exception guarantee of push_back ?

compiler is gcc 11.2.1 and/or clang 12.0.1

curiousguy12
  • 1,741
  • 1
  • 10
  • 15
  • 1
    `emplace_back`'s strong exception guarantee is revoked if an element's move constructor throws. It will only use a non-noexcept move constructor if it absolutely has to, it prefers a copy constructor to a potentially throwing move constructor specifically to avoid having to break this guarantee. – François Andrieux Feb 09 '22 at 16:53

1 Answers1

2

According to [vector.modifiers]/2 if the element type of std::vector is not copy-insertable and not nothrow-move-constructible, then an exception thrown from a move constructor of the element type results in an unspecified state of the container.

std::vector must prefer the copy constructor if the type isn't nothrow-movable, so that the exception guarantees can be preserved, but if that isn't possible, it is impossible to give strong exception guarantees.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • So much for strong guarantees huh.. IMO, it should have rejected the code, but I'm not in the committee. Thanks for the answer. – curiousguy12 Feb 10 '22 at 10:37