按值或按引用传递构造函数参数

时间:2011-11-18 00:11:52

标签: c++ pass-by-reference

关于这样一个函数的快速问题:

class Test {
  public:
    Test(vector<int>& v) {
      v_ = v;
    }
  private:
    std::vector<int> v_;
};

使用Test(vector<int>& v)Test(vector<int> v)之间有什么区别?我似乎知道第一个应该更快,因为它是传递参考。但我不确定是否存在其他差异。

2 个答案:

答案 0 :(得分:2)

区别在于Test(vector<int>& v)(BTW是左值参考)v是指原始对象,而Test(vector<int> v)则是副本。以下示例代码演示了与int和普通函数的区别(请注意,对于int,pass-by-value实际上更快!):

#include <iostream>

int global_i;

void pass_by_value(int i)
{
  std::cout << "pass by value:\n";
  std::cout << "initially: i = " << i << ", global_i = " << global_i << "\n";
  i++;
  std::cout << "after i++: i = " << i << ", global_i = " << global_i << "\n";
  global_i++;
  std::cout << "after global_i++: i = " << i << ", global_i = " << global_i << "\n";
}

void pass_by_reference(int& i)
{
  std::cout << "pass by reference:\n";
  std::cout << "initially: i = " << i << ", global_i = " << global_i << "\n";
  i++;
  std::cout << "after i++: i = " << i << ", global_i = " << global_i << "\n";
  global_i++;
  std::cout << "after global_i++: i = " << i << ", global_i = " << global_i << "\n";
}

void pass_by_const_reference(int const& i)
{
  std::cout << "pass by const reference:\n";
  std::cout << "initially: i = " << i << ", global_i = " << global_i << "\n";
  // i++; not allowed!
  // std::cout << "after i++: i = " << i << ", global_i = " << global_i << "\n";
  global_i++;
  std::cout << "after global_i++: i = " << i << ", global_i = " << global_i << "\n";
}

int main()
{
  global_i = 1;
  pass_by_value(global_i);

  global_i = 1;
  pass_by_reference(global_i);

  global_i = 1;
  pass_by_const_reference(global_i);
}

这个输出是:

pass by value:
initially: i = 1, global_i = 1
after i++: i = 2, global_i = 1
after global_i++: i = 2, global_i = 2
pass by reference:
initially: i = 1, global_i = 1
after i++: i = 2, global_i = 2
after global_i++: i = 3, global_i = 3
pass by const reference:
initially: i = 1, global_i = 1
after global_i++: i = 2, global_i = 2

如您所见,通过按值调用,参数和传递的变量是完全分开的。递增参数不会更改传递的变量,并且递增传递的变量不会更改参数。另一方面,通过引用传递,参数只允许访问传递的变量:无论你增加哪一个都无关紧要,因为它们是相同的。通过const引用传递,它们也是相同的,但是你不允许使用这个参数(尽管有这种方法)。但是,该参数仍然反映了对传递的变量的任何更改。

这些是功能上的差异。但是有一些差异:对于传递值和传递const引用,您可以使用右值,如call_by_value(2)call_by_const_reference(2)。对于按值调用,很明显会发生什么:参数得到值2,就是这样。但是对于const引用,有一个期望的对象(例如,你可以在函数中获取该对象的地址)。因此,在这种情况下,创建临时对象。对于非const引用的调用,您不能传递右值。

C ++ 11在混合中添加了另一种类型,即右值引用。这些用&&而不是&表示。在函数内部,它们的行为与普通(左值)引用完全相同,但它们的区别在于它们可以绑定到右值,即使它们不是常量。此外,如果您将它们用作返回类型,则调用表达式将为rvalue类型,就像您返回了一个值一样。特别是,您将无法传递函数的结果,该函数将rvalue引用返回到期望左值引用的函数,就像您无法使用文字2那样。

答案 1 :(得分:0)

您的代码中没有右值引用,只需进行大量不必要的复制。

但是,既然我们已经讨论过这个主题,那么现在就用移动语义来写这个是正确的方法:

Test(std::vector<int> v)  // by value!
:  v_(std::move(v))
{
}

在11世纪之前的世界中,下一个最好的方法是通过const-reference获取参数并复制它:

Test(std::vector<int> const & v)
:  v_(v)
{
}