编写移动副本和移动赋值构造函数的有效方法

Abd*_*man 4 c++ constructor move variable-assignment c++11

以下赋值和副本移动构造函数是否最有效?如果有人有其他方式请告诉我?我的意思是什么回合std :: swap?并通过复制构造函数调用赋值在下面的代码中是安全的吗?

#include <iostream>
#include <functional>
#include <algorithm>
#include <utility>

using std::cout;
using std::cin;
using std::endl;
using std::bind;


class Widget
{

public:

    Widget(int length)
        :length_(length),
        data_(new int[length])
    {
        cout<<__FUNCTION__<<"("<<length<<")"<<endl;
    }

    ~Widget()
    {
        cout<<endl<<__FUNCTION__<<"()"<<endl;
        if (data_)
        {
            cout<<"deleting source"<<endl;
        } 
        else
        {
            cout<<"deleting Moved object"<<endl;
        }

        cout<<endl<<endl;
    }

    Widget(const Widget& other)
        :length_(other.length_),
        data_(new int[length_])
    {
        cout<<__FUNCTION__<<"(const Widget& other)"<<endl;
        std::copy(other.data_,other.data_ + length_,data_);
    }

    Widget(Widget&& other)
/*
        :length_(other.length_),
        data_(new int[length_])*/
    {
        cout<<__FUNCTION__<<"(Widget&& other)"<<endl;
        length_ = 0;
        data_ = nullptr;
        std::swap(length_,other.length_);
        std::swap(data_,other.data_);
    }

    Widget& operator = (Widget&& other)
    {
        cout<<__FUNCTION__<<"(Widget&& other)"<<endl;

        std::swap(length_,other.length_);
        std::swap(data_,other.data_);

        return *this;
    }

    Widget& operator = (const Widget& other)
    {
        cout<<__FUNCTION__<<"(const Widget& other)"<<endl;
        Widget tem(other);
        std::swap(length_,tem.length_);
        std::swap(data_,tem.data_);

        return *this;
    }
    int length()
    {
        return length_;
    }

private:

    int length_;
    int* data_;
};



int main()
{
    {
        Widget w1(1);
        Widget w2(std::move(Widget(2)));

        w1 = std::move(w2);
    }


    cout<<"ENTER"<<endl;
    cin.get();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

fgp*_*fgp 6

从效率POV看起来很好,但包含大量重复的代码.ID

  • swap()为您的班级实施操作员.
  • 初始化length_以及data_声明它们的位置.
  • 尽可能在其他操作方面实施操作.

可能想要使用std::memcpy而不是std::copy因为您正在处理原始数组.有些编译器会为你做这件事,但可能不是全部......

这是代码的重复数据删除版本.请注意,只有一个地方需要知道如何Widget交换两个实例.并且只有一个知道如何分配给定大小的Widget的地方.

编辑:您通常还希望使用依赖于参数的查找来定位交换,以防您有非原始成员.

编辑:集成@ Philipp的建议,让赋值运算符按值获取它的参数.这样,它充当移动分配和复制赋值运算符.在移动的情况下,不是如果你传递一个临时的,它不会被复制,因为移动构造函数,而不是复制构造函数将用于传递参数.

编辑: C++ 11允许在rvalues上调用非成本成员,以便与先前版本的标准兼容.这允许Widget(...) = someWidget编译奇怪的代码.制作operator=需要一个左为this通过将&声明防止以后.请注意,即使没有这个限制,代码也是正确的,但它似乎是一个好主意,所以我添加了它.

编辑:正如Guillaume Papin所指出的,析构函数应该使用delete[]而不是普通的delete.C++标准要求通过new []删除分配的内存delete [],即允许new' andnew []`使用不同的堆.

class Widget
{
public:
    Widget(int length)
        :length_(length)
        ,data_(new int[length])
    {}

    ~Widget()
    {
        delete[] data_;
    }

    Widget(const Widget& other)
        :Widget(other.length_)
    {
        std::copy(other.data_, other.data_ + length_, data_);
    }

    Widget(Widget&& other)
    {
        swap(*this, other);
    }

    Widget& operator= (Widget other) &
    {
        swap(*this, other);
        return *this;
    }

    int length() const
    {
        return length_;
    }

private:
    friend void swap(Widget& a, Widget& b);

    int length_ = 0;
    int* data_ = nullptr;
};

void swap(Widget& a, Widget& b) {
    using std::swap;
    swap(a.length_, b.length_);
    swap(a.data_, b.data_);
}
Run Code Online (Sandbox Code Playgroud)