[英]Implementing copy assignment operator in terms of move constructor
考虑以下概念/示例类
class Test
{
public:
explicit Test(std::string arg_string)
: my_string( std::move(arg_string) )
{ }
Test(const Test& Copy) {
this->my_string = Copy.my_string;
}
Test& operator=(Test Copy) {
MoveImpl( std::move(Copy) );
return *this;
}
Test(Test&& Moved) {
MoveImpl( std::forward<Test&&>(Moved) );
}
Test& operator=(Test&& Moved) {
MoveImpl( std::forward<Test&&>(Moved) );
return *this;
}
private:
void MoveImpl(Test&& MoveObj) {
this->my_string = std::move(MoveObj.my_string);
}
std::string my_string;
};
复制构造const&
照常采用const&
。
复制赋值运算符是根据复制构造函数实现的(如我记得正确,Scott Meyers指出,异常安全性和自赋值问题可以通过这种方式解决)。
在实现move构造函数和move赋值运算符时,我发现存在一些“代码重复”,通过添加MoveImpl(&&)
私有方法来“消除”。
我的问题是,由于我们知道复制赋值运算符会获取对象的新副本,该对象将在作用域端清除,因此使用MoveImpl()
函数实现复制赋值的功能是否正确/好的做法运营商。
复制赋值运算符的按值签名的妙处在于,它消除了对移动赋值运算符的需求(前提是您正确定义了移动构造函数!)。
class Test
{
public:
explicit Test(std::string arg_string)
: my_string( std::move(arg_string) )
{ }
Test(const Test& Copy)
: my_string(Copy.my_string)
{ }
Test(Test&& Moved)
: my_string( std::move(Moved.my_string) )
{ }
// other will be initialized using the move constructor if the actual
// argument in the assignment statement is an rvalue
Test& operator=(Test other)
{
swap(other);
return *this;
}
void swap(Test& other)
{
std::swap(my_string, other.my_string);
}
private:
std::string my_string;
};
您的思路是正确的,但通用点在于交换操作。
如果您尝试更早进行操作,则将失去在构造函数的初始化列表中初始化成员的机会,从概念上讲,这会导致成员的冗余默认初始化以及难以整齐地处理异常的困难。
这更接近您想要的模型:
class Test
{
public:
explicit Test(std::string arg_string)
: my_string( std::move(arg_string) )
{ }
Test(const Test& Copy) : my_string(Copy.my_string)
{
}
Test& operator=(Test const& Copy)
{
auto tmp(Copy);
swap(tmp);
return *this;
}
Test(Test&& Moved) : my_string(std::move(Moved.my_string))
{
}
Test& operator=(Test&& Moved)
{
auto tmp = std::move(Moved);
swap(tmp);
return *this;
}
void swap(Test& other) noexcept
{
using std::swap;
swap(my_string, other.my_string);
}
private:
std::string my_string;
};
当然,实际上,除非您绝对需要在析构函数中进行特殊处理(您几乎从不这样做),否则零规则应始终优先考虑:
class Test
{
public:
explicit Test(std::string arg_string)
: my_string( std::move(arg_string) )
{ }
// copy, assignment, move and move-assign are auto-generated
// as is destructor
private:
std::string my_string;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.