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函数对象
posted @ 2021-07-03 16:07  Destiny233  阅读(37)  评论(0)    收藏  举报