【Effective C++】item20: Prefer pass-by-reference-to-const to pass-by-value

使用pass-by-reference-to-const而不是pass-by-value

默认情况下,C++以传值(by-value)的方式传递对象至函数。
而C++也提供一种by-reference的方式。
那么,两者有什么去别呢?或者说,by-reference有什么好处吗?

性能问题

这些副本由对象的拷贝构造函数产出,这可能是pass-by-value费时的原因。
考虑一下代码。

class Person
{
private:
    /* data */
    string name;
    string address;

public:
    Person(/* args */)
    {
        cout << "Person ctor" << endl;
    }
    virtual ~Person() // 这里一定要有virtual
    {
        cout << "Person dtor" << endl;
    }
};

class Student : Person
{
private:
    /* data */
    string schoolName;
    string schoolAddress;

public:
    Student(/* args */)
    {
        cout << "Student ctor" << endl;
    }
    ~Student()
    {
        cout << "Student dtor" << endl;
    }
};

bool validateStudent(Student s)
{
    return true;
}

当前的validateStudent函数会执行6次拷贝构造函数和6次析构函数,
分别是Person、Student和4个string。

而通过引用的方式没有任何构造函数和析构函数被调用。

bool validateStudent(const Student& s);

现在以pass-by-reference的方式进行调用时,将它声明为const是很有必要的,因为pass-by-value的时候调用者知道传入的是一份copy,不会对原来的Student对象产生任何改变,因为不这样做的话,传入reference会引起调用者的担心。

对象切割(Slicing)问题

现有代码

class Window
{
private:
    /* data */
    string _name;
public:
    string name() const
    {
        return _name;
    }
    virtual void display() const
    {
        cout << "simple window" << endl;
    }
    Window(): _name("Window") {}
    ~Window() {}
};

class WindowWithScrollBar : public Window
{
private:
    /* data */
public:
    virtual void display() const
    {
        cout << "window with scrollbar" << endl;
    }
    WindowWithScrollBar() {}
    ~WindowWithScrollBar() {}
};

若传参方式是by-value

void printNameAndDisplay(Window w)
{
    cout << w.name() << endl;
    w.display();
}

那么将会产生对象切割问题,即使传入的是derived class对象,但是base class内的拷贝构造函数将会被调用,derived class内部的”特性“都会被切割掉。所以内部调用总是Windows::display()

总结

  1. 从C++编译器底层实现来看,reference往往是以指针实现,所以对内置类型而言,pass-by-value可能比pass-by-reference效率会高些。STL的迭代器和函数对象也适用此条。
  2. 内置类型都很小,于是所有小型的class都适用pass-by-value这是个不靠谱的推论
  3. 由于某些编译器对待内置类型和用户定义类型的态度截然不同。所以对于哪怕只有一个double成员的自定义类对象,也更应该以pass-by-reference的方式传递。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值