• C++ 传值和传引用的效率对比


    条款22: 尽量用“传引用”而不用“传值”

    c语言中,什么都是通过传值来实现的,c++继承了这一传统并将它作为默认方式。除非明确指定,函数的形参总是通过“实参的拷贝”(拷贝构造函数)来初始化的,函数的调用者得到的也是函数返回值的拷贝。为避免这种潜在的昂贵的开销,就不要通过值来传递对象,而要通过引用。

    通过引用来传递参数还有另外一个优点:它避免了所谓的“切割问题(slicing problem)”(派生类对象对基类对象赋值,派生类对象的派生部分会被切割)。当一个派生类的对象作为基类对象被传递时,它(派生类对象)的作为派生类所具有的行为特性会被“切割”掉,从而变成了一个简单的基类对象。这往往不是你所想要的。例如,假设设计这么一套实现图形窗口系统的类:

    复制代码

    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();
    }

    想象当用一个windowwithscrollbars对象来调用这个函数时将发生什么:

    windowwithscrollbars wwsb;
    
    printnameanddisplay(wwsb);

    参数w将会作为一个windows对象而被创建(它是通过值来传递的,记得吗?),所有wwsb所具有的作为windowwithscrollbars对象的行为特性都被“切割”掉了。printnameanddisplay内部,w的行为就象是一个类window的对象(因为它本身就是一个window的对象),而不管当初传到函数的对象类型是什么。尤其是,printnameanddisplay内部对display的调用总是window::display,而不是windowwithscrollbars::display。

    解决切割问题的方法是通过引用来传递w:

    // 一个不受“切割问题”困扰的函数
    void printnameanddisplay(const window& w)
    {
      cout << w.name();
      w.display();
    }

    现在w的行为就和传到函数的真实类型一致了。

    以上说的其实就是多态的实现,参数是基类的指针或引用,实际运行的对象类型在运行时决定。

    #include <iostream>
    #include <string>
    using namespace std;
    
    class Person {
    public:
      Person() { //cout << "Person()" << endl; 
      }
    
      ~Person() { //cout << "~Person()" << endl; 
      }
     
    private:
      string name, address;
    };
    
    
    class Student: public Person {
    public:
      Student() { //cout << "Student()" << endl; 
      }
      ~Student() { //cout << "~Student()" << endl; 
      }
     
    private:
      string schoolName, schoolAddress;
    };
    
    
    // Expensive version with pass by value.
    Student returnStudent_by_val(Student s) { return s; }
    
    // Cheap version with pass by reference.
    const Student& returnStudent_by_ref(const Student& s) { return s; }
    
    int main(){
    
      Student plato;                      // Plato studied under Socrates
    
      //by_val
      clock_t start_by_val = clock();
      for (int i =0; i<100000000; i++) {
        returnStudent_by_val(plato);               // call returnStudent
      }
      clock_t end_by_val   = clock();
      cout << "returnStudent_by_val:	花费了" << (double)(end_by_val - start_by_val) / CLOCKS_PER_SEC << "秒" << endl;
     
      //by_ref
      clock_t start_by_ref = clock();
      for (int i =0; i<100000000; i++) {
        returnStudent_by_ref(plato);               // call returnStudent
      }
      clock_t end_by_ref   = clock();
      cout << "returnStudent_by_ref:	花费了" << (double)(end_by_ref - start_by_ref) / CLOCKS_PER_SEC << "秒" << endl;
    
    }
    


     

    returnStudent_by_val: 花费了0.080625秒
    
    returnStudent_by_ref: 花费了0.002526秒
    
    
    
    [Done] exited with code=0 in 0.552 seconds
    
    
    
    [Running] cd "/Users/didi/cppp/Effective-Cpp/Second_Edition/item22/" && g++ item22_.cpp -o item22_ && "/Users/didi/cppp/Effective-Cpp/Second_Edition/item22/"item22_
    
    returnStudent_by_val: 花费了0.068812秒
    
    returnStudent_by_ref: 花费了0.002714秒
    
    
    
    [Done] exited with code=0 in 0.492 seconds
    
    
    
    [Running] cd "/Users/didi/cppp/Effective-Cpp/Second_Edition/item22/" && g++ item22_.cpp -o item22_ && "/Users/didi/cppp/Effective-Cpp/Second_Edition/item22/"item22_
    
    returnStudent_by_val: 花费了7.10935秒
    
    returnStudent_by_ref: 花费了0.283496秒
    
    
    
    [Done] exited with code=0 in 8.017 seconds
    
    
  • 相关阅读:
    【转】eclipse修改workspace
    win7+64位+Oracle+11g+64位下使用P…
    Oracle&nbsp;11g&nbsp;R2安装手册(…
    Maven&nbsp;3&nbsp;入门&nbsp;--&nbsp;安装与配置
    JSP+JavaBean+Servlet工作原理实例…
    欢迎您在新浪博客安家
    win7中配置eclipse连接Ubuntu内的hadoop
    Visual Studio 2010 单元测试目录
    spring 面试题
    java集合类
  • 原文地址:https://www.cnblogs.com/cx2016/p/12926141.html
Copyright © 2020-2023  润新知