mardi 4 août 2015

Expected Moves vs Copies

It is my understanding that move semantics can use move-constructors to elide what would otherwise be a copy. For example, a function returning a (perhaps) large data structure can now return by value, and the move constructor will be used to avoid a copy.

My question is this: is the compiler required to not copy when this is possible? It doesn't seem to be the case. In that case, wouldn't the following code have "implementation-defined" semantics?

static const int INVALID_HANDLE = 0xFFFFFFFF;

class HandleHolder {
    int m_handle;
public:
    explicit HandleHolder(int handle) : m_handle(handle) {}
    HandleHolder(HandleHolder& hh) {
        m_handle = hh.m_handle;
    }
    HandleHolder(HandleHolder&& hh) : m_handle(INVALID_HANDLE) {
        swap(m_handle, hh.m_handle);
    }
    ~HandleHolder() noexcept {
        if (m_handle != INVALID_HANDLE) {
            destroy_the_handle_object(m_handle);
        }
    }
};

Say then we make a function:

HandleHolder make_hh(int handle) { return HandleHolder(handle); }

Which constructor is called? I would expect the move constructor, but am I guaranteed the move constructor?

I'm aware this is a silly example and that -- for example -- the copy constructor of this object should be deleted because there is no way to use it safely otherwise, but the semantics are simple enough that I wouldn't think something like this would be implementation-defined.

Aucun commentaire:

Enregistrer un commentaire