强制移动语义

时间:2014-02-26 18:33:11

标签: c++11 move-semantics

我正在尝试使用移动语义(就像一个实验)。 这是我的代码:

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;
}

但是std :: move不会将mc移动到mc2,它只是复制(copyies指针原样)。如果我删除复制构造函数编译器为MyClass生成它。

如何强制使用移动语义?如何使它在这种结构中使用:

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

我试图使用'&amp;&amp;'运算符明确标记rvalue,但是,原因,它不起作用。

3 个答案:

答案 0 :(得分:6)

您将m2声明为引用,不作为值。所以它仍然指的是初始化的内容,即m1。你想要这个:

MyClass mc2 = std::move(mc);

Live example

至于第二部分 - 没有办法强迫这样的结构:

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

移动。如果你想从左值移动(并且mc确实是左值),你必须明确地使用std::move(或另一个强制转换为右值)。

可以做一件事,但这将是一个肮脏的黑客,使代码不直观,并成为错误的一个很好的来源。您可以使用非const引用添加复制构造函数(和复制赋值运算符)的重载,这将执行此操作。基本上像std::auto_ptr这样的东西在它被合理地弃用之前就已经做过了。但它永远不会通过我的代码审查,例如。如果您想移动,只需std::move


一些附注:

  • 在空指针上调用deletedelete[]保证是无操作,因此您可以安全地从析构函数中删除if

  • 通常最好在C ++代码中使用std::copy代替memcpy,您不必担心sizeof正确

答案 1 :(得分:1)

如果删除复制构造函数和赋值运算符

,则可以强制移动语义
MyClass(const MyClass& src)= delete;
void operator=(const MyClass& src) = delete;

在这种情况下,将选择提供的移动构造函数或移动赋值运算符。

答案 2 :(得分:0)

通过一些评论重写一下你的课程。仔细看看,你可能会注意到一些错过的东西。像:

  • MyClass(size_t c)中未检查c != 0
  • 在重新分配之前,
  • void operator=(const MyClass& src)而非delete[] data; (如果存在)

还有一些其他小细节。希望你的编译器可以处理这个问题。

class MyClass {
private:
    // initialize memebers directly
    int* data = nullptr;
    size_t count = 0;
public:
    // default empty contructor
    MyClass() = default;
    // destructor
    ~MyClass() {
        *this = nullptr; // use operator = (nullptr_t)
    }
    // allow nullptr construct
    MyClass(nullptr_t):MyClass() {}
    // allow nullptr assignment (for clearing)
    MyClass& operator = (nullptr_t) {
        if(data) {
            delete[] data;
            data = nullptr;
        }
        count = 0;
        return *this;
    }
    // chain to default constructor, redundant in this case
    MyClass(size_t c):MyClass() {
        // maybe size_t is 0?
        if(count = c) {
            data = new int[count];
        }
    }
    // chain to default constructor, redundant in this case
    MyClass(MyClass&& src):MyClass() {
        *this = std::move(src); // forward to move assignment
    }
    MyClass& operator=(MyClass&& src) {
        // don't swap with self
        if(&src != this) {
            // it's better to swap and let src destroy when it feels like it.
            // I always write move contructor and assignment to swap data.
            // it's gonna be destroyed anyway, or not...
            std::swap(src.data, data);
            std::swap(src.count, count);
        }
        return *this;
    }
    MyClass(const MyClass& src):MyClass() {
        *this = src; // forward to copy assignment
    }
    MyClass& operator = (const MyClass& src) {
        // don't copy to self
        if(&src != this) {
            // delete first
            if(data) {
                delete[] data;
                data = nullptr;
            }

            // now reallocate
            if(count = src.count) {
                data = new int[count];
                memcpy(data, src.data, sizeof(int)* count);
            }
        }
        return *this;
    }
    // easy way to use the object in a if(object) to test if it has content
    explicit operator bool() const {
        return data && count;
    }
    // same as above but made for if(!object) to test if empty
    bool operator !() const {
        return !data || !count;
    }
public:
    int* get_data() const {
        return data;
    }
    size_t get_count() const {
        return count;
    }
    // add more custom methods
};

现在移动你做到这一点:

MyClass object1; // default construct
MyClass object1(5); // construct with capacity
MyClass object2(object1); // copy constructor
MyClass object3(std::move(object1)); // move constructor
object2 = object1; // copy assignment
object3 = std::move(object1); // move constructor
std::swap(object2, object3); // swap the two
object2 = nullptr; // to empty it
if(object1); // bool cast