Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force Move semantics

I'm trying to use move semantics (just as an experiment). Here is my code:

class MyClass {
public:
    MyClass(size_t c): count(c) {
        data = new int[count];
    }



    MyClass( MyClass&& src) : count(src.count) {
        data = src.data;
        src.count = 0;
        src.data = nullptr;
    }

    void operator=( MyClass&& src) {
        data = src.data;
        count = src.count;
        src.count = 0;
        src.data = nullptr;
    }




    ~MyClass() {
        if (data != nullptr)
            delete[] data;
    }

    int* get_data() const {
        return data;
    }

    size_t get_count() const {
        return count;
    }

private:

    MyClass(const MyClass& src) : count(src.count) {
        data = new int[src.count];
        memcpy(data, src.data, sizeof(int)*src.count);
    }

    void operator=(const MyClass& src) {
        count = src.count;
        data = new int[src.count];
        memcpy(data, src.data, sizeof(int)*src.count);
    }


    int* data;
    size_t count;
};


int main()
{
    MyClass mc(150);
    for (size_t i = 0; i < mc.get_count(); ++i)
        mc.get_data()[i] = i;
    MyClass &&mc2 = std::move(mc);

    return 0;
}

But std::move does not move mc to mc2, it just copies (copyies pointer as it is). If I remove copy constructor compiler generates it for MyClass.

How can I force move semantics to be used? How can I make it to be used in such constructions:

MyClass mc2(mc); //Move, not copy
-or-
MyClass mc2 = mc; //Move, not copy

I tried to use a '&&' operator to explicitely mark rvalue, but, of cause, it didn't work.

like image 264
Xanx Avatar asked Feb 26 '14 18:02

Xanx


People also ask

What's the need to move semantics?

Move semantics allows you to avoid unnecessary copies when working with temporary objects that are about to evaporate, and whose resources can safely be taken from that temporary object and used by another.

What does STD move do?

std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.

What is the difference between the Move and Copy operator?

Copy assignment operator create a new object from passed object by copying each and every item into a new memory location. Move assignment operator create a new object by using as much memory from passed object.

What are move constructors?

A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying. For more information about move semantics, see Rvalue Reference Declarator: &&. This topic builds upon the following C++ class, MemoryBlock , which manages a memory buffer.


2 Answers

You're declaring m2 as a reference, not as a value. So it still refers to what it was initialised with, namely m1. You wanted this:

MyClass mc2 = std::move(mc);

Live example

As for the second part - there is no way to force a construct like these:

MyClass mc2(mc); //Move, not copy
//-or-
MyClass mc2 = mc; //Move, not copy

to move. If you want to move from an lvalue (and mc is indeed an lvalue), you have to use std::move (or another cast to rvalue) explicitly.

There is one thing you could do, but it would be a dirty hack, make the code unintuitive and be a great source for bugs. You could add an overload of the copy constructor (and copy assignment operator) taking a non-const reference, which would do the move. Basically something like std::auto_ptr used to do before it was rightfully deprecated. But it would never pass code review with me, for example. If you want to move, just std::move.


A few side notes:

  • Calling delete or delete[] on a null pointer is guaranteed to be a no-op, so you can safely drop the if from your destructor.

  • It's generally preferable to use std::copy instead of memcpy in C++ code, you don't have to worry about getting the sizeof right

like image 185
Angew is no longer proud of SO Avatar answered Sep 18 '22 06:09

Angew is no longer proud of SO


You can force move semantics, if you delete the copy constructor and the assignment operator

MyClass(const MyClass& src)= delete;
void operator=(const MyClass& src) = delete;

in this case the provided move constructor or move assignment operator will be picked.

like image 31
Wolfgang Kundrus Avatar answered Sep 22 '22 06:09

Wolfgang Kundrus