Move assignment operator and exceptions

Viewed 59

I have a couple of questions about move assignment operator and possibly thrown exceptions:

  1. Provided that is_nothrow_move_assignable<T>::value is true for the type T, is it enough to conclude that move assignment operator for that type will never throw an exception? In other words, is it ok to have this noexcept specification:

    struct MyClass
    {
        MyClass& operator = (MyClass&& other) noexcept(std::is_nothrow_move_assignable<OtherClass>::value)
        {
            this->data = std::move(other.data);
            return *this;
        }
    
        OtherClass data;
    };

(Let's assume that we cannot rely on defaulted move-assignment operator)

  1. Talking specifically about std::vector, in C++11 its move-assignment operator may throw implementation-defined exceptions (according to the docs). And even since C++17 its noexcept specification still depends on the allocator traits. But this is a general case. Let's say we have two instrances of std::vector<double> with default allocator. Is it still possible that move assignment throws an exception in this case?
    std::vector<double> v1{ 1,2,3 }, v2{4,5};
    v1 = std::move(v2);  // can it throw?
1 Answers
  1. No.noexcept keyword says only, that it does not suppose to throw any exception and compiler will assume that the function will not throw exception, thus it will not produce exception-handing code. If noexcept function will throw an exception, the program will be terminated immediately. Thus said, I believe, using noexcept(std::is_nothrow_move_assignable<OtherClass>::value) is enough.
  2. Lets take a look at the standard and cppreference:
noexcept(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value
|| std::allocator_traits<Allocator>::is_always_equal::value)
  • std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value, standard says([allocator.requirements])

If X::propagate_on_- container_move_assignment::value is true, X shall satisfy the MoveAssignable requirement and the move operation shall not throw exceptions.

the double type is plain old builtin type, so it satisfies MoveAssignable requirements (https://en.cppreference.com/w/cpp/named_req/MoveAssignable) and thus exception should not be thrown.

  • std::allocator_traits<Allocator>::is_always_equal::value is true

In noexcept statement binary OR is used, so it shall not throw any exceptions.

Related