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

问题描述 投票:0回答:5

我尝试过以下方法:

std::function<void ()> getAction(std::unique_ptr<MyClass> &&psomething){
    //The caller was 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 was 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.
}
c++ lambda c++11 unique-ptr
5个回答
85
投票

此问题已通过 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);});

45
投票

您无法在 lambda 中永久捕获

unique_ptr
。事实上,如果你想永久捕获 lambda 中的任何内容,它必须是“可复制”的;仅仅可移动是不够的。 这可能被认为是 C++11 中的缺陷,但您需要一些语法来明确表示您想要将

unique_ptr

值移动到 lambda 中。 C++11 规范的措辞非常谨慎,以防止对命名变量进行隐式移动;这就是

std::move
存在的原因,这是一件
的事情。 要做你想做的事,需要使用

std::bind

(这将是半复杂的,需要一个短序列

binds
)或只返回一个常规的旧对象。

另外,永远不要将

unique_ptr

乘以

&&
,除非你实际上正在编写它的移动构造函数。只看价值;用户按值提供它的唯一方法是使用
std::move
。事实上,通常最好不要通过
&&
获取任何内容,除非您正在编写移动构造函数/赋值运算符(或实现转发函数)。
    


16
投票
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
投票
unique_ptr

粘在

shared_ptr
内。 这是因为我的代码需要
unique_ptr
(由于 API 限制),所以我实际上无法将其转换为
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
在第一次调用期间已被移动/丢失。
    


2
投票
捕获 unique_ptr

的 lambda 无法转换为 std::function,因为 std::function 要求可调用对象是可复制的。

auto lambdaWithoutCapture = [](){return 1;}; //Can be std::function
auto lambdaWithCapture = [=](){return 1;}; //Can be std::function
auto lambdaWithCapture2 = [&](){return 1;}; //Can be std::function
auto lambdaWithCapture3 = [uptrProblematic = std::move(uptrProblematic)]() mutable {return 1;}; //Can't be std::function

因此,如果不需要指定函数的返回类型,则可以使用不使用 std::function 的方法。但您需要知道,这仅在本地范围内有效。您不能在头文件中声明 
auto workerFactory();

,因为这会引发编译错误。

auto workerFactory()
{
    std::unique_ptr uptrProblematic = std::make_unique<int>(9);
    int importantData = 71;
    return [=, uptrProblematic = std::move(uptrProblematic)](std::string input) mutable -> int {
        std::cout << "Problematic variable is equal to: " << *uptrProblematic << "\n";
        std::cout << "Important data is equal to: " << importantData << "\n";
        std::cout << "Input equal to: " << input << "\n";
        return 9;
    };
}

int main()
{
    auto worker = workerFactory();
    worker("Test");
}

	
© www.soinside.com 2019 - 2024. All rights reserved.