实现std::function克隆时出现未定义行为问题求助
问题描述
尝试实现一个仅处理int(*)(int)类型的std::function克隆版本,但遇到以下问题:
- 调用拷贝构造创建的对象的调用运算符时,sanitizer检测到未定义行为
- 存在潜在内存泄漏(分配的内存未释放)
- 调用
a3(5)时程序崩溃
相关代码:
#include <iostream> #include <functional> int foo(int x ) { return x; } int bar(int x ) { return x*x; } class A { public: A(int(*f)(int)) :callable_{+[](void *data, int x)->int{ auto & obj = *static_cast<typename std::decay<int(*)(int)>::type *>(data); return obj(x); }} { f_ = new std::decay<int(*)(int)>::type(f); } A(A const & other) { callable_ = other.callable_; f_ = new std::decay<int(*)(int)>::type(std::decay<int(*)(int)>::type(other.f_)); } A & operator = (A const & other) { callable_ = other.callable_; f_ = new std::decay<int(*)(int)>::type(std::decay<int(*)(int)>::type(other.f_)); std::cout << f_ << std::endl; return *this; } int operator()(int x) { return callable_(f_,5); } void * f_; int (*callable_)(void *data,int) = {}; }; int main() { A a1(foo); A a2(bar); A a3(a1); std::cout << a3(5) << std::endl; }
问题分析与修复
1. 拷贝构造函数的核心错误
拷贝构造里的std::decay<int(*)(int)>::type(other.f_)是非法的:
std::decay<int(*)(int)>::type本质就是int(*)(int),直接把void*类型的other.f_转成函数指针,相当于把指针地址当成函数地址使用,这会直接触发未定义行为和崩溃。- 正确做法是先将
other.f_转回原类型指针,解引用获取真正的函数指针值后再拷贝:A(A const & other) { callable_ = other.callable_; auto orig_ptr = static_cast<std::decay<int(*)(int)>::type*>(other.f_); f_ = new std::decay<int(*)(int)>::type(*orig_ptr); }
2. 赋值运算符的同类型错误与自我赋值处理
赋值运算符存在和拷贝构造相同的指针转换错误,同时需要处理自我赋值场景避免重复释放内存:
A & operator = (A const & other) { if (this == &other) return *this; // 避免自我赋值导致的内存错误 // 先释放当前对象已分配的内存 delete static_cast<std::decay<int(*)(int)>::type*>(f_); // 拷贝其他对象的内容 callable_ = other.callable_; auto orig_ptr = static_cast<std::decay<int(*)(int)>::type*>(other.f_); f_ = new std::decay<int(*)(int)>::type(*orig_ptr); return *this; }
3. 内存泄漏问题修复
类中使用new分配了内存,但未实现对应的delete操作,需要添加析构函数释放资源:
~A() { delete static_cast<std::decay<int(*)(int)>::type*>(f_); }
4. 调用运算符的参数错误
operator()里硬编码传入了5,忽略了外部传入的参数x,需要修正为:
int operator()(int x) { return callable_(f_, x); }
修复后的完整代码
#include <iostream> #include <functional> int foo(int x ) { return x; } int bar(int x ) { return x*x; } class A { public: A(int(*f)(int)) :callable_{+[](void *data, int x)->int{ auto & obj = *static_cast<typename std::decay<int(*)(int)>::type *>(data); return obj(x); }} { f_ = new std::decay<int(*)(int)>::type(f); } A(A const & other) { callable_ = other.callable_; auto orig_ptr = static_cast<std::decay<int(*)(int)>::type*>(other.f_); f_ = new std::decay<int(*)(int)>::type(*orig_ptr); } A & operator = (A const & other) { if (this == &other) return *this; delete static_cast<std::decay<int(*)(int)>::type*>(f_); callable_ = other.callable_; auto orig_ptr = static_cast<std::decay<int(*)(int)>::type*>(other.f_); f_ = new std::decay<int(*)(int)>::type(*orig_ptr); return *this; } ~A() { delete static_cast<std::decay<int(*)(int)>::type*>(f_); } int operator()(int x) { return callable_(f_, x); } void * f_; int (*callable_)(void *data,int) = {}; }; int main() { A a1(foo); A a2(bar); A a3(a1); std::cout << a3(5) << std::endl; // 输出5 std::cout << a2(5) << std::endl; // 输出25 }
内容的提问来源于stack exchange,提问作者getsoubl
相关产品推荐
相关产品推荐

