私有构造函数可阻止栈上创建对象,必须配合删除拷贝/移动构造函数,并提供返回std::unique_ptr的公有静态工厂函数来安全创建堆对象。

为什么要把构造函数设为 private
类对象无法在栈上创建,本质是让编译器在栈分配阶段就报错。最直接的办法是封掉公有构造入口——把所有构造函数(包括默认、拷贝、移动)都设为 private,这样栈上声明 MyClass obj; 或临时对象 MyClass() 都会触发 “attempting to reference a private constructor” 错误。
但仅靠 private 不够:用户仍可通过友元或静态成员函数绕过,而我们正需要后者来提供可控的堆创建接口。
如何提供安全的堆创建接口
必须用 public 的静态工厂函数返回堆对象,常见模式是返回 std::unique_ptr:
class MyClass {
private:
MyClass() = default; // 禁止外部直接构造
MyClass(const MyClass&) = delete;
MyClass(MyClass&&) = delete;
<p>public:
static std::unique_ptr<myclass> create() {
return std::make_unique<myclass>();
}
};</myclass></myclass></p>
注意三点:
- 不返回裸指针(如
MyClass*),避免用户忘记delete或重复释放 - 不提供
new的裸调用接口(如static MyClass* create_raw()),否则等于开后门 - 若需自定义删除器或分配器,
std::make_unique不支持,得用std::unique_ptr(new MyClass, my_deleter)
析构函数要不要也设为 private
通常不需要。把析构函数设为 private 会导致 std::unique_ptr 在销毁时编译失败(它需要访问析构函数)。正确做法是保持析构函数 public,但依赖智能指针自动管理生命周期。
唯一例外是想彻底禁止用户手动 delete:可将析构函数设为 protected,并让工厂函数返回 std::unique_ptr(其删除器是友元或模板特化,能访问 protected 析构),但这种设计增加复杂度,一般没必要。
有没有更严格的限制手段
可以结合 operator new 重载 + 删除 operator delete 来进一步堵漏,但实际效果有限且易出问题:
- 重载
class作用域的operator new并设为private,能阻止new MyClass调用(但静态工厂里new仍可用) - 删除全局
operator delete会影响整个程序,绝对不可取 - 现代 C++ 中,
std::make_unique不依赖类内operator new,所以这类重载基本失效
真正可靠的防线只有两点:私有构造 + 公有静态工厂。其他手段要么绕不过去,要么破坏 ABI 或引入未定义行为。
最容易被忽略的是拷贝/移动构造函数——只要漏删其中一个,用户就能通过 MyClass obj = *MyClass::create(); 拷贝到栈上。务必显式 = delete 所有非常量左值/右值构造路径。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











