zoukankan      html  css  js  c++  java
  • More Effective C++ 条款22 考虑以操作符复合形式(op=)取代其独身形式(op)

    1. 一般来说,重载了算数操作符(以下称"独身形式"),那么也就要重载复合赋值操作符(以下称"复合形式").要确保操作符的复合形式例如(operator+=)和独身形式(例如operator+)行为相一致,基于前者实现后者是一个好方法.例如:

    class Rational{
    public:
        Rational operator+=(const Rational&);
       ...
    }
    Rational operator+(const T&lhs,const T&rhs){
        return T(lhs)+=rhs;
    }
    View Code

     2. 操作符的复合形式通常比其独身形式效率更高:独身形式需要返回新对象,因而需要承担临时对象的构造和析构成本,复合形式直接将结果写入右端变量,不需要临时对象的构造过程,因此以下使用独身形式的写法:

    Rational a,b,c,d;
    ...
    Rational result=a+b+c+d;

        效率没有使用复合形式的写法高:

    Rational a,b,c,d;
    Rational result=a;
    result+=b+=c+=d;

        因为前者使用operator+产生了3个临时对象,即使有RVO(返回值优化,见条款21),那也只是发生在最后一个operator+,而前两个operator+构造的临时对象不会被优化掉(稍后会解释,如果按照1中operator+的实现,即使是最后一个operator+产生的临时对象也不会被优化,因此临时对象总共有3个而不是2个).

        前者易编写,维护,调试而后者效率较高,对汇编程序员比较直观.

    3. 《More Effective C++》解释了1中operator的实现方法为

    Rational operator+(const T&lhs,const T&rhs){
        return T(lhs)+=rhs;
    }

    的原因(为了便于说明,称以上实现为版本1),声称返回匿名对象比返回具名对象更容易使编译器实行RVO,但所谓的"返回匿名对象比返回具名对象更容易使比编译器实行RVO"是建立在两个基础之上的:1.NRVO(具名返回值优化,见条款21)还未出现;2.返回匿名对象,return语句只返回一个匿名对象,而不再对其进行其他操作.

        对于以下操作:

    Rational a,b;
    Rational c=a+b;

        operator+的版本1实际上是无法完成RVO的:版本的最后一步是return T(lhs)+=rhs,返回的不是临时对象T(lhs),而是临时对象调用operator+=后的结果,此时编译器不知道谁才是要返回的结果(T(lhs)这个临时对象显然不是,因为还有后续操作),因此只能老老实实的对T(lhs)调用operator+=,再将临时对象的结果拷贝给c,临时对象的产生无法避免.

        也就是说,《More Effective C++》所提倡的这种方法现在来看已经不合时宜了,在NRVO已经普及的今天,operator+的以下实现(称版本2)反而更能帮助编译器实现优化:

    Rational operator+(const Rational&lhs,const Ration&rhs){
        Rational temp(lhs);
        temp+=rhs;
        return temp;
    }
    View Code

         以下是实验代码以及Win7-32,Visual Studio 2013 release模式下的结果:

    #include<iostream>
    using namespace std;
    class Rational{
    public:
        Rational& operator+=(const Rational&rhs){
            numerator += rhs.numerator;
            denominator += rhs.denominator;
            return *this;
        }
        Rational(const Rational&rhs){
            cout << "copy constructor" << endl;
        }
        Rational() :numerator(0), denominator(0){ cout << "constructor" << endl; }
    private:
        int numerator;
        int denominator;
    };
    Rational operator+(const Rational& lhs, const Rational& rhs){
        return Rational(lhs)+=rhs;
    }
    int main(){
        Rational a, b;
        Rational c = a + b;
        system("pause");
        return 0;
    }
    View Code

        运行结果为

        共调用了两次copy constructor,可见并没有实行优化.

        operator+改为实现2后:

    Rational operator+(const Rational& lhs, const Rational& rhs){
        Rational temp(lhs);
        temp += rhs;
        return temp;
    }
    View Code

        实验结果为:

        只调用了一次copy constructor,可见直接将operator+中的temp替换为外层的c,即实行了NRVO优化.

        以上实验的详细解释可参照http://www.xuebuyuan.com/1595871.html,由于实验平台不同,实验结果会有出入,但是中心思想是相同的.

  • 相关阅读:
    【HDU2007】平方和与立方和
    NetCore3.1使用Nexus包管理生成docker镜像(含权限)
    NetCore3.1使用nacos访问阿里云ACM配置中心中KVM加密后的配置
    【架构笔记】基础篇04 数组、队列、链表
    【架构笔记】基础篇03 CPU的运行与其对线程的影响
    【架构笔记】基础篇02 网络模型与细节思维方式构建
    【架构笔记】基础篇01 CPU运行基本原理
    dotnetcore使用selenium爬取svn代码路径目录
    【架构笔记】基础篇 09 简述N种查找算法
    【架构笔记】基础篇 08简述N种排序算法
  • 原文地址:https://www.cnblogs.com/reasno/p/4839374.html
Copyright © 2011-2022 走看看