如何将unique_ptr捕获到lambda表达式中?

Ear*_*ine 38 c++ lambda unique-ptr c++11

我尝试过以下方法:

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
    };
}
Run Code Online (Sandbox Code Playgroud)

但它没有编译.有任何想法吗?

更新:

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
    };
}
Run Code Online (Sandbox Code Playgroud)

它会是一个好的候选人吗?

更新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.
}
Run Code Online (Sandbox Code Playgroud)

mat*_*ort 57

这个问题通过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);});
Run Code Online (Sandbox Code Playgroud)

  • 现在的例子应该是`go.run([u = move(u)] ...`.似乎没有`=`的构造在2013年是可以接受的,但标准的定义不同. (3认同)
  • lambda 中的“u”是“const”吗? (3认同)
  • @Vlad&gt; 你的意思是,如果你希望工厂和 lambda 都拥有 unique_ptr 的副本怎么办?这与 unique_ptr 的概念不冲突吗? (3认同)
  • 这并没有解决我的问题,因为生成的 lambda 无法构造 std::function 。 (2认同)

Nic*_*las 31

你不能永久捕获unique_ptr一个lambda.实际上,如果你想永久捕获lambda中的任何东西,它必须是可复制的 ; 只是可移动是不够的.

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

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

另外,不要采取unique_ptr&&,除非你实际上是写它的移动的构造.只需按价值看待它; 用户可以通过值提供它的唯一方法是使用std::move.实际上,&&除非你正在编写移动构造函数/赋值运算符(或实现转发函数),否则从不采取任何操作通常是一个好主意.

  • 这个答案应该根据c ++ 14草案的最新变化进行更新. (5认同)
  • "*确实,除非你正在编写移动构造函数/赋值运算符,否则永远不要用'&&`取任何东西.*"或者除非你实现完美转发...... (3认同)
  • 我同意用`&&`取'unique_ptr`并不是一个好主意.但是,一般来说,我认为用"&&"来表示"我希望调用者实际上给我一些东西的所有权,而不仅仅是为了参考". (2认同)

mar*_*n78 18

使用std::bindNicol Bolas提到的"半复杂"解决方案毕竟不是那么糟糕:

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

  • 我同意,看起来不错. (2认同)

tcb*_*tcb 9

对我有用的次优解决方案是将其转换unique_ptr为a shared_ptr然后捕获shared_ptrlambda.

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();
    };
}
Run Code Online (Sandbox Code Playgroud)