再学C++Primer(12)-C++中的高级内存管理-创新互联

C++ primer的最后一章,虽说是高级主题,但其实是一些非常有用的东西,包括内存分配,RTTI,volatile等等。

成都做网站、成都网站制作服务团队是一支充满着热情的团队,执着、敏锐、追求更好,是创新互联的标准与要求,同时竭诚为客户提供服务是我们的理念。成都创新互联把每个网站当做一个产品来开发,精雕细琢,追求一名工匠心中的细致,我们更用心!

new/delete

C++中内存方面最常用的就是new表达式和delete表达式。

string *sp = new string("fucku");

实际上发生了三件事:

1)调用名为operator new的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象;

2)运行该类型的一个构造函数,用指定初始化式构造对象;

3)返回指向新分配并构造的对象的指针;

delete sp;

实际上发生了两件事:

1)对sp指向的对象运行适当的析构函数;

2)通过调用名为operator delete的标准库函数释放该对象所占用的内存。

C++中还有一些更加“原子”的做法.

下面的两种方法来分配和释放未构造的原始内存

1)allocator类,能够针对某个类型进行内存分配,该类支持一个抽象接口,以分配内存并随后使用该内存保存对象;

2)标准库中的operator new 和 operator delete,它们分配和释放需要大小的原始的,未类型化的内存;

下面的四种方法还提供不同的方法在原始内存中构造和撤销对象

1)allocator类定义名为construct和 destroy的成员,construct成员在未构造内存中初始化对象,destroy成员在对象上运行适当的析构函数;

2)placement new 表达式,接受指向未构造内存的指针,并在该空间初始化一个对象或是一个数组;

3)可以直接调用对象的析构函数来删除对象。运行析构函数并不释放对象所占有的内存;

4)使用uninitialized_fill,uninitialized_fill_n 和uninitialized_copy,进行构造或者拷贝构造。

Vector类的部分实现

vector.h

template class Vector{ public:     Vector():elements(0),first_free(0),end(0){}     void push_back(const T&);     //... private: 	static std::allocator alloc; 	void reallocate(); 	T* elements; 	T* first_free; 	T* end; 	//... }

私有成员的三个指针说明一下:

elements,指向数组第一个元素;

first_free,指向最后一个实际元素之后的元素;

end,指向数组最后一个元素。

再学C++ Primer(12)- C++中的高级内存管理

Vector的size等于 first_free - elements;

Vector的capacity等于end - elements +1;

剩余的自由空间是 end - first_free.

还有两个函数,push_back 用于vector中push元素,reallocate用于重新分配内存。

push_back 函数的实现如下

template  void Vector::push_back(const T& t) { 	if(first_free == end) 		reallocate(); 	alloc.construct(first_free,t); 	++first_free; }

首先检查一下是否有剩余空间,如果没有空间的话调用reallocate函数重新分配内存,接下来在first_free所指向的内存块构建对象;最后将first_free指针向后移动一个单位。

高潮来了,reallocate函数!

先说明一下内存扩张策略:每次重新分配时分配两倍内存,函数首先计算当前在用的元素数目,将该数目翻倍,并请求allocator对象来获得所需数量的空间,如果Vector为空,就分配两个元素。

这样的策略平摊下来的时间复杂度是O (1).实现如下:

template  void Vector::reallocate() { 	std::ptrdiff_t size  = first_free - elemens; 	std::ptrdiff_t newcapacity = a * max(size,1); 	 	T* newelements = alloc.allocate(newcapaciy); 	 	uninitialized_copy(elements, first_free, newelements); 	for(T *p = first_free; p != elements;) 		alloc.destroy(--p); 		 	if(elements) 		alloc.deallocate(elements, end-elements); 		 	elements = newelements; 	firts_free = elements + size; 	end = elements + newcapacity; }

uninitialized_copy 使用标准copy算法的特殊版本,这个版本在原始的未构造的内存中复制构造每一个元素;

for循环对旧数组中每个对象调用allocator的destroy成员,逆序销毁元素,destroy调用T的析构函数来释放对象的资源;

一旦复制并析构了元素,就释放原来占用的空间,不过在deallocate之前,斌需检查elements的合法性;

最后,并需重置指针以指向新分配并初始化的数组。

重载new/delete

    虽然C++标准库已经为我们提供了new与delete操作符的标准实现,但是由于缺乏对具体对象的具体分析,系统默认提供的分配器在时间和空间两方面都存在着一些问题:分配器速度较慢,而且在分配小型对象时空间浪费比较严重,特别是在一些对效率或内存有较大限制的特殊应用中。比如说在嵌入式的系统中,由于内存限制,频繁地进行不定大小的内存动态分配很可能会引起严重问题,甚至出现堆破碎的风险;再比如在游戏设计中,效率绝对是一个必须要考虑的问题,而标准new与delete操作符的实现却存在着天生的效率缺陷。此时,我们可以求助于new与delete操作符的重载,它们给程序带来更灵活的内存分配控制。除了改善效率,重载new与delete还可能存在以下两点原因:

检测代码中的内存错误。
获得内存使用的统计数据。

    相对于其他的操作符,operator new具有一定的特殊性,在多个方面上与它们大不相同。首先,对于用户自定义类型,如果不重载,其他操作符是无法使用的,而operator new则不然,即使不重载,亦可用于用户自定义类型。其次,在参数方面,重载其他操作符时参数的个数必须是固定的,而operator new的参数个数却可以是任意的,只需要保证第一个参数为size_t类型,返回类型为void *类型即可。所以operator new的重载会给我们一种错觉:它更像是一个函数重载,而不是一个操作符重载。

详细请参考:effective C++ 33条

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


网站栏目:再学C++Primer(12)-C++中的高级内存管理-创新互联
网站链接:http://myzitong.com/article/icepg.html