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

如何禁用对象直接创建,仅允许通过new及智能指针实例化?

这个问题挺有意思的,确实可以实现强制堆分配、禁止栈上创建对象的需求,核心思路是利用C++的访问控制(私有/保护成员)限制栈对象的创建,同时给new和智能指针开"后门"。下面分两种常见方案来演示:

方案一:私有构造+静态工厂方法(最严谨,完全禁止直接new)

这种方式彻底把构造函数藏起来,只允许通过类提供的静态方法创建对象,同时确保智能指针能正确销毁对象:

#include <memory>

class Test {
private:
    // 把构造函数设为私有,禁止直接创建(不管栈还是堆)
    Test() = default;
    // 析构函数也设为私有,确保只有授权的代码能销毁对象
    ~Test() = default;

    // 让std::default_delete能访问私有析构,这样unique_ptr可以正常工作
    friend class std::default_delete<Test>;

public:
    // 静态工厂方法,返回unique_ptr
    static std::unique_ptr<Test> create_unique() {
        // 这里不能用std::make_unique,因为它需要访问私有构造函数
        return std::unique_ptr<Test>(new Test());
    }

    // 静态工厂方法,返回shared_ptr
    static std::shared_ptr<Test> create_shared() {
        // 用lambda作为删除器,因为lambda在类内部能访问私有析构
        return std::shared_ptr<Test>(new Test(), [](Test* ptr) {
            delete ptr;
        });
    }

    // 测试用的成员函数
    void say_hello() const {
        printf("Hello from heap-allocated Test!\n");
    }
};

效果验证:

  • 栈创建:Test t; → 编译错误(构造函数私有)
  • 直接new:Test* ptr = new Test(); → 编译错误(构造函数私有)
  • 通过工厂创建unique_ptr:auto ptr = Test::create_unique(); → 正常工作,销毁时自动调用析构
  • 通过工厂创建shared_ptr:auto ptr = Test::create_shared(); → 正常工作

方案二:公有构造+私有析构(允许直接new,但禁止栈创建)

如果你想保留直接new的能力,但禁止栈对象,这种方案更贴合你的描述:

#include <memory>

class Test {
private:
    // 析构函数设为私有,栈对象无法自动调用析构,从而禁止栈创建
    ~Test() = default;

    // 让std::default_delete访问析构,确保unique_ptr能正常销毁
    friend class std::default_delete<Test>;

public:
    // 构造函数公有,允许直接new
    Test() = default;

    // 提供静态方法手动销毁裸指针(因为直接delete会报错)
    static void destroy(Test* ptr) {
        delete ptr;
    }

    void say_hello() const {
        printf("Hello from heap-allocated Test!\n");
    }
};

效果验证:

  • 栈创建:Test t; → 编译错误(析构私有,栈对象无法自动调用)
  • 直接new:Test* ptr = new Test(); → 可以创建,但直接delete ptr;会报错(析构私有),必须用Test::destroy(ptr);
  • unique_ptr:std::unique_ptr<Test> ptr(new Test()); → 正常工作,销毁时自动调用析构
  • shared_ptr:如果直接std::shared_ptr<Test> ptr(new Test());会报错,需要用工厂方法或者自定义删除器,比如:
    auto ptr = std::shared_ptr<Test>(new Test(), [](Test* p) { Test::destroy(p); });
    

为什么这些方案能生效?
  • 栈对象的销毁是自动的,编译器会在作用域结束时插入析构调用,如果析构函数私有,编译器无法生成这段代码,从而禁止栈创建。
  • 堆对象的销毁是手动(delete)或智能指针自动触发的,通过友元声明或类内部的lambda/静态方法,我们给这些销毁路径开了访问私有析构的权限。
注意事项(你也提到不会在生产用,这里提一下)
  • 这种设计违反了C++的常规习惯,会让其他开发者困惑。
  • 智能指针的使用会受限,比如std::make_unique无法直接使用(因为需要访问构造函数)。
  • 如果类有继承关系,私有析构会导致派生类无法正常工作,除非派生类也做相应的访问控制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:25:14