为啥 lambda init-capture 对 unique_ptr 不起作用?
Posted
技术标签:
【中文标题】为啥 lambda init-capture 对 unique_ptr 不起作用?【英文标题】:Why does lambda init-capture not work for unique_ptr?为什么 lambda init-capture 对 unique_ptr 不起作用? 【发布时间】:2015-10-30 05:15:15 【问题描述】:我正在尝试使用 C++14 初始化捕获功能通过捕获将 unique_ptr 移动到 lambda 中。出于某种原因,gcc 和 clang 都拒绝编译我的代码,坚持认为我正在尝试复制一个显然不起作用的 unique_ptr
。我认为避免复制正是 init-capture + std::move
功能的重点——事实上,传递 unique_ptr
似乎是每个人都使用的主要示例。
我做错了什么?
#include <functional>
#include <iostream>
#include <memory>
#include <string>
void runFunc(std::function<void()>&& f)
auto ff = std::move(f);
ff();
int main()
auto ptr = std::make_unique<std::string>("hello world\n");
runFunc([captured_ptr = std::move(ptr)]()
std::cout << *captured_ptr;
);
来自 gcc 的输出:
http://coliru.stacked-crooked.com/a/d91a480b2b6428ac
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
In file included from main.cpp:1:0:
/usr/local/include/c++/5.2.0/functional: In instantiation of 'static void std::_Function_base::_Base_manager<_Functor>::_M_clone(std::_Any_data&, const std::_Any_data&, std::false_type) [with _Functor = main()::<lambda()>; std::false_type = std::integral_constant<bool, false>]':
/usr/local/include/c++/5.2.0/functional:1746:16: required from 'static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = main()::<lambda()>]'
/usr/local/include/c++/5.2.0/functional:2260:19: required from 'std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = main()::<lambda()>; <template-parameter-2-2> = void; _Res = void; _ArgTypes = ]'
main.cpp:15:6: required from here
/usr/local/include/c++/5.2.0/functional:1710:34: error: use of deleted function 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)'
__dest._M_access<_Functor*>() =
^
main.cpp:13:43: note: 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed:
runFunc([captured_ptr = std::move(ptr)]()
^
main.cpp:13:43: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = std::__cxx11::basic_string<char>; _Dp = std::default_delete<std::__cxx11::basic_string<char> >]'
In file included from /usr/local/include/c++/5.2.0/memory:81:0,
from main.cpp:3:
/usr/local/include/c++/5.2.0/bits/unique_ptr.h:356:7: note: declared here
unique_ptr(const unique_ptr&) = delete;
clang 的输出:
http://coliru.stacked-crooked.com/a/4374988d875fcedc
In file included from main.cpp:1:
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/functional:1711:10: error: call to implicitly-deleted copy constructor of '(lambda at main.cpp:13:13)'
new _Functor(*__source._M_access<_Functor*>());
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/functional:1746:8: note: in instantiation of member function 'std::_Function_base::_Base_manager<(lambda at main.cpp:13:13)>::_M_clone' requested here
_M_clone(__dest, __source, _Local_storage());
^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/functional:2260:33: note: in instantiation of member function 'std::_Function_base::_Base_manager<(lambda at main.cpp:13:13)>::_M_manager' requested here
_M_manager = &_My_handler::_M_manager;
^
main.cpp:13:13: note: in instantiation of function template specialization 'std::function<void ()>::function<(lambda at main.cpp:13:13), void>' requested here
runFunc([captured_ptr = std::move(ptr)]()
^
main.cpp:13:14: note: copy constructor of '' is implicitly deleted because field '' has a deleted copy constructor
runFunc([captured_ptr = std::move(ptr)]()
^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/unique_ptr.h:356:7: note: 'unique_ptr' has been explicitly marked deleted here
unique_ptr(const unique_ptr&) = delete;
^
1 error generated.
【问题讨论】:
【参考方案1】:因为std::function
必须是可复制的:
std::function
满足 CopyConstructible 和 CopyAssignable 的要求。
还有问题中的constructor:
用
f
的副本初始化目标。
您正在构造的 lambda(完全有效)有一个 unique_ptr
成员,这使得它不可复制。如果您重写 runFunc
以按值获取任意函子:
template <typename F>
void runFunc(F f)
auto ff = std::move(f);
ff();
它会编译。
【讨论】:
很好地解释了问题,但解决方案非常有限。如果我想将“函数指针”保存在某处怎么办?除了std::function
,还有其他可以使用的类型吗?以上是关于为啥 lambda init-capture 对 unique_ptr 不起作用?的主要内容,如果未能解决你的问题,请参考以下文章
为啥要缓存对 MySQL RDS 的 AWS Lambda python 调用?
为啥不能为 Java 中的 var 关键字分配 lambda 表达式?