为什么同时使用一个赋值运算符处理复制和移动赋值效率不高
Why is it not efficient to use a single assignment operator handling both copy and move assignment?
以下是C++Primer第五版:的练习
练习13.53:作为低效率的问题,HasPtr赋值运算符并不理想。解释原因。实施复制分配并移动HasPtr的分配运算符并进行比较在新的移动分配操作符中执行的操作与复制和交换版本。(第544页)
文件hasptr.h
:
//! a class holding a std::string*
class HasPtr
{
friend void swap(HasPtr&, HasPtr&);
friend bool operator <(const HasPtr& lhs, const HasPtr& rhs);
public:
//! default constructor.
HasPtr(const std::string &s = std::string()):
ps(new std::string(s)), i(0)
{ }
//! copy constructor.
HasPtr(const HasPtr& hp) :
ps(new std::string(*hp.ps)), i(hp.i)
{ }
//! move constructor.
HasPtr(HasPtr&& hp) noexcept :
ps(hp.ps), i(hp.i)
{ hp.ps = nullptr; }
//! assignment operator
HasPtr&
operator = (HasPtr rhs);
//! destructor.
~HasPtr()
{
delete ps;
}
private:
std::string *ps;
int i;
};
文件hasptr.cpp
:的一部分
//! specific swap.
inline void
swap(HasPtr &lhs, HasPtr &rhs)
{
using std::swap;
swap(lhs.ps, rhs.ps); // swap the pointers, not the string data
swap(lhs.i, rhs.i); // swap the int members
std::cout <<"swapping!n";
}
//! operator = using specific swap
HasPtr&
HasPtr::operator = (HasPtr rhs)
{
swap(*this,rhs);
return *this;
}
我的问题是,为什么这样做没有效率?
步骤1
设置一个性能测试,练习移动分配运算符。
设置另一个性能测试,练习复制分配运算符。
步骤2
按照问题陈述中的说明,双向设置赋值运算符。
步骤3
重复执行步骤1和2,直到您确信自己做得正确为止。
步骤3应该有助于教育您了解正在发生的事情,很可能是告诉您性能在哪里发生了变化和在哪里没有发生变化。
猜测不是步骤1-3的选项。实际上你必须去做。否则,你将(正确地)不相信你的猜测是正确的。
步骤4
现在您可以开始猜测了。有些人会称之为"形成假设"。这是"猜测"的一种奇特说法。但至少现在它是受过教育的猜测。
在回答这个问题时,我完成了这个练习,并注意到一次测试没有显著的性能差异,另一次测试的性能差异为6X。这进一步使我得出了一个假设。完成这项工作后,如果您不确定自己的假设,请使用代码、结果和后续问题更新您的问题。
澄清
有两种特殊的成员分配运算符,它们通常具有签名:
HasPtr& operator=(const HasPtr& rhs); // copy assignment operator
HasPtr& operator=(HasPtr&& rhs); // move assignment operator
可以使用一个具有所谓复制/交换习惯用法的分配运算符来实现移动分配和复制分配:
HasPtr& operator=(HasPtr rhs);
第一个集合不能重载此单个赋值运算符。
使用复制/交换习惯用法实现两个赋值运算符(复制和移动),还是只实现一个更好?这就是练习13.53的要求。若要回答,您必须同时尝试两种方法,并测量复制作业和移动作业。聪明、善意的人会通过猜测而不是测试/测量来犯错。你选择了一个好的练习来学习。
正如问题所表明的,这是"低效率的问题"。当您使用HasPtr& operator=(HasPtr rhs)
并编写类似hp = std::move(hp2);
的内容时,ps
成员会被复制两次(指针本身不是它所指向的对象):一次是由于调用move构造函数而从hp2
复制到rhs
,一次是因为调用swap
而从rhs
复制到*this
。但是当您使用HasPtr& operator=(HasPtr&& rhs)
时,ps
只从rhs
复制到*this
一次。
- 警告处理为错误这里有什么问题
- 在C#中处理C++指针而不使用unsafe的最佳方法
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 处理多个异常集合的C++方法
- 使用strcpy将char数组的元素复制到另一个数组
- 如何处理带有指针的类的双(或多个)复制构造函数
- 为什么Boost.Asio处理程序必须是可复制的
- 为什么同时使用一个赋值运算符处理复制和移动赋值效率不高
- 每次需要时,将整个文件从磁盘复制到内存中,以处理或读取文件中的数据,直到文件全部读取
- 文件处理,在复制内容时插入ÿ字符
- 如何与命名构造函数一起处理不可复制的成员
- 在复制赋值运算符(c++)中处理异常
- 如何最好地处理具有未初始化内存的复制交换习惯用法
- C++运算符语法,用于处理 a = b + c,而无需在 "a.data_ptr" 中显式复制数据
- c++中的文件处理,将数据复制到类的对象
- 如何处理复制指针的释放
- 在异常处理中避免复制
- 默认复制构造函数是否处理常量
- 如何处理赋值操作符和复制构造函数中的引用数据成员