我尝试过以下方法:
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++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
乘以
&&
,除非你实际上正在编写它的移动构造函数。只看价值;用户按值提供它的唯一方法是使用 std::move
。事实上,通常最好不要通过 &&
获取任何内容,除非您正在编写移动构造函数/赋值运算符(或实现转发函数)。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 无法转换为 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");
}