核心思路是将所有构造函数(含默认、拷贝、移动)设为private并删除,提供public静态工厂函数(如create())返回智能指针;必须禁用全部构造路径以防绕过,且优先用std::unique_ptr管理生命周期。

把构造函数设为private,提供静态工厂函数
核心思路是让外部无法直接调用构造函数,但类内部能控制实例化时机。最常用且可靠的做法是将所有构造函数(包括默认、拷贝、移动)设为 private,再提供一个 public 的静态成员函数(如 create() 或 getInstance()),在其中使用 new 分配对象并返回指针。
注意:必须同时禁用拷贝和移动语义,否则用户可能通过拷贝构造或赋值绕过限制:
class NonStackObject {
private:
NonStackObject() = default;
NonStackObject(const NonStackObject&) = delete;
NonStackObject& operator=(const NonStackObject&) = delete;
NonStackObject(NonStackObject&&) = delete;
NonStackObject& operator=(NonStackObject&&) = delete;
public:
static std::unique_ptr<NonStackObject> create() {
return std::make_unique<NonStackObject>();
}
};
为什么不能只禁用栈上创建(比如删掉默认构造)
仅把默认构造函数设为 private 或 delete 是不够的——用户仍可通过带参构造在栈上创建,例如 NonStackObject obj(42);;更隐蔽的是,聚合初始化、结构体字面量、临时对象绑定到 const 引用等场景都可能绕过限制。
真正有效的约束必须覆盖所有构造路径,所以需要:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 所有构造函数(含隐式生成的)都不可被外部访问
- 显式删除拷贝/移动,防止通过返回值或参数传递间接构造栈对象
- 不提供任何
public的非静态构造方式(如init()成员函数)
new出来的对象怎么管理生命周期
返回裸指针(NonStackObject*)虽然简单,但容易引发内存泄漏。更安全的做法是返回智能指针:
- 用
std::unique_ptr表明所有权转移,调用方必须接管释放责任 - 若需共享所有权,可返回
std::shared_ptr,但要注意循环引用风险 - 避免返回
std::shared_ptr时在工厂函数里直接用new—— 应该用std::make_shared(但注意:它会调用 public 构造,所以此时构造函数必须是protected+ 友元类,或改用std::shared_ptr配合自定义删除器)
常见错误是写成:return std::shared_ptr<nonstackobject>(new NonStackObject());</nonstackobject> —— 这会丢失 make_shared 的内存分配优化,且异常安全不如 make_shared。
友元类或继承场景下的例外处理
如果允许某个管理类(如工厂类或池类)也能创建该对象,可以把构造函数设为 protected,并声明该类为 friend:
class ObjectPool;
class NonStackObject {
protected:
NonStackObject();
friend class ObjectPool;
};
但要注意:friend 会破坏封装性,且子类若继承 NonStackObject,就可能绕过限制(除非也禁用其构造)。因此,除非明确需要扩展点,否则优先用 private + 静态工厂的组合。
实际项目中,这类设计往往出现在资源敏感型对象(如 GPU buffer、数据库连接句柄)上,关键不是“禁止栈分配”,而是确保析构逻辑可控、资源释放不被忽略——这点比语法限制更重要。

















