所以我有一个需要将std :: vector作为参数的函数。我想知道声明参数的最佳方法,以便底层数组不会被深度复制,因为它可能相当大。
// which should I choose?
void myFunc(std::vector<char>); // 1
void myFunc(std::vector<char>&); // 2
void myFunc(std::vector<char>&&); // 3
void myFunc(std::vector<char>*) // 4
我应该选择哪个?另外,我不会修改函数中的向量,所以不应该添加const?我应该重载该函数并将它们组合在一起吗?
答案 0 :(得分:6)
如果您打算在函数内复制它:
void myFunc(std::vector<char>);
如果您只想阅读参数而不复制它:
void myFunc(const std::vector<char>&);
如果要修改传递给函数的原始矢量:
void myFunc(std::vector<char>&);
如果您想要move函数中的优化rvalues 或:
void myFunc(std::vector<char>&&);
如果您需要能够表示通过引用传递的可选参数:
void myFunc(const std::vector<char>*);
如果你需要传递一个你想要修改的可选参数 - nullptr
:
void myFunc(std::vector<char>*);
答案 1 :(得分:2)
如果您不想要深层复制 std::vector
:
将移动到您的函数中:
// 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))
),那么它将被深度复制。在幕后,v
的参数foo()
仅由 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&&);
当然,其中一部分是无用的,应该删除。但是,太多的声明也被称为完美转发问题(实际上,当它出现问题时没有rvalue-references,因此问题小了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-qualifiers的实现?让我介绍通用引用:
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>&&
如果您传递rvalue:
foo(std::vector<int>{0, 1, 2}); // v is rvalue
等...
但在这种情况下,您必须检查Vector
类型的接受程度。但这是另一个故事。
在这种情况下,我绝对没有理由传递指针而不是引用。