关于这样一个函数的快速问题:
class Test {
public:
Test(vector<int>& v) {
v_ = v;
}
private:
std::vector<int> v_;
};
使用Test(vector<int>& v)
和Test(vector<int> v)
之间有什么区别?我似乎知道第一个应该更快,因为它是传递参考。但我不确定是否存在其他差异。
答案 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)
{
}