以下是 C ++ Primer 5th Edition 的练习:
练习13.53: 作为低效率的问题, HasPtr 赋值运算符并不理想。解释为什么。实施一个 HasPtr 的复制赋值和移动赋值运算符并进行比较 在新的移动赋值运算符中执行的操作 复制和交换版本。(P.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;
}
我的问题是为什么这样做效率不高?
答案 0 :(得分:11)
第1步
设置一个性能测试,用于练习移动赋值运算符。
设置另一个执行复制赋值运算符的性能测试。
第2步
按照问题陈述中的说明设置赋值运算符。
第3步
迭代第1步和第2步,直到您确信自己已正确执行它们为止。
第3步应该可以帮助您了解正在发生的事情,最有可能是告诉您性能在哪里发生变化和不会发生变化。
猜测不是步骤1-3的选项。你实际上必须这样做。否则你(正确地)不相信你的猜测是正确的。
第4步
现在你可以开始猜测了。有些人会称之为“形成一种假设”。说“猜测”的奇特方式。但至少现在它是受过教育的猜测。
我在回答这个问题时进行了这个练习,并注意到一个测试没有显着的性能差异,另一个测试的性能差异为6倍。这进一步促使我得出一个假设。完成这项工作后,如果您不确定您的假设,请使用您的代码,结果和后续问题更新您的问题。
<强>澄清强>
有两个特殊的成员赋值运算符,它们通常具有签名:
HasPtr& operator=(const HasPtr& rhs); // copy assignment operator
HasPtr& operator=(HasPtr&& rhs); // move assignment operator
可以使用单个赋值运算符实现移动赋值和复制赋值,并使用所谓的复制/交换习惯用法:
HasPtr& operator=(HasPtr rhs);
此单一赋值运算符不能使用第一组重载。
使用复制/交换习惯用法实现两个赋值运算符(复制和移动)或仅使用一个是否更好?这就是练习13.53所要求的。要回答,您必须尝试两种方式,并测量复制分配和移动分配。聪明,善意的人通过猜测而不是测试/测量来弄错。你选择了一个很好的练习来学习。
答案 1 :(得分:2)
正如问题所暗示的那样,它是低效率的问题&#34;。当您使用'<li>' and '</li>'
并编写HasPtr& operator=(HasPtr rhs)
之类的内容时,hp = std::move(hp2);
成员会被复制两次(指针本身不是它指向的对象):从ps
到{{}} {1}}调用移动构造函数的结果,以及调用hp2
后从rhs
调用rhs
的结果。但是,当您使用*this
时,swap
只会从HasPtr& operator=(HasPtr&& rhs)
复制到ps
一次。