本文介绍了为什么使用单个赋值运算符处理复制和移动赋值效率不高?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是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!
";
}

//! operator = using specific swap
HasPtr&
HasPtr::operator = (HasPtr rhs)
{
    swap(*this,rhs);
    return *this;
} 

我的问题是为什么这样做效率不高?

My question is why it is not efficient to do so?

推荐答案

第一步

设置一个性能测试来练习移动赋值运算符.

Set up a performance test which exercises the move assignment operator.

设置另一个性能测试来练习复制赋值运算符.

Set up another performance test which exercises the copy assignment operator.

第 2 步

按照问题陈述中的说明以两种方式设置赋值运算符.

Set up the assignment operator both ways as instructed in the problem statement.

步骤 3

重复第 1 步和第 2 步,直到您确信自己的操作正确为止.

Iterate on Steps 1 and 2 until you have confidence that you did them correctly.

第 3 步应该帮助您了解正在发生的事情,最有可能的方法是告诉您性能在哪些方面发生了变化以及哪些方面没有发生变化.

Step 3 should help educate you as to what is going on, most likely by telling you where the performance is changing and where it is not changing.

猜测不是步骤 1-3 的选项.你实际上必须这样做.否则,您将(理所当然地)对自己的猜测是正确的没有信心.

Guessing is not an option for Steps 1-3. You actually have to do them. Otherwise you will (rightly) have no confidence that your guesses are correct.

步骤 4

现在您可以开始猜测了.有些人会称之为形成假设".说猜测"的奇特方式.但至少现在它是受过教育的猜测.

Now you can start guessing. Some people will call this "forming a hypothesis." Fancy way of saying "guessing." But at least now it is educated guessing.

我在回答这个问题的同时完成了这个练习,并注意到在一项测试中没有显着的性能差异,而在另一项测试中则有 6 倍的性能差异.这进一步使我产生了一个假设.完成这项工作后,如果您不确定自己的假设,请使用您的代码、结果和后续问题更新您的问题.

I ran through this exercise while answering this question and noted no significant performance difference on one test, and a 6X performance difference on the other. This further led me to an hypothesis. After you do this work, if you are unsure of your hypothesis, update your question with your code, results, and subsequent questions.

澄清

有两个特殊的成员赋值运算符,它们通常具有签名:

There are two special member assignment operators which typically have the signatures:

HasPtr& operator=(const HasPtr& rhs);  // copy assignment operator
HasPtr& operator=(HasPtr&& rhs);       // move assignment operator

可以使用称为复制/交换习语的单个赋值运算符来实现移动赋值和复制赋值:

It is possible to implement both move assignment and copy assignment with a single assignment operator with what is called the copy/swap idiom:

HasPtr& operator=(HasPtr rhs);

这个单一的赋值运算符不能被第一个集合重载.

This single assignment operator can not be overloaded with the first set.

使用复制/交换习语是实现两个赋值运算符(复制和移动)还是只实现一个更好?这就是练习 13.53 的要求.要回答,您必须同时尝试两种方法,并测量复制分配和移动分配.聪明的、善意的人们会通过猜测而不是测试/测量来理解这一点.你选择了一个很好的练习来学习.

Is it better to implement two assignment operators (copy and move), or just one, using the copy/swap idiom? This is what Exercise 13.53 is asking. To answer, you must try both ways, and measure both copy assignment and move assignment. And smart, well meaning people get this wrong by guessing, instead of testing/measuring. You have picked a good exercise to study.

这篇关于为什么使用单个赋值运算符处理复制和移动赋值效率不高?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-23 15:16