You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:43:27