Effective C++ 10

10.如果写了operator new,就要同时写operator delete。

为什么要写自己的operator new和delete,首先这不叫重载,这叫隐藏。 new只是用来申请空间,而构造函数是在申请的空间的基础上继续初始化。

为了效率。缺省的operator new 进行内存分配是并不仅仅分配一块所需大小的内存,因为delete释放内存时要知道指针所指向内容的大小,所以,new时会有一个块来储存内存块的大小,而delete时,会根据这个大小来判断删除内存大小。所以当一个类本身很小的时候,这样做,既浪费时间于内存大小的判断,也浪费空间于内存大小的保存。对于某些类较小,且需要一定数量的这些小对象来储存数据时,最好能写一个operator new 来节约空间与时间。

而由于自己的Operator new申请的内存块中没有保存内存块的大小,导致使用缺省的delete时,会导致不可预测的后果。所以若写了operator new ,就必须同时写operator delete。

一般解决方法是 申请一大块内存,作为内存池,将其分为若干块,每块大小正好为储存对象的大小。当前没有被使用时。

尝试将这种固定大小内存的分配器封装起来。

//内存池的实现。
class Pool{
public:
	Pool (size_t n,int size);
	void* alloc(size_t n);//为一个对象分配足够的内存
	void free(void* p,size_t n);//将p指定的内存返回到内存池。
	~Pool();//释放内存池中的全部资源
private:
	void* block;
	const int BLOCK_SIZE;//池内存放块的数量
	void* list;
};

Pool::Pool(size_t n,int size):BLOCK_SIZE(size){
	block = ::operator new(n*size);
	int i;
	for(i = 0;i<BLOCK_SIZE -1;i++){
		*(unsigned int*)((unsigned int)block + n*i) =
		(unsigned int)block + n*(1+i);
	}
	*(unsigned int*)((unsigned int)block + n*i) = 0;
	list = block;
}

void* Pool::alloc(size_t n){
	void* p = list;
	if(p){//如果自由链表中还有元素,即还有空间
		list = (void*)*(unsigned int *)list;
		return p;
	}else{
		throw std::bad_alloc();
	}
	return p;
}

void Pool::free(void* p,size_t n){
	if(0 == p)return;
	*(unsigned int*)((unsigned int)p) = (unsigned int)list;
	list = (void*)p;
}
Pool::~Pool(){
	delete block;
}

class A{
public:
	int a;
	static void* operator new (size_t size);
	static void operator delete (void* p,size_t size);
	A(int x){a = x;}
private:
	static Pool memPool;

};
Pool A::memPool(sizeof(A),10);
inline void* A::operator new(size_t size){
	return memPool.alloc(size);
}
inline void A::operator delete(void* p,size_t size){
	memPool.free(p,size);
}
int main(){
	A* list[10];
	for(int i = 0 ; i < 10;i++){
		list[i] = new A(i);
	}
		int i = 0;
	for(int i = 0 ; i < 10;i++){
		delete list[i];
	}
	i = 1;
	for(int i = 10 ; i < 20;i++){
		list[i-10] = new A(i);
	}
	for(int i = 0 ; i < 10;i++){
		delete list[i];
	}

	system("pause");

}

这是一个内存池的实现,结果感觉虽然实现了内存池的基本功能,但写的不好看。。。譬如一些问题没有解决,如果要求内存大于池的最大容量的处理,以及释放池内元素时,如果重复释放需要进行一些判断此块内存释放已释放。

忽略上面代码,简单分析一下内存池的基本功能:alloc 为对象申请空间的请求提供内存,而free释放对象现在所在的内存。

这里说的写了 operator new 就要写对应的operator delete,因为你在自己写的new中一定会定义一些其他的操作,使的数据的组织结构不是一个简单的new就实现的,可能有多块动态地址,或者可能像内存池中并没有实际的去申请新的空间,所以一定要根据自己写的new中的操作,设计对应的delete操作。

时间: 2024-10-03 22:40:17

Effective C++ 10的相关文章

Effective Item 10 - 尽量使可变性最小化

不可变类,即实例不能被修改的类,实例中包含的所有信息在对象的生命周期内固定不变. 常见的比如String.基本类型的封装类.BigDecimal.BigInteger. 相对与可变类,不可变更易于设计.实现.使用,且更稳定(less prone to error)更安全. 比如,不可变类本质上就是线程安全的,不需要做同步处理,使用起来也非常方便. 设计不可变类,我们有5个原则: 1.不提供任何可修改对象状态的方法.(这种方法也成为mutator,相对词汇"可变性(mutability)"

More Effective C++----(10)在构造函数中防止资源泄漏

Item M10:在构造函数中防止资源泄漏 如果你正在开发一个具有多媒体功能的通讯录程序.这个通讯录除了能存储通常的文字信息如姓名.地址.电话号码外,还能存储照片和声音(可以给出他们名字的正确发音). 为了实现这个通信录,你可以这样设计: class Image { // 用于图像数据 public: Image(const string& imageDataFileName); ... }; class AudioClip { // 用于声音数据 public: AudioClip(const

Effective C++ .10,11 operator=的约定与注意

1. 返回一个reference to *this 返回一个指向自身的引用符合惯例,可以进行如(a=c).modify()类似的操作,即可以形成链式操作,否则修改的只是一个临时对象.这个和Java中常用的builder模式是一个道理 2. 自我赋值的检测和异常安全 赋值进行前进行自我检测,相同就直接返回.如果不进行检测,很容易造成资源的错误释放,导致无法复制(自己的资源被释放了). class Data { private: int* data; int len; public: Data(in

卓越管理的秘密(Behind Closed Doors)

或许提到本书甚至本书的作者Johanna Rothman我们会感到些许陌生,那么提起她的另一本获得素有软件界奥斯卡之称的Jolt生产效率大奖的名著<项目管理修炼之道>,会不会惊讶的发现,原来是她! 很久以前就买了英文版的Behind Closed Doors: Secrets of Great Management一书(中文版为<门后的秘密:卓越管理的故事>),可惜当时并没有引起足够的重视,草草翻阅后便束之高阁.开始的印象就是一本以故事叙述为主的工作场景再现,配以总结的若干管理技巧

C++异常处理 - try,catch,throw,finally的用法

写在前面 所谓异常处理,即让一个程序运行时遇到自己无法处理的错误时抛出一个异常,希望调用者可以发现处理问题. 异常处理的基本思想是简化程序的错误代码,为程序键壮性提供一个标准检测机制. 也许我们已经使用过异常,但是你习惯使用异常了吗? 现在很多软件都是n*365*24小时运行,软件的健壮性至关重要. 内容导读 本文包括2个大的异常实现概念:C++的标准异常和SHE异常. C++标准异常: 也许你很高兴看到错误之后的Heap/Stack中对象被释放,可是如果没有呢? 又或者试想一下一个能解决的错误

C++处理异常 try,catch,throw,finally

异常处理的基本思想是简化程序的错误代码,为程序键壮性提供一个标准检测机制. 也许我们已经使用过异常,但是你会是一种习惯吗,不要老是想着当我打开一个文件的时候才用异常判断一下,我知道对你来说你喜欢用return value或者是print error message来做,你想过这样做会导致Memory Leak,系统退出,代码重复/难读,垃圾一堆…..吗?现在的软件已经是n*365*24小时的运行了,软件的健壮已经是一个很要考虑的时候了.自序:对写程序来说异常真的是很重要,一个稳健的代码不是靠返回

软件项目成功之要素

      我们在不断探寻更好的软件开发方法,希望能找到适合自己和团队的好办法.不过,基于既有的教条,关于各种开发方法孰优孰劣的讨论最终总会演变成激烈的争吵.字典中教条的定义是"一种权威性观点,但并没有充分的依据".我们经常会看到,各种方法的拥护者们都坚持认为自己的方法才是开发软件唯一正确的方法.我们不断听到一些从业人员这么讲,他们执着地采用某种方式开发软件,即使这种方法明显危害到团队的其他人甚至整个组织,却仍然固执己见.事实上,开发软件根本没有所谓"绝对正确的方法"

百度粉红色风科技上来看积分

http://www.ebay.com/cln/508gua_gvqjq/-/167266747010/2015.02.10 http://www.ebay.com/cln/jhu2290/-/167423283013/2015.02.10 http://www.ebay.com/cln/cha.m22/-/167166250017/2015.02.10 http://www.ebay.com/cln/fenyu56/-/167382503016/2015.02.10 http://www.eb

百度附件是分开就爱死了开发了

http://www.ebay.com/cln/m_m3154/-/167249028014/2015.02.10 http://www.ebay.com/cln/zhsu412/-/167238372018/2015.02.10 http://www.ebay.com/cln/mi.han5/-/167545028015/2015.02.10 http://www.ebay.com/cln/lij5252/-/167389481016/2015.02.10 http://www.ebay.co