Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this move allowed?

Tags:

c++

c++11

move

A vector when it does a resize will attempt to use move semantics to move the objects from the old array to the new one. But if the templated object in the vector does not support a no throw noexcept move constructor then it will revert to using copy construction so that the strong exception guarantee is preserved.

But when I try this:

#include <vector>

class X
{
    public:
        // Needs default constructor
        X() {}

        // Copy operations disabled.
        X(X const&)             = delete;
        X& operator=(X const&)  = delete;

        X(X&&)              // throwable move constructor
        {}
        X& operator=(X&&)   // throwable move assignment.
        {return *this;}
};

int main()
{
    // Vector of Size zero
    std::vector<X>  data;

    // Vector of Size ten.
    // Since the move constructor can potentially throw
    // We have to copy elements when we do a resize
    //
    // But X has a disabled copy semantics
    // Thus I would expect a compile time error here.
    data.resize(10);
}

This compiles without error or warning:

> g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
> g++ -std=c++11 test.cpp
>
like image 267
Martin York Avatar asked Dec 19 '22 07:12

Martin York


1 Answers

The strong exception safety guarantee is not provided for noncopyable elements that have a throwing move constructor.

[vector.capacity]/p12-14 (emphasis mine):

void resize(size_type sz); 

12 Effects: If sz <= size(), equivalent to calling pop_back() size() - sz times. If size() < sz, appends sz - size() default-inserted elements to the sequence.

13 Requires: T shall be MoveInsertable and DefaultInsertable into *this.

14 Remarks: If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects.

Note that this doesn't require T to be CopyInsertable.

Internally, the implementation likely uses std::move_if_noexcept, which, despite the name, is really "move if noexcept or if noncopyable".

like image 68
T.C. Avatar answered Jan 07 '23 07:01

T.C.