我正在尝试避免在我的函数中输出参数。旧功能是:
void getAllBlockMeanError(
const vector<int> &vec, vector<int> &fact, vector<int> &mean, vector<int> &err)
此处vec
是输入参数,fact
,mean
和err
是输出参数。我试图将输出参数分组为一个元组:
tuple< vector<int>, vector<int>, vector<int> >
getAllBlockMeanErrorTuple(const vector<int> &vec)
{
vector<int> fact, mean, err;
//....
return make_tuple(fact, mean, err);
}
现在我可以用以下方法调用新函数:
tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec);
对我来说看起来更干净。虽然我有一个问题,tie(fact, mean, err)
的平等分配如何运作?它是做深拷贝还是移动?由于fact
中的mean
,err
和getAllBlockMeanErrorTuple
将会被销毁,我希望它会移动而不是深层复制。
答案 0 :(得分:14)
你的功能签名是tuple< vector<int>, vector<int>, vector<int> >
,这是一个临时的,元素有资格被移动,所以
std::tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec)
应移动 - 分配fact
,mean
和err
。
以下是您自己查看的示例程序(demo):
#include <iostream>
#include <vector>
#include <tuple>
struct A
{
A() = default;
~A() = default;
A(const A&)
{
std::cout << "Copy ctor\n";
}
A(A&&)
{
std::cout << "Move ctor\n";
}
A& operator=(const A&)
{
std::cout << "Copy assign\n";
return *this;
}
A& operator=(A&&)
{
std::cout << "Move assign\n";
return *this;
}
};
std::tuple<A, A> DoTheThing()
{
A first;
A second;
return std::make_tuple(first, second);
}
int main()
{
A first;
A second;
std::tie(first, second) = DoTheThing();
}
输出:
复制ctor
复制ctor
移动分配
移动分配
请注意,该函数必须创建用于返回tuple
的向量的副本,这可能不是您想要的。您可能希望std::move
元素std::make_tuple
:
return make_tuple(std::move(fact), std::move(mean), std::move(err));
Here's the same example as above, but with std::move used in make_tuple
请注意,使用C ++ 17的结构化绑定,您可以完全忘记使用std::tie
,而更多地依赖auto
(谢谢,@ Yakk):
auto[fact, mean, err] = getAllBlockMeanErrorTuple(vec);
clang(3.8.0)和gcc(6.1.0)的C ++ 17标准的早期实现尚不支持它,但似乎在clang 4.0.0中有一些支持:{{3 (谢谢,@ Revolver_Ocelot)
您会注意到带有结构化绑定的输出更改为:
移动ctor
移动ctor
表示他们利用了copy-elision,这可以节省额外的移动操作。
答案 1 :(得分:12)
std::tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec);
会做一个移动任务。
但正如评论
所述return make_tuple(fact, mean, err);
会做副本,你可以用以下方法解决:
return make_tuple(std::move(fact), std::move(mean), std::move(err));