使用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()
。
总结
从C++编译器底层实现来看,reference往往是以指针实现,所以对内置类型而言,pass-by-value可能比pass-by-reference效率会高些。STL的迭代器和函数对象也适用此条。内置类型都很小,于是所有小型的class都适用pass-by-value。这是个不靠谱的推论!由于某些编译器对待内置类型和用户定义类型的态度截然不同。所以对于哪怕只有一个double
成员的自定义类对象,也更应该以pass-by-reference的方式传递。