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/
這與操作符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