我尝试了以下内容:
std::function<void ()> getAction(std::unique_ptr<MyClass> &&psomething){
//The caller given ownership of psomething
return [psomething](){
psomething->do_some_thing();
//psomething is expected to be released after this point
};
}
但它没有编译。有什么想法吗?
更新:
AS建议,需要一些新语法来明确指定我们需要将所有权转移到lambda,我现在考虑以下语法:
std::function<void ()> getAction(std::unique_ptr<MyClass> psomething){
//The caller given ownership of psomething
return [auto psomething=move(psomething)](){
psomething->do_some_thing();
//psomething is expected to be released after this point
};
}
这会是一个好人选吗?
更新1:
我将按以下方式显示move
和copy
的实施情况:
template<typename T>
T copy(const T &t) {
return t;
}
//process lvalue references
template<typename T>
T move(T &t) {
return std::move(t);
}
class A{/*...*/};
void test(A &&a);
int main(int, char **){
A a;
test(copy(a)); //OK, copied
test(move(a)); //OK, moved
test(A()); //OK, temporary object
test(copy(A())); //OK, copying temporary object
//You can disable this behavior by letting copy accepts T &
//test(move(A())); You should never move a temporary object
//It is not good to have a rvalue version of move.
//test(a); forbidden, you have to say weather you want to copy or move
//from a lvalue reference.
}
答案 0 :(得分:52)
C ++ 14中的lambda generalized capture解决了这个问题:
// a unique_ptr is move-only
auto u = make_unique<some_type>(some, parameters);
// move the unique_ptr into the lambda
go.run([u = move(u)]{do_something_with(u);});
答案 1 :(得分:31)
您无法永久捕获lambda中的unique_ptr
。实际上,如果你想永久捕获lambda中的任何东西,它必须是 copyable ;只是可移动是不够的。
这可能被认为是C ++ 11中的一个缺陷,但您需要一些语法来明确表示您希望将unique_ptr
值移动到lambda中。 C ++ 11规范的措辞非常谨慎,以防止对命名变量的隐式移动;这就是std::move
存在的原因,这是好的事情。
要执行您想要的操作,需要使用std::bind
(这将是半复杂的,需要短序列binds
)或只返回常规旧对象。
此外,永远不要将unique_ptr
除&&
,除非您实际上正在编写其移动构造函数。只需按价值看待它;用户可以按值提供的唯一方法是使用std::move
。实际上,除非你正在编写移动构造函数/赋值运算符(或实现转发函数),否则永远不要通过&&
取任何东西。
答案 2 :(得分:18)
Nicol Bolas提到的使用std::bind
的“半复杂”解决方案毕竟不是那么糟糕:
std::function<void ()> getAction(std::unique_ptr<MyClass>&& psomething)
{
return std::bind([] (std::unique_ptr<MyClass>& p) { p->do_some_thing(); },
std::move(psomething));
}
答案 3 :(得分:9)
对我有用的次优解决方案是将unique_ptr
转换为shared_ptr
,然后捕获lambda中的shared_ptr
。
std::function<void()> getAction(std::unique_ptr<MyClass> psomething)
{
//The caller given ownership of psomething
std::shared_ptr<MyClass> psomethingShared = std::shared_ptr<MyClass>(std::move(psomething));
return [psomethingShared]()
{
psomethingShared->do_some_thing();
};
}
答案 4 :(得分:0)
我使用了这个非常狡猾的解决方法,其中涉及将unique_ptr
粘贴在shared_ptr
内。这是因为我的代码需要unique_ptr
(由于API限制),所以我实际上无法将其转换为shared_ptr
(否则我永远无法获得{ {1}}返回)。
我使用这种憎恶的理由是它适用于我的测试代码,我必须unique_ptr
std::bind
进入测试函数调用。
unique_ptr
现在调用// Put unique_ptr inside a shared_ptr
auto sh = std::make_shared<std::unique_ptr<Type>>(std::move(unique));
std::function<void()> fnTest = std::bind([this, sh, input, output]() {
// Move unique_ptr back out of shared_ptr
auto unique = std::move(*sh.get());
// Make sure unique_ptr is still valid
assert(unique);
// Move unique_ptr over to final function while calling it
this->run_test(std::move(unique), input, output);
});
会在将fnTest()
传递给run_test()
时调用unique_ptr
。第二次调用fnTest()
将导致断言失败,因为unique_ptr
在第一次调用期间已被移动/丢失。