1. 程式人生 > >C++優化記憶體分配

C++優化記憶體分配

C++中,在需要物件時使用new操作符,為物件分配記憶體並在分配的記憶體處初始化一個物件。

在使用new操作符時,有兩步1、給物件分配記憶體,這時記憶體是未構造的2、在分配記憶體處執行建構函式。

在一些情況下,第2步是不需要的,或者可以推遲第2步的操作,先分配記憶體,在需要時,在預先分配的記憶體中再構造物件。例如,我們構建了一個物件,但是從來不使用,在使用時,已經給物件賦予了其他值。(在給沒有物件的記憶體賦值時,其後果可能是災難性的,之前在過載=運算子時就看以看到,賦值操作符是要刪除左值的,如果沒有左值,呼叫左值物件的解構函式程式崩潰)

delete操作符也是有2步,1、呼叫解構函式2、把物件所用記憶體還給系統。

在處理C++記憶體分配時,要解決2個問題。1、分配原始記憶體時,必須在記憶體中構造物件。2、在釋放記憶體之前,必須適當地撤銷物件。

C++提供2中方法來分配和釋放未構造的原始記憶體。1、allocator類。2、operator new和operator delete。

C++也提供了不同的方法在原始記憶體中構造和撤銷物件

1、allocator類的成員函式construct在未構造的記憶體中初始化物件,成員函式destroy在物件上執行解構函式。

2、定位new表示式,它接受之前未構造的記憶體的指標,在該記憶體中初始化物件或陣列。

3、直接呼叫物件的構造、解構函式。執行解構函式並不是釋放物件所佔用記憶體,只是銷燬物件。

4、演算法uninitilalized_fill和uninitialized_copy

allocator類是一個類模板,它可以提供型別化記憶體分配和物件的構造與撤銷

allocator<T> a;//a為allocator物件,處理T型別記憶體
a.allocate(n);//分配n*sizeof(T)大小的未構造的記憶體
a.deallocate(p,n);//釋放記憶體n*sizeof(T),p為指向記憶體物件,並不執行解構函式
a.construct(p,t);//在指標p處構造物件,執行T型別的複製建構函式,用t初始化
a.destroy(p);//執行p指標處物件的解構函式

更多關於allocator的資料,參考這裡:http://www.cplusplus.com/reference/memory/allocator/

operator new函式和operator delete函式

這與操作符new和delete不同。operator new函式只是分配記憶體,operator delete只是銷燬物件。

operator new函式有2個版本

void *operator new(size_t );//分配一個物件記憶體

void *operator new[](size_t);//分配一個數組記憶體

注意,上面函式返回的是void*指標,這個有點像malloc函式,在使用前要進行指標型別轉換。

同理,operator delete函式也有2個版本

void *operator delete(void* );//釋放物件

void *operator delete[](void *);//釋放陣列

有點像allocator的deallocate函式,但是delete函式是在void*指標上操作的。注意,operator delete函式並不執行解構函式,如果需要可以顯示呼叫解構函式

定位new表示式

定位new表示式是用來在已分配的記憶體上初始化物件的,它並不分配記憶體。使用方法如下:

new (p) type;//在指標p處構造type型別物件

new (p) type(initializer list);//在指標p處用初始化列表構造物件。

可以結合《STL原始碼剖析》”2.1-設計一個簡單的空間配置器“來學習一下,使用operator new和operator delete以及定位new來實現allocator類。

#ifndef _JJALLOC_
#define _JJALLOC_
#include<new>
#include<cstddef>
#include<cstdlib>
#include<climits>
#include<iostream>

namespace JJ
{
	template<class T>
	inline T* _allocate(ptrdiff_t size, T*){//分配記憶體,但不初始化
		std::set_new_handler(0);
		T* tmp=(T*)(::operator new((size_t)(size*sizeof(T))));
		if(tmp==0){
			std::cerr<<"out of memory"<<std::endl;
			exit(1);
		}
		return tmp;
	}
	
	template<class T>
	inline void _deallocate(T* buffer){//釋放記憶體
		::operator delete(buffer);
	}
	
	template<class T1, class T2>
	inline void _construct(T1* p, const T2& value){
		new(p) T1(value);//定位new
	}
	
	template<class T>
	inline void _destroy(T* ptr){
		ptr->~T();//顯示呼叫解構函式
	}
	
	template<class T>
	class allocator{
		public:
			typedef T value_type;
			typedef T* pointer;
			typedef const T* const_pointer;
			typedef T& reference;
			typedef const T& const_reference;
			typedef size_t size_type;
			typedef ptrdiff_t difference_type;//兩個指標的差
			
			template<class U>
			struct rebind{
				typedef allocator<U> other;
			};
			
			pointer allocate(size_type n, const void* hint=0)
			{
				return _allocate((difference_type)n, (pointer)0);
			}
			
			void deallocate(pointer p, size_type n)
			{
				_deallocate(p);
			}
			
			void construct(pointer p, const T& value)
			{
				_construct(p,value);
			}
			
			void destroy(pointer p)
			{
				_destroy(p);
			}
			
			pointer address(reference x)
			{
				return (pointer)&x;
			}
			
			const_pointer const_address(const_reference x)
			{
				return (const_pointer)&x;
			}
			
			size_type max_size()const
			{
				return size_type(INT_MAX*2/sizeof(T));//使用UNIT_MAX時編譯出錯
			}
		};
}

#endif