如何捕获一个lambdaexpression式unique_ptr?

我已经尝试了以下内容:

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 }; } 

但它不编译。 有任何想法吗?

更新:

如上所示,需要一些新的语法明确指定我们需要将所有权转移给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:

我将显示我的movecopy实现如下:

 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. } 

这个问题在C ++ 14中通过lambda广义捕获来解决:

 // 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);}); 

您不能在lambda中永久捕获unique_ptr 。 事实上,如果你想永久捕捉lambda中的任何东西,它必须是可复制的 ; 只是可移动性不足。

这可能被认为是C ++ 11中的缺陷,但是您需要一些语法来明确地说明您想将unique_ptr值移到lambda中。 C ++ 11规范的措辞非常谨慎,以防止在命名variables上进行隐式移动; 这就是为什么std::move存在,这是一件好事。

要做你想做的事,需要使用std::bind (这将是半复杂的,需要一个简短的binds序列),或者只是返回一个普通的旧对象。

另外,除非你正在编写它的移动构造函数,否则绝对不要用&&来取得unique_ptr 。 只要拿它的价值; 用户可以通过值提供的唯一方法是使用std::move 。 事实上,除非你正在编写移动构造器/赋值操作符(或者实现一个转发函数),否则通常不要用&&来取任何东西。

毕竟,Nicol Bolas提到的使用std::bind的“半复杂”解决scheme并不是那么糟糕:

 std::function<void ()> getAction(std::unique_ptr<MyClass>&& psomething) { return std::bind([] (std::unique_ptr<MyClass>& p) { p->do_some_thing(); }, std::move(psomething)); } 

为我工作的次优解决scheme是将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(); }; } 

我使用这个真正不好的解决方法,其中涉及将unique_ptr粘在shared_ptr 。 这是因为我的代码需要一个unique_ptr (由于API限制),所以我实际上不能将其转换为shared_ptr (否则我永远不能得到我的unique_ptr回来)。

我使用这种憎恶的理由是,它是我的testing代码,我不得不std::bind unique_ptr std::bind到testing函数调用。

 // 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已经被移动/丢失了。