1.53、如何保证类的对象只能被开辟在堆上?
1. 将构造函数声明为私有或受保护,禁止外部直接在栈上或作为全局/静态对象创建实例,因为这些场景都需要调用构造函数,而私有构造函数阻止了这种调用。
2. 提供一个public
的静态工厂函数(如CreateInstance
)来返回堆上对象的指针,该函数内部使用new
操作符创建对象。
3. 将析构函数声明为protected
或私有,防止外部直接delete
对象,避免误用。
destroy
)来负责delete
自身,确保对象生命周期由类自身控制,避免内存泄漏。
这样,用户只能通过工厂函数获得堆上对象,且不能在栈上或静态区创建实例,且对象销毁也受控,类似于单例模式的管理方式。
为什么不能通过重载operator new
禁止堆上分配来保证只能堆分配?
- •
operator new
只是负责内存分配,不负责对象构造。构造函数的访问权限才是关键。 - • 如果将
operator new
重载为不可用,只能禁止堆分配,反而允许栈分配。反之,私有构造函数禁止栈分配,工厂函数配合new
实现堆分配。
因此,控制构造函数访问权限是根本,operator new
重载是辅助手段。
代码结构:
class HeapOnly {
public:
static HeapOnly* CreateInstance() {
return new HeapOnly();
}
void destroy() {
delete this;
}
protected:
~HeapOnly() {} // 保护析构函数,防止外部delete
private:
HeapOnly() {} // 私有构造函数,禁止栈上或全局创建
};
这样,HeapOnly obj;
或HeapOnly* p = new HeapOnly;
都会编译错误,唯一合法方式是HeapOnly* p = HeapOnly::CreateInstance();
。
通过p->destroy();
安全释放堆内存。
这种设计不仅保证了对象只能在堆上创建,还能控制对象生命周期,避免栈上临时对象或全局静态对象带来的管理复杂性,适合需要严格控制内存管理和生命周期的场景。
本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
(加入我的知识星球,免费获取账号,解锁所有文章。)
阅读剩余
版权声明:
作者:讳疾忌医-note
链接:https://www.1217zy.vip/archives/1369
文章版权归作者所有,未经允许请勿转载。
THE END