如何将unique_ptr捕获到lambda表达式中
How to capture a unique_ptr into a lambda expression?
我尝试了以下方法:
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.
}
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规范的措辞非常谨慎,以防止对命名变量的隐式移动;这就是std::move
存在的原因,这是一个好的事情。
要做你想做的事情,要么使用std::bind
(这将是半卷积的,需要binds
的短序列),要么只是返回一个常规的旧对象。
同样,永远不要用unique_ptr
代替&&
,除非你真的在写它的move构造函数。只要按值取;用户可以按值提供它的唯一方法是使用std::move
。实际上,永远不要通过&&
获取任何东西,除非您正在编写move构造函数/赋值操作符(或实现转发函数)。
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));
}
对我来说,一个次优的解决方案是将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
)。
我使用这个讨厌的东西的理由是,它是为我的测试代码,我必须在测试函数调用中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
在第一次调用期间已经被移动/丢失。
还需要知道,lambda捕获unique_ptr不能转换为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");
}
- 这 4 个 lambda 表达式之间有什么区别?
- 使用成员在类中创建 lambda 表达式
- 将 lambda 表达式传递给 std::function in C++
- 在 lambda 表达式中使用 std::atomic
- &&对lambda表达式有什么好处?
- Tbb 库:错误:编写自定义类函数而不是 lambda 表达式时,对函数的调用不匹配
- 列表.erase 中的 lambda 表达式
- 使用 lambda 表达式的 Raspbian G++ 8.3.0 导致 ']' 之前的预期主表达式 - 即使标准设置为 c++14
- 仅通过引用捕获的 lambda 表达式是否保证不会抛出?
- C++: priority_queue:模板参数中的 lambda 表达式
- 容器如何处理 lambda 表达式的参数
- 在C++ Lambda 表达式中,为什么人们更喜欢按值捕获而不是作为参数传递?
- 如何在 lambda 表达式中传递变量?
- 针对 std::function 的 lambda 表达式和模板推导:为什么会这样?
- 如何修改Lambda表达式以将输出放入文本文件
- C++如何使用lambda表达式来捕获上一次迭代的值
- 为什么Qt在信号和插槽中为lambda表达式抛出错误?
- C++:从捕获函数参数的函数返回 lambda 表达式
- C++ Lambda 表达式:通过 ref 开销捕获
- Qt 连接无法识别 lambda 表达式