C++ 传递向量(左值到右值)
C++ pass vector (lvalue to rvalue)
假设您将 2 vectors
作为 lvalue references
传递给函数。后来你意识到,你可以使用递归并使用它们的 iterators
传递这些 vectors
的切片。
如果我继续编写一些 util
函数以将这些 vecotrs
用作 rvalues
,这是否是一个合适的策略?或者我应该以任何方式避免这种情况?
简化模式:
Node* util(vector<int>&& a, vector<int>&& b) {
Node* root = new Node(a[0]);
root->left = util({ a.begin(), a.end() }, { b.begin(), b.end() });
root->right = util({ a.begin(), a.end() }, { b.begin(), b.end() });
return root;
}
Node* main(vector<int>& a, vector<int>& b) {
return util({ a.begin(), a.end() }, { b.begin(), b.end() });
}
现实例子 (LeetCode 105):
TreeNode* util(vector<int>&& preorder, vector<int>&& inorder) {
if (!preorder.empty()) {
TreeNode* root = new TreeNode(preorder[0]);
auto r = find(inorder.begin(), inorder.end(), preorder[0]);
root->left = util(
{ preorder.begin() + 1, preorder.begin() + 1 + distance(inorder.begin(), r) },
{ inorder.begin(), r });
root->right = util(
{ preorder.begin() + 1 + distance(inorder.begin(), r), preorder.end() },
{ r + 1, inorder.end() });
return root;
}
return nullptr;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return util({ preorder.begin(), preorder.end() },
{ inorder.begin(), inorder.end() });
}
你走错路了:{a.begin(), a.end()}
等同于std::vector<int>(a.begin(), a.end())
,我。 e.调用构造函数接受两个迭代器,复制这两个迭代器之间的所有数据,即。 e.你的情况下的整个向量(或更实际的例子中的向量的子范围)。
但您不会以任何方式修改向量,因此不需要任何副本。
如果你只想读取原始向量,那么你可以直接使用迭代器;你可以按值传递它们,在引擎盖下,它们或多或少只是指向向量数据的指针:
TreeNode* util
(
vector<int>::const_iterator preorderBegin, vector<int>::const_iterator preorderEnd,
vector<int>::const_iterator inorderBegin, vector<int>::const_iterator inorderEnd
)
{
// ...
++preorderBegin; // if we do so before the call, we have just one addition; compiler
// might optimize to the same code, but we don't rely on it this way
util(preorderBegin, preorderBegin + distance(), inorderBegin, r);
// ...
}
const_iterator
?好吧,我们要接受 const
个向量:
TreeNode* buildTree(vector<int> const& preorder, vector<int> const& inorder)
// ^ ^
// you don't modify the vectors, so accept them as constant
{
return util(preorder.begin(), preorder.end(), inorder.begin(), inorder.end());
// note the dropped braces...
}
假设您将 2 vectors
作为 lvalue references
传递给函数。后来你意识到,你可以使用递归并使用它们的 iterators
传递这些 vectors
的切片。
如果我继续编写一些 util
函数以将这些 vecotrs
用作 rvalues
,这是否是一个合适的策略?或者我应该以任何方式避免这种情况?
简化模式:
Node* util(vector<int>&& a, vector<int>&& b) {
Node* root = new Node(a[0]);
root->left = util({ a.begin(), a.end() }, { b.begin(), b.end() });
root->right = util({ a.begin(), a.end() }, { b.begin(), b.end() });
return root;
}
Node* main(vector<int>& a, vector<int>& b) {
return util({ a.begin(), a.end() }, { b.begin(), b.end() });
}
现实例子 (LeetCode 105):
TreeNode* util(vector<int>&& preorder, vector<int>&& inorder) {
if (!preorder.empty()) {
TreeNode* root = new TreeNode(preorder[0]);
auto r = find(inorder.begin(), inorder.end(), preorder[0]);
root->left = util(
{ preorder.begin() + 1, preorder.begin() + 1 + distance(inorder.begin(), r) },
{ inorder.begin(), r });
root->right = util(
{ preorder.begin() + 1 + distance(inorder.begin(), r), preorder.end() },
{ r + 1, inorder.end() });
return root;
}
return nullptr;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return util({ preorder.begin(), preorder.end() },
{ inorder.begin(), inorder.end() });
}
你走错路了:{a.begin(), a.end()}
等同于std::vector<int>(a.begin(), a.end())
,我。 e.调用构造函数接受两个迭代器,复制这两个迭代器之间的所有数据,即。 e.你的情况下的整个向量(或更实际的例子中的向量的子范围)。
但您不会以任何方式修改向量,因此不需要任何副本。
如果你只想读取原始向量,那么你可以直接使用迭代器;你可以按值传递它们,在引擎盖下,它们或多或少只是指向向量数据的指针:
TreeNode* util
(
vector<int>::const_iterator preorderBegin, vector<int>::const_iterator preorderEnd,
vector<int>::const_iterator inorderBegin, vector<int>::const_iterator inorderEnd
)
{
// ...
++preorderBegin; // if we do so before the call, we have just one addition; compiler
// might optimize to the same code, but we don't rely on it this way
util(preorderBegin, preorderBegin + distance(), inorderBegin, r);
// ...
}
const_iterator
?好吧,我们要接受 const
个向量:
TreeNode* buildTree(vector<int> const& preorder, vector<int> const& inorder)
// ^ ^
// you don't modify the vectors, so accept them as constant
{
return util(preorder.begin(), preorder.end(), inorder.begin(), inorder.end());
// note the dropped braces...
}