为何std::function在此处尝试调用已删除的拷贝构造函数?
为何std::function在此处尝试调用拷贝构造函数?
#include <functional> struct MyFoo { MyFoo() {} MyFoo(const MyFoo&) = delete; MyFoo(MyFoo&&) = default; MyFoo& operator=(const MyFoo&) = delete; MyFoo& operator=(MyFoo&&) = default; void operator()(int) { } }; int main(void) { std::function<void(int)> foo{MyFoo()}; }
错误信息:Error C2280 'MyFoo::MyFoo(const MyFoo &)': attempting to reference a deleted function
问题分析
你提到MyFoo是右值,按道理std::function应该移动而非拷贝它,但实际触发拷贝构造函数调用的核心原因是:C11至C17标准中,std::function的构造逻辑要求传入的可调用对象必须支持拷贝构造。
早期标准的std::function内部是通过存储对象拷贝的方式实现的,即便传入的是右值,其底层实现依然会尝试调用拷贝构造函数完成内部存储的初始化,这就导致被删除的拷贝构造函数被引用,触发编译错误。
解决方法
这个问题在C++20标准中已经被修复:std::function新增了支持仅可移动类型的构造重载,会通过std::move语义转移对象所有权。你可以通过两种方式解决:
- 升级编译器到支持C++20的版本,原代码无需修改即可正常编译,
std::function会自动移动MyFoo对象。 - 若无法升级标准,可以用
std::unique_ptr或std::shared_ptr包装MyFoo,间接绕开拷贝要求:
#include <functional> #include <memory> struct MyFoo { MyFoo() {} MyFoo(const MyFoo&) = delete; MyFoo(MyFoo&&) = default; MyFoo& operator=(const MyFoo&) = delete; MyFoo& operator=(MyFoo&&) = default; void operator()(int) { } }; int main(void) { std::function<void(int)> foo{[ptr = std::make_unique<MyFoo>()](int x) { (*ptr)(x); }}; }
这里std::function存储的是可拷贝的lambda,lambda通过智能指针持有仅可移动的MyFoo对象,间接完成函数调用,规避了拷贝构造的限制。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

