More Effective C++ 27:要求或禁止在堆中产生对象

堆中建立对象

为了执行这种限制,你必须找到一种方法禁止以调用new以外的其它手段建立对象。这很容易做到。非堆对象在定义它的地方被自动构造,在生存时间结束时自动被释放,所以只要禁止使用隐式的构造函数和析构函数,就可以实现这种限制。
把这些调用变得不合法的一种最直接的方法是把构造函数和析构函数声明为 private
这样做副作用太大。没有理由让这两个函数都是 private。最好让析构函数成为 private,让构造函数成为 public

例如,如果我们想仅仅在堆中建立代表无限精确度数字的对象,可以这样做:

class UPNumber 
{
    
public: 
	UPNumber(); 
	UPNumber(int initValue); 
	UPNumber(double initValue); 
	UPNumber(const UPNumber& rhs); 
	void destroy() const {
    delete this; }  // 伪析构函数 (一个 const 成员函数, 因为即使是 const 对象也能被释放。) 
	... 
private: 
	~UPNumber(); 
}; 

然后客户端这样进行程序设计:

UPNumber n; // 错误! (在这里合法, 但是当它的析构函数被隐式地调用时,就不合法了) 
UPNumber *p = new UPNumber; //正确 
... 
delete p; // 错误! 试图调用private 析构函数 
p->destroy(); // 正确

在这里插入图片描述
另一种方法是把全部的构造函数都声明为 private
这种方法的缺点是:一个类经常有许多构造函数,类的作者必须记住把它们都声明为 private。否则如果这些函数就会由编译器生成,构造函数包括拷贝构造函数,也包括默认构造函数;编译器生成的函数总是 public。因此仅仅声明析构函数为 private 是很简单的,因为每个类只有一个析构函数。

上面这种方法虽然可行,但是这种方法也禁止了继承和包含。

class UPNumber {
    ... }; // 声明析构函数或构造函数为 private 
class NonNegativeUPNumber: public UPNumber {
    ... }; // 错误! 析构函数或构造函数不能编译 
class Asset 
{
    
private: 
	UPNumber value; 
	... // 错误! 析构函数或 构造函数不能编译 
};

在这里插入图片描述
在这里插入图片描述
这些困难也不是不能克服,通过把 UPNumber 的析构函数声明为 protected
就可以解决继承的问题,需要包含 UPNumber 对象的类可以修改为包含指向 UPNumber 的指针:
在这里插入图片描述
在这里插入图片描述

判断一个对象是否在堆中

上述粗略的类定义表明一个非堆的 NonNegativeUPNumber 对象是合法的:

NonNegativeUPNumber n; // 正确

在这里插入图片描述
那么现在 NonNegativeUPNumber 对象 n 中的 UPNumber 部分也不在堆中,这样说对么?
所有 UPNumber对象 —即使是做为其它派生类的基类—也必须在堆中。我们如何能强制执行这种约束呢?

没有简单的办法。UPNumber 的构造函数不可能判断出它是否做为堆对象的基类而被调用。也就是说对于 UPNumber 的构造函数来说没有办法侦测到下面两种环境的区别:

NonNegativeUPNumber *n1 = new NonNegativeUPNumber; // 在堆中 
NonNegativeUPNumber n2; //不再堆中

或许你认为你能够在 new 操作符、operator newnew 操作符调
用的构造函数的相互作用中操作一波。你可能会这样修改:

class UPNumber 
{
    
public: 
	 // 如果建立一个非堆对象,抛出一个异
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值