zoukankan      html  css  js  c++  java
  • Effective C++ 笔记 —— Item 20: Prefer pass-by-reference-to-const to pass-by-value.

    By default, C++ passes objects to and from functions by value (a characteristic it inherits from C).The end result is that passing an object by value leads to one call to the object's copy constructor, one call to the object's destructor.

    There is a way to bypass all those constructions and destructions: pass by reference-to-const

    bool validateStudent(const Student& s);

    Passing parameters by reference also avoids the slicing problem. When a derived class object is passed (by value) as a base class object, the base class copy constructor is called, and the specialized features that make the object behave like a derived class object are "sliced" off. You’re left with a simple base class object — little surprise, since a base class constructor created it.

    For example:

    class Window 
    {
    public:
        // ...
        std::string name() const; // return name of window
        virtual void display() const; // draw window and contents
    };
    
    class WindowWithScrollBars: public Window 
    {
    public:
        // ...
        virtual void display() const;
    };

    Now suppose you'd like to write a function to print out a window's name and then display the window. Here's the wrong way to write such a function:

    void printNameAndDisplay(Window w) // incorrect! parameter may be sliced!
    { 
        std::cout << w.name();
        w.display();
    }

    Consider what happens when you call this function with a WindowWithScrollBars object:

    WindowWithScrollBars wwsb;
    printNameAndDisplay(wwsb);

    The parameter w will be constructed as a Window object.In particular, the call to display inside printNameAndDisplay will always call Window::display, never WindowWithScrollBars::display.

    The way around the slicing problem is to pass w by reference-to-const:

    void printNameAndDisplay(const Window& w) // fine, parameter won't  be sliced
    { 
        std::cout << w.name();
        w.display();
    }

    Now w will act like whatever kind of window is actually passed in.

    If you peek under the hood of a C++ compiler, you'll find that references are typically implemented as pointers, so passing something by reference usually means really passing a pointer. As a result, if you have an object of a built-in type (e.g., an int), it's often more efficient to pass it by value than by reference. For built-in types, then, when you have a choice between pass-by-value and pass-by-reference-to-const, it's not unreasonable to choose pass-by-value. This same advice applies to iterators and function objects in the STL, because, by convention, they are designed to be passed by value. 

    Built-in types are small, so some people conclude that all small types are good candidates for pass-by-value, even if they’re user-defined. This is shaky reasoning. Just because an object is small doesn’t mean that calling its copy constructor is inexpensive. Many objects — most STL containers among them — contain little more than a pointer, but copying such objects entails copying everything they point to. That can be very expensive.

    Even when small objects have inexpensive copy constructors, there can be performance issues. Some compilers treat built-in and userdefined types differently, even if they have the same underlying representation. For example, some compilers refuse to put objects consisting of only a double into a register, even though they happily place naked doubles there on a regular basis. When that kind of thing happens, you can be better off passing such objects by reference, because compilers will certainly put pointers (the implementation of references) into registers.

    Another reason why small user-defined types are not necessarily good pass-by-value candidates is that, being user-defined, their size is subject to change. A type that’s small now may be bigger in a future release, because its internal implementation may change. Things can even change when you switch to a different C++ implementation. 

    Things to Remember:

    • Prefer pass-by-reference-to-const over pass-by-value. It’s typically more efficient and it avoids the slicing problem.
    • The rule doesn’t apply to built-in types and STL iterator and function object types. For them, pass-by-value is usually appropriate.
  • 相关阅读:
    查询死锁和处理死锁(SqlServer)
    日期函数(SqlServer)
    [Shell] echo/输出 中引用命令
    Github 团队协作基本流程与命令操作 图解git工作流程
    HTML 引入 CSS、JS 的三种方式
    JavaScript 字符串匹配 | JS 的正则用法 | 从后边匹配
    Sublime + Chrome 本地调试 CSS 选择器
    常用 CSS 选择器
    使用 Sublime 或其他编辑器调试 Tampermonkey 油猴脚本
    使用 chrome 扩展 Vimium 实现快捷键关闭其他标签页
  • 原文地址:https://www.cnblogs.com/zoneofmine/p/15238522.html
Copyright © 2011-2022 走看看