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

如何将类静态方法作为std::unique_ptr的删除器并解决相关编译及类型别名问题

问题原因

你遇到的编译错误来自旧版本GCC对应的libstdc++实现限制:当std::unique_ptr的删除器类型是函数指针时,用nullptr直接构造unique_ptr会默认将删除器也初始化为空指针,触发库内的静态断言,禁止使用空函数指针作为删除器。
你代码里的静态成员初始化s_instance_{nullptr}正好触发了这个场景,哪怕后续赋值时会传入正确的删除器地址,构造阶段的断言也会先报错。

修复方案

方案1:初始化时传入删除器(最小修改)

只需要修改静态成员s_instance_的初始化语句,构造时同时传入nullptr和删除器地址即可:

// 把原来的这行
// std::unique_ptr<Singleton, decltype(&Singleton::deleter)> Singleton::s_instance_{nullptr};
// 替换为
std::unique_ptr<Singleton, decltype(&Singleton::deleter)> Singleton::s_instance_{nullptr, &Singleton::deleter};

这样构造阶段就会给删除器赋值为合法的函数地址,不会触发空指针断言。

方案2:使用空类型删除器(更优)

函数指针作为删除器会让每个unique_ptr多占用一个指针的存储空间,你可以把删除逻辑封装成一个空的仿函数类型,既不会有额外开销,也天然避免空删除器的问题:

class Singleton {
public:
    // 定义空类型删除器
    struct Deleter {
        void operator()(Singleton* p) const {
            delete p;
            std::cout << "In deleter\n" << std::endl;
        }
    };
    // 类内直接定义别名,外部可以直接用Singleton::UPtr
    using UPtr = std::unique_ptr<Singleton, Deleter>;

    static UPtr& getInstance(void);
    void hello (void) {
       std::cout << "Hello!\n" << std::endl;
    }

    Singleton(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton& operator=(Singleton&&) = delete;

private:
    static UPtr s_instance_;

    Singleton() { std::cout << "Constructed\n" << std::endl; }
    ~Singleton() { std::cout << "Destroyed\n" << std::endl; }
};

// 静态成员初始化直接用默认构造即可,不需要传删除器
Singleton::UPtr Singleton::s_instance_;

// getInstance里构造unique_ptr也不需要传删除器
Singleton::UPtr& Singleton::getInstance (void)
{
    if (s_instance_ == nullptr) {
        s_instance_ = UPtr(new Singleton());
    }
    return s_instance_;
}

别名缩短方案

你之前在类外定义别名报错,是因为此时Singleton是不完整类型,且deleter成员还未声明,编译器无法识别。
用上述方案2在类的public区域定义UPtr别名是最简洁的方式,外部所有用到该unique_ptr类型的地方都可以直接写Singleton::UPtr,不需要重复写完整的类型声明。

额外注意

你当前代码中getInstance返回unique_ptr的非const引用,外部调用reset会直接释放全局单例实例,如果这不是预期行为,建议改为返回实例的普通引用Singleton&,或者返回const引用避免外部修改内部存储的指针。

内容的提问来源于stack exchange,提问作者void

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 14:15:02