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)
从效率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)