51

我尝试了以下方法:

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:

我将展示我的实现,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.
}
4

5 回答 5

74

此问题已通过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);});
于 2013-06-06T17:28:59.137 回答
42

您不能unique_ptr在 lambda 中永久捕获 a。事实上,如果你想永久捕获 lambda 中的任何内容,它必须是可复制的;仅仅可移动是不够的。

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

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

此外,永远不要使用unique_ptrby &&,除非您实际上正在编写它的移动构造函数。只看价值;用户可以通过值提供它的唯一方法是使用std::move. &&实际上,除非您正在编写移动构造函数/赋值运算符(或实现转发功能),否则永远不要采取任何措施通常是一个好主意。

于 2011-11-23T03:48:26.050 回答
19

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));
}
于 2012-10-05T10:54:03.357 回答
16

对我有用的次优解决方案是将 转换unique_ptr为 ashared_ptr然后shared_ptr在 lambda 中捕获。

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();
    };
}
于 2015-01-13T16:15:45.333 回答
3

我使用了这个非常狡猾的解决方法,其中包括unique_ptrshared_ptr. 这是因为我的代码需要 a unique_ptr(由于 API 限制),所以我实际上无法将其转换为 a shared_ptr(否则我将永远无法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在第一次调用期间 已经移动/丢失。

于 2015-04-02T10:05:49.787 回答