zoukankan      html  css  js  c++  java
  • 条款20: 宁以pass-by-reference-to-const 替换 pass-by-value

    1、为什么要宁以pass-by-reference-to-const 替换 pass-by-value

    效率方面

    缺省情况下,C++以by value 方式传递对象至(或来自)函数。
    除非你另外指定,否则函数参数都是以实际实参的副本为初值,而调用段所获得的亦是函数返回值的一个副本。这些副本都是由对象的copy构造函数产出的,这可能使得pass-by-value 称为昂贵的(费时的)操作。

    考虑下述例子:

    class Person {
    public:
        Person();
        virtual ~Person();
        ...
    private:
        string name;
        string address;
    };
    
    class Student: public Person {
    public:
        Student();
        ~Student();
        ...
    private:
        string schoolName;
        string schoolAddress;    
    };
    
    bool validateStudent(Student s);
    Student plato;
    
    //传递参数方式一
    bool platoIsOK = validateStudent(plato);
    //传递参数方式二
    bool validateStudent(const Student& s);
    

    以方式一传递参数时,由于C++默认的是by value 的方式,因此,会构造一个Student对象,并且以plato进行初始化。这会导致调用Student的构造函数,而当函数返回时,势必又要调用其析构函数。 这只是表面,由于Student继承自Person,因此在创建Student时,势必要调用其基类的构造函数来初始化其基类部分,销毁时也是同样的。而又由于Person 和Student类中又内涵string对象,因此在构建时,又要调用string对象的构造和析构函数。全部算在一起,一共会调用6次析构函数和6次构造函数。这是非常耗时的操作。

    而避免上述耗时的方法也非常简单,即以pass-by-value-to-const方式传递参数即可。这样的传递方式不会有任何新的对象被创建,因此也不会调用析构函数和构造函数。

    2、第二个原因,避免slicing(对象切割)问题

    (1)什么是对象切割问题?

    一个函数的形参,接收的是一个基类的对象。 但如果调用这个函数时,传递的是一个派生类对象的话,那么形参只会构造这个派生类对象的基类部分作为实参。因此,当在函数内使用这个派生类对象时,它的所有被特化的部分都会表现的是基类的特性。

    举栗子:

    class Window {
    public:
        ...
        string name() const;
        virtual void display() const;
    };
    class WindowWithScrollBars: public Window {
    public:
        ...
        virtual void display() const;
    };
    
    void printNameAndDisplay(Window w) //造成对象切割问题
    {
        cout << w.name();
        w.display();
    }
    
    
    //解决办法
    void printNameAndDisplay(const Window& w)
    {
        cout << w.name();
        w.display();
    }
    
    (2)解决的方法

    参数以pass-by-reference-to-const 方式传递。

    3、pass-by-reference-to-const和pass-by-value的区别,及适用场景?

    pass-by-reference-to-const 的底层实现是指针,pass-by-reference-to-const方式通常意味着传递的是指针。因此,如果是内置类型的参数,pass-by-value比pass-by-reference-to-const的效率更高一些。同样的,对于STL的迭代器,以及函数对象,pass-by-value比pass-by-reference-to-const的效率更高一些。

    因此对于内置类型、STL迭代器、函数对象 这三类,使用by value方式传递参数更好。

    4、是不是小型的type都可以pass-by-value?

    不是的,从下述三个方面考虑。

    (1)小型的type 可能在今后的维护中变大。
    (2)小型的type 的copy构造函数可能代价依然很大。
    (3)即使小型的type 的copy构造函数的代价不大,编译器对待自定义类型和内置类型的态度是截然不同的。例如:编译器往往拒绝把对象放进缓存器,而接受把内置类型放进缓存器,即使它们的底层描述是一样的。能放进缓存器,效率肯定就会高一点。
  • 相关阅读:
    webservice接口示例(spring+xfire+webservice)
    SoapUI 测试接口演示
    XML 文档结构必须从头至尾包含在同一个实体内
    Oracle url编码与解码
    【中山市选2010】【BZOJ2467】生成树
    synchronized与static synchronized 的差别、synchronized在JVM底层的实现原理及Java多线程锁理解
    自己动手写搜索引擎
    PopupWindow底部弹出
    JAVA集合类型(二)
    双卡手机发送短信
  • 原文地址:https://www.cnblogs.com/lasnitch/p/12764176.html
Copyright © 2011-2022 走看看