Effective C++ 条款20:宁以pass-by-reference-to-const替换pass-by-value
看个例子
class Person {
public:
Person();
virtual ~Person();
private:
std::string name;
std::string address;
};
class Student: public Person {
public:
Student();
~Student();
private:
std::string schoolName;
std::string schoolAddress;
};
bool validateStudent(Student s);
int main(){
Student plato;
validateStudent(plato);
}
我们定义了两个类,其中Person类有两个string成员变量。Student派生于Person,但是自己又定义了两个string成员变量。因此一共有4个成员变量。
在main函数中,我们以传值的形式将plato传给函数。这时候会发生这几件事
- 调用Student复制构造函数,析构函数
- 调用Person复制构造函数,析构函数
- 调用string复制构造函数,析构函数
一共有4个string变量,因此会调用4次string的构造函数和析构函数。那么总代价就是6次构造函数和6次析构函数,假设string是一个非常长的字符串,那么花销将是非常大的。
但是我们仅仅是想看看这个Student合法吗,不会做任何的修改。难道读个数据代价那么大吗。
用const引用代替
bool validateStudent(const Student& s);
为什么用引用
因为传引用不需要创建任何新的对象,所以没有构造函数的调用,同时也不会有析构函数的调用。
为什么用const
传值的话会生成新的变量,所以即使validateStudent修改了数据也无所谓。但是传引用可能会修改原始的数据,这不是用户希望看到的。即使这里并没有修改,但调用者没有看到const就会怀疑被修改了。
对象切割
假设现在有一个Base基类和一个Derived派生类。
class Base {
public:
virtual std::string name() const { return "Base "; }
};
class Derived : public Base {
public:
virtual std::string name() const { return "Derived "; }
};
void print_const(const Base& obj){
std::cout << obj.name() << endl;
}
void print(Base obj) {
std::cout << obj.name() << endl;
}
int main() {
Derived obj;
print_const(obj);
print(obj);
//--output--
//Derived
//Base
}
我们本意是想让其动态绑定,传入的是派生类,就调用派生类的方法。但是如果不用引用的话,派生类对象传给基类就会被切割掉。
还提一点就是,这里只需要引用就行了,const其实不是必须的,但最好加上。
什么应该用pass by value
- 内置类型(int之类)
- STL迭代器
- STL函数对象

浙公网安备 33010602011771号