我尝试了以下方法:
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.
}
6条答案
按热度按时间bjp0bcyl1#
这个问题由C++14中的lambda通用捕获解决:
zphenhs42#
你不能在lambda中永久捕获
unique_ptr
,事实上,如果你想在lambda中永久捕获任何东西,它必须是 copyable 的;仅仅可移动是不够的。这可能被认为是C11中的一个缺陷,但是你需要一些语法来明确地表示你想把
unique_ptr
值移到lambda中。C11规范的措辞非常谨慎,以防止对命名变量的隐式移动;这就是std::move
存在的原因,这是一件“好”事情。要完成所需的操作,需要使用
std::bind
(这将是半卷积的,需要一个binds
的短序列)或只返回一个常规的旧对象。另外,不要逐个取
unique_ptr
,除非你实际上是在写它的移动构造函数。用户可以通过值提供它的唯一方法是使用std::move
。实际上,通常最好不要使用&&
,除非您正在编写移动构造函数/赋值运算符(或实现转发函数)。kninwzqo3#
Nicol Bolas提到的使用
std::bind
的“半卷积”解决方案毕竟不是那么糟糕:eblbsuwk4#
对我来说,一个次优的解决方案是将
unique_ptr
转换为shared_ptr
,然后在lambda中捕获shared_ptr
。6ojccjat5#
我使用了一个非常狡猾的解决方法,将
unique_ptr
粘贴到shared_ptr
中,这是因为我的代码需要unique_ptr
(由于API限制),所以我无法将其转换为shared_ptr
(否则我将永远无法恢复unique_ptr
)。我之所以使用这个令人厌恶的代码,是因为它是用于测试代码的,我必须将
std::bind
和unique_ptr
插入测试函数调用。现在,调用
fnTest()
将调用run_test()
,同时将unique_ptr
传递给它。第二次调用fnTest()
将导致Assert失败,因为unique_ptr
在第一次调用期间已被移动/丢失。30byixjq6#
我们还需要知道,捕获unique_ptr的lambda不能转换为std::function,因为
std::function
要求可调用对象是可复制的。因此,如果你不需要指定函数的返回类型,你可以使用不使用std::function的方法。但是你需要知道,这只在局部作用域有效。你不能在头文件中声明
auto workerFactory();
,因为这会引起编译错误。