写移动复制和移动赋值构造函数的有效方式 [英] The efficient way to write move copy and move assignment constructors

查看:140
本文介绍了写移动复制和移动赋值构造函数的有效方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下赋值和复制移动构造函数是否最有效?
如果有人有其他方式请告诉我?
我的意思是什么bout std :: swap?

Are the following assignment and copy move constructors the most efficient? if anybody have other way please tell me? I mean what bout std::swap? and calling assignment through copy constructor is safe in the code below?

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


推荐答案

,但是包含了大量的重复代码。

Looks fine from an efficiency POV, but contains an awefull lot of duplicated code. I'd


  • 为您的课程实施 swap() li>
  • 初始化它们被声明的 length _ data _ 。 $ b

  • Implement a swap() operator for your class.
  • Initialize length_ and data_ where they are declared.
  • Implement operations in terms of other operations whereever possible.

您可以 std :: memcpy 而不是 std :: copy 一些编译器会为你这样做,但可能不是所有的...

You might want to use std::memcpy instead of std::copy since your dealing with a raw array anway. Some compilers will do that for you, but probably not all of them...

这里是你的代码的重复版本。请注意,如何只有一个地方,需要知道 Widget 的两个实例是如何交换的。

Here's de-duplicated version of your code. Note how there is only one place which needs to know how two instances of Widget are swapped. And only one place which knows how to allocate a Widget of a given size.

编辑:您通常也可以选择一个

You usually also want to use argument-dependent lookup to locate swap, just in case you ever have non-primitive members.

编辑:整合@ Philipp的建议,可以使用参数相关的查找来定位交换使赋值运算符以值为参数。这样,它充当移动分配和复制分配操作符。在移动的情况下,不是如果你传递一个临时,它不会被复制,因为move构造函数,复制构造函数将被用于传递参数。

Integrated @Philipp's suggestion of making the assignment operator take it's argument by value. That way, it acts as both move assignment and copy assignment operator. In the move case, not that if you pass a temporary, it won't be copied, since the move constructor, not the copy constructor will be used to pass the argument.

编辑:C ++ 11允许在rvalues中调用非成本成员,以与以前版本的标准兼容。这允许像 Widget(...)= someWidget 这样的古怪代码来编译。通过将& operator = 需要 >在声明之后阻止。请注意,即使没有这个限制,代码是正确的,但它似乎是一个好主意,所以我添加了它。

C++11 allows non-cost members to be called on rvalues for compatibility with previous versions of the standard. This allows weird code like Widget(...) = someWidget to compile. Making operator= require an lvalue for this by putting & after the declaration prevents that. Note though that the code is correct even without that restriction, but it nevertheless seems like a good idea, so I added it.

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

As Guillaume Papin pointed out, the destructor should use delete[] instead of plain delete. The C++ standard mandates that memory allocated via new [] be deleted via delete [], i.e. it allows new' andnew []` to use different heaps.

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

这篇关于写移动复制和移动赋值构造函数的有效方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆