13.如何做到要求或禁止在堆中产生你自定义的对象
2013-05-22 10:39
274 查看
如果你的程序要在嵌入式系统上工作,发生在嵌入式系统上的内存泄露是非常严重的,它的堆空间是非常珍贵的。有没有可能编写出来的代码要求或禁止在堆中产生对象呢。通常是可以的。
1.要求在堆中建立对象
意思就是我们必须调用new才能创建一个对象,非堆对象在定义它的地方被自动构造,在生存时间结束时自动被释放,所以只要禁止使用隐式构造函数和析构函数,就可以实现这种限制。
最简单的方法就是将构造函数和析构函数声明为private,私有的。但是这样做副作用太大。
我们只需要将析构函数设置成私有的就可以。然后定义一个伪析构函数,让他来访问真正的析构函数。
例如下面一个类:
UPNumber n;//这里定义是合法的,但是当析构函数被隐世调用时就不合法了。
UPNumber *p=new UPNumber; //正确
delete p;//不正确,调用私有的析构函数
p->destroy();//正确,调用伪析构函数,删除对象本身。
另一种做法是将所有的构造函数都声明为private,然后用为构造函数返回创建的对象。但是这里有一个问题是,一个类经常有许多构造函数,你必须把这些构造函数都声明为private。包括拷贝构造函数,缺省构造函数等,不然编译器会自动替你生成这些函数,而编译器生成的这些函数都是public的。
虽然这样做是可以的,但是我们是需要付出代价的,我们将不能使用继承和包含。也就是说其他的类不能从这个类继承,也不能有这个类的成员。
经说过,这种方法也禁止了继承和包容(containment):
通常建立一个对象有三种情况:
a.对象被直接实例化
b.对象作为派生类的基类,在派生类实例化时被实例化。
c.对象被嵌入到其他对象中。
要想实现不允许在堆中创建对象,我们应先考虑new操作符,因为每次都是调用new来创建堆中对象。实现禁止调用new就能实现我们的功能。由于new操作符是调用operator new函数来达到目的的。所以我们可以自己将这个函数声明为private。例如:
class UPNumber {
private:
static void *operator new(size_t size);
static void operator delete(void *ptr);
...
};
现在用户仅仅可以做允许它们做的事情:
UPNumber n1; // okay
static UPNumber n2; // also okay
UPNumber *p = new UPNumber; // error! attempt to call
// private operator new
如果你也想禁止UPNumber堆对象数组,可以把operator new[]和operator delete[]也声明为private。
有趣的是,把operator new声明为private经常会阻碍UPNumber对象做为一个位于堆中的派生类对象的基类被实例化。因为operator new和operator delete是自动继承的,如果operator new和operator delete没有在派生类中被声明为public(进行改写,overwrite),它们就会继承基类中private的版本,如下所示:
1.要求在堆中建立对象
意思就是我们必须调用new才能创建一个对象,非堆对象在定义它的地方被自动构造,在生存时间结束时自动被释放,所以只要禁止使用隐式构造函数和析构函数,就可以实现这种限制。
最简单的方法就是将构造函数和析构函数声明为private,私有的。但是这样做副作用太大。
我们只需要将析构函数设置成私有的就可以。然后定义一个伪析构函数,让他来访问真正的析构函数。
例如下面一个类:
class UPNumber { public: UPNumber(); UPNumber(int initValue); UPNumber(double initValue); UPNumber(const UPNumber& rhs); // 伪析构函数 (一个const 成员函数, 因为 // 即使是const对象也能被释放。) void destroy() const { delete this; } ... private: ~UPNumber();//析构函数 };使用时:
UPNumber n;//这里定义是合法的,但是当析构函数被隐世调用时就不合法了。
UPNumber *p=new UPNumber; //正确
delete p;//不正确,调用私有的析构函数
p->destroy();//正确,调用伪析构函数,删除对象本身。
另一种做法是将所有的构造函数都声明为private,然后用为构造函数返回创建的对象。但是这里有一个问题是,一个类经常有许多构造函数,你必须把这些构造函数都声明为private。包括拷贝构造函数,缺省构造函数等,不然编译器会自动替你生成这些函数,而编译器生成的这些函数都是public的。
虽然这样做是可以的,但是我们是需要付出代价的,我们将不能使用继承和包含。也就是说其他的类不能从这个类继承,也不能有这个类的成员。
经说过,这种方法也禁止了继承和包容(containment):
class UPNumber { ... }; // 声明析构函数或构造函数 // 为private class NonNegativeUPNumber: public UPNumber { ... }; // 错误! 析构函数或 //构造函数不能编译 class Asset { private: UPNumber value; ... // 错误! 析构函数或 //构造函数不能编译 };通过把析构函数设置成protected,我们可以解决继承问题,需要包含UPNumber对象的类可以修改成包含指向UPNumber的指针:
class UPNumber { ... }; // 声明析构函数为protected class NonNegativeUPNumber: public UPNumber { ... }; // 现在正确了; 派生类 // 能够访问 // protected 成员 class Asset { public: Asset(int initValue); ~Asset(); ... private: UPNumber *value; }; Asset::Asset(int initValue) : value(new UPNumber(initValue)) // 正确 { ... } Asset::~Asset() { value->destroy(); } // 也正确2.禁止在堆中创建对象
通常建立一个对象有三种情况:
a.对象被直接实例化
b.对象作为派生类的基类,在派生类实例化时被实例化。
c.对象被嵌入到其他对象中。
要想实现不允许在堆中创建对象,我们应先考虑new操作符,因为每次都是调用new来创建堆中对象。实现禁止调用new就能实现我们的功能。由于new操作符是调用operator new函数来达到目的的。所以我们可以自己将这个函数声明为private。例如:
class UPNumber {
private:
static void *operator new(size_t size);
static void operator delete(void *ptr);
...
};
现在用户仅仅可以做允许它们做的事情:
UPNumber n1; // okay
static UPNumber n2; // also okay
UPNumber *p = new UPNumber; // error! attempt to call
// private operator new
如果你也想禁止UPNumber堆对象数组,可以把operator new[]和operator delete[]也声明为private。
有趣的是,把operator new声明为private经常会阻碍UPNumber对象做为一个位于堆中的派生类对象的基类被实例化。因为operator new和operator delete是自动继承的,如果operator new和operator delete没有在派生类中被声明为public(进行改写,overwrite),它们就会继承基类中private的版本,如下所示:
class UPNumber { ... }; // 同上 class NonNegativeUPNumber: //假设这个类 public UPNumber { //没有声明operator new ... }; NonNegativeUPNumber n1; // 正确 static NonNegativeUPNumber n2; // 也正确 NonNegativeUPNumber *p = // 错误! 试图调用 new NonNegativeUPNumber; // private operator new如果派生类声明它自己的operator new,当在堆中分配派生对象时,就会调用这个函数,于是得另找一种不同的方法来防止UPNumber基类的分配问题。UPNumber的operator new是private这一点,不会对包含UPNumber成员对象的对象的分配产生任何影响:
class Asset { public: Asset(int initValue); ... private: UPNumber value; }; Asset *pa = new Asset(100); // 正确, 调用 // Asset::operator new 或 // ::operator new, 不是 // UPNumber::operator new
相关文章推荐
- 技术(3)—要求(或禁止)对象产生于heap之中
- 要求或禁止在堆中产生对象
- More Effective C++(条款27:要求(或禁止)对象产生于heap之中)
- C++中要求(或禁止)对象产生于heap中
- 【more effective c++读书笔记】【第5章】技术(3)——要求(或禁止)对象产生于heap之中
- 要求或禁止在堆中产生对象
- 【more effective c++读书笔记】【第5章】技术(3)——要求(或禁止)对象产生于heap之中
- 条款27:要求/禁止对象产生于heap中
- 【M27】要求或者禁止对象产生于heap之中
- 自定义java.policy配置(如何让你的类禁止读写文件?禁止创建Socket对象?)
- 要求或禁止在堆中产生对象
- 要求或禁止在堆中产生对象
- 自定义java.policy配置(如何让你的类禁止读写文件?禁止创建Socket对象?)
- 自定义java.policy配置(如何让你的类禁止读写文件?禁止创建Socket对象?)
- More Effective C++ 阅读笔记(十三)--要求或禁止在堆中产生对象
- 要求或禁止在堆中产生对象
- More Effective C++----(27)要求或禁止在堆中产生对象
- 要求或禁止在堆中产生对象
- more effective C++设计模式 要求(或禁止)对象产生于heap中
- 条款二十七 要求或者禁止对象产生于heap中