移动到你的函数中:
// foo() decalaration
void foo(std::vector<int> v);
// usage example
std::vector<int> v {0, 1, 2, 3};
foo(std::move(v));
// v is moved into foo() and invalid now
你也可以用同样的方式从函数中返回这个向量:
// foo() decalaration
std::vector<int> foo(std::vector<int> v) {
return v.push_back(4), std::move(v);
}
// usage example
std::vector<int> v {0, 1, 2, 3};
v = foo(std::move(v));
// now v is {0, 1, 2, 3, 4} and no one were deep copied
但请注意,如果您不移动它(调用foo(v) 而不是foo(std::move(v))),那么它将被深度复制。在后台,foo() 的参数 v 只是由 move-constructor 构造的。
作为参考传递:
// foo() declaration
void foo(std::vector<int>& v);
但是现在我们有一个问题:哪个引用和cv-qualifiers?嗯,一般我们有2种引用和4种cv-qualifiers,一共8个声明:
void foo(std::vector<int>&);
void foo(std::vector<int> const&);
void foo(std::vector<int> volatile&);
void foo(std::vector<int> const volatile&);
void foo(std::vector<int>&&);
void foo(std::vector<int> const&&);
void foo(std::vector<int> volatile&&);
void foo(std::vector<int> const volatile&&);
当然,其中一部分是无用的,应该删除。但尽管如此,过多的声明也被称为 完美转发问题(实际上,当出现问题时没有右值引用,因此问题小了 2 倍)。
例如,如果要修改v,则至少需要2个函数:
void foo(std::vector<int>&);
void foo(std::vector<int>&&);
在这种情况下,您将能够在左值对象上调用 foo():
std::vector<int> v;
foo(v);
以及临时:
foo(std::vector<int>{1, 2, 3, 4, 5});
但是如何编码只针对不同的引用类型和/或 cv 限定符的一种实现呢?让我介绍一下通用参考:
template<typename Vector>
void foo(Vector&& v);
Vector&&始终是引用类型,可以推导出为
-
std::vector<int>& 如果你将std::vector<int> 类型的左值传递给foo():
std::vector<int> v;
foo(v); // v is lvalue
-
std::vector<int> const& 如果你传递 std::vector<int> 类型的 const 左值:
std::vector<int> const v;
foo(v); // v is const lvalue
-
std::vector<int>&& 如果你传递右值:
foo(std::vector<int>{0, 1, 2}); // v is rvalue
等等……
但在这种情况下,您必须检查 Vector 类型的接受度。但那是另一回事了。