传递std::unique_ptr给std::bind报错,无法调用绑定后的函数
问题分析与解决
报错原因
std::unique_ptr是不可拷贝的类型。当你用std::bind(std::move(fnc), std::move(args)...)绑定unique_ptr时,指针会被移动到生成的_Bind对象中。但调用bind_f()时,std::bind默认会尝试拷贝内部存储的参数传递给目标lambda,而unique_ptr没有拷贝构造函数,直接触发编译错误。
解决办法
方法1:用Lambda替代std::bind
Lambda对移动语义的支持更直观,完全可以替代std::bind的场景,还能避免这类问题:
#include <iostream> #include <memory> #include <functional> #include <tuple> using namespace std; template <typename F, typename... Args> void TestF(F&& fnc, Args&&... args) { auto bind_f = [fnc = std::move(fnc), args = std::make_tuple(std::move(args)...)]() mutable { std::apply(std::move(fnc), std::move(args)); }; bind_f(); } int main() { std::unique_ptr<int> ptr = std::make_unique<int>(11); auto work = [](std::unique_ptr<int> val) { cout << *val << endl; }; auto work2 = [](int val, std::string str) { cout << val << endl; }; TestF(std::move(work2), 10, "ssdf"s); TestF(std::move(work), std::move(ptr)); cout << "done" << endl; }
这里用std::make_tuple存储移动后的参数,再通过std::apply转发给目标函数,完美处理unique_ptr的所有权转移。
方法2:调用bind对象时用std::move触发移动语义
std::bind返回的对象,其operator()在对象是右值时,会移动内部存储的参数而非拷贝。只需调整调用方式:
template <typename F, typename... Args> void TestF(F&& fnc, Args&&... args) { auto bind_f = std::bind(std::move(fnc), std::move(args)...); std::move(bind_f)(); // 转成右值触发移动语义 }
这样调用时,_Bind对象里的unique_ptr会被移动到目标lambda的参数中,符合所有权转移的需求。
方法3:调整目标函数的参数类型
如果不需要转移unique_ptr的所有权,可以把lambda的参数改为引用:
auto work = [](const std::unique_ptr<int>& val) { // 改为const引用 cout << *val << endl; };
此时std::bind会以左值引用的方式传递参数,不需要拷贝或移动,调用bind_f()就不会报错。
内容的提问来源于stack exchange,提问作者vansergh
相关产品推荐
相关产品推荐

