Memory (C++標準庫)

memory 是C++標準程式庫中的一個頭文件，定義了C++標準中的智能指針、內存分配器（allocator）、與垃圾回收有關的函數、臨時性的申請與釋放動態內存的函數、在內存上創建（構造）對象的函數等等。

**運算符**
 operator!= 測試allocator、智能指針是否不等- operator==測試allocator、智能指針是否相等- operator>= 測試智能指針所指向的數據對象地址- operator   測試智能指針所指向的數據對象地址-  operator
template >
class unique_ptr {
public:
typedef Type element_type; //指針基類型
typedef Del deleter_type; //析構類型
typedef T1 pointer; //指針類型 為Del::pointer，否則為Type //構造函數
unique_ptr ();                         //11 空指針
unique_ptr (nullptr_t _Nptr);  //22 空指針
explicit unique_ptr (pointer _Ptr); //33
unique_ptr (pointer _Ptr, typename conditional::value, Del,typename add_reference::type>::type _Deleter);          //44
unique_ptr (pointer _Ptr,typename remove_reference::type&& _Deleter); //55
unique_ptr (unique_ptr&& _Right); //66
template unique_ptr (unique_ptr&& _Right); //77
//析構函數
~unique_ptr ();
//
unique_ptr& operator= (unique_ptr&& _Right); //右值賦值
template unique_ptr& operator= (unique_ptr&& _Right);//右值賦值
void swap (unique_ptr& _Right);     //交換兩個unique_ptr對象的內容
pointer release ();                              //在stored_ptr中存儲pointer的新的值，並返回前一個值，用於放棄對所指數據對象的獨佔
void reset (pointer _Ptr = pointer() ); //delete當前擁有的資源並接受新的資源
pointer get () const; //返回stored_ptr
Type& operator* () const; //返回*stored_ptr
pointer operator-> () const; //返回stored_ptr
Del& get_deleter ();  //返回stored_deleter的引用
const Del& get_deleter () const; //返回stored_deleter
explicit operator bool () const; //get() != pointer() 的值
unique_ptr(const unique_ptr& _Right) = delete;
unique_ptr& operator=(const unique_ptr& _Right) = delete;
private:
pointer stored_ptr;    // exposition only
Del stored_deleter;    // exposition only
};
unique_ptr的主要用途有：
#  實現資源獲取即初始化（RAII）。當程序發生異常時，異常處理機制的棧展開（stack unwinding）會銷燬局部變量，包括unique_ptr對象，從而自動釋放資源。
# 實現右值移動語義。例如，unique_ptr類型可作為函數的返回值類型，採用了隱式地移動賦值。
# 在容器中保存unique_ptr對象。需要顯式地移動賦值，即通過std::move()。

**shared_ptr**
shared_ptr是一個類模板，包裝了使用引用計數的智能指針。當shared_ptr在退出其作用域、生命期結束時，析構函數或自動對所指內存數據對象的引用計數減去1。如果內存數據對象的引用計數為0，則會被自動delete。指向同一資源的shared_ptr共同擁有一個控制塊，其中保存了shared_ptr的引用計數、指向這一資源的weak_ptr的數目、資源的析構器（deleter ）地址、對該控制塊的可定製的allocator。
template
class shared_ptr {
public:
typedef Ty element_type;  //指針基類型
//構造函數
shared_ptr();                      //11 空指針
shared_ptr(nullptr_t);         //22 空指針
shared_ptr(const shared_ptr& sp);  //33 拷貝構造
shared_ptr(shared_ptr&& sp);         //44 右值移動構造
template explicit shared_ptr(Other * ptr); //55 由其他指針初始化，構造失敗時自動調用delete ptr
template shared_ptr(Other * ptr, D dtor); //66 由其他指針初始化，dtor是個可調用的函數對象，構造失敗時自動調用dtor(ptr)
template shared_ptr(nullptr_t, D dtor); //77 空指針，並指定deleter
template shared_ptr(Other *ptr, D dtor, A alloc);//88 alloc管理shared_ptr控制塊的內存分配與釋放，構造失敗時自動調用dtor(ptr)
template shared_ptr(nullptr_t, D dtor, A alloc);//99 空指針
template shared_ptr(const shared_ptr& sp); //0A  拷貝構造+類型轉換
template shared_ptr(const shared_ptr&& sp); //0B 移動構造+類型轉換
template  explicit shared_ptr(const weak_ptr& wp); //0C 由弱指針拷貝構造
template  shared_ptr(auto_ptr& ap); //0D 由auto_ptr指針拷貝構造
template shared_ptr(unique_ptr&& up); //0E 由unique_ptr移動構造
template shared_ptr(const shared_ptr& sp, Ty *ptr); //0F 
templateshared_ptr(const unique_ptr& up) = delete;//10 禁用const unique_ptr作為移動構造函數
~shared_ptr(); // 析構函數
shared_ptr& operator=(const shared_ptr& sp); //賦值運算符
template shared_ptr& operator=(const shared_ptr& sp); //類型轉換的賦值運算符
shared_ptr& operator=(shared_ptr&& sp); //右值引用的移動語義
template shared_ptr& operator=(shared_ptr&& sp); //右值引用+類型轉換
template shared_ptr& operator=(auto_ptr&& ap); //右值引用+auto_ptr類型轉換
template  shared_ptr& operator=(const unique_ptr& up) = delete; //禁止const型unique_ptr移動賦值給shared_ptr
template  shared_ptr& operator=(unique_ptr&& up);//右值引用的移動語義+類型轉換
void swap(shared_ptr& sp); //交換兩個指針的內容
//reset成員函數，把當前指向的數據對象的引用計數減1，然後指向參數表中新的數據對象
void reset(); 
template void reset(Other *ptr);
template void reset(Other *ptr, D dtor);
template void reset(Other *ptr, D dtor, A alloc);
Ty *get() const;                 //返回所指向的數據對象的地址
Ty& operator*() const;     //返回所指向的數據對象
Ty *operator->() const;    //返回所指向的數據對象的地址
long use_count() const;   //返回引用計數值
bool unique() const;        //判斷是否獨佔引用數據對象
operator bool() const;     //判斷是否指向了一個數據對象
template bool owner_before(shared_ptr const& ptr) const;
template bool owner_before(weak_ptr const& ptr) const;
template  D* get_deleter(shared_ptr const& ptr);
};

**weak_ptr**
弱指針weak_ptr用於指向、但不擁有（即不參加引用計數）由shared_ptr管理的資源。弱指針並不直接提供對資源的訪問。應該通過shared_ptr來訪問資源。當資源的引用計數為0（所有擁有該資源的shared_ptr對象都已被銷燬），該資源將被delete，這時如果仍然有弱指針指向該資源，則該弱指針將變為expired狀態。這實際上避免了資源的循環引用計數。對於循環的引用計數，如果把其中的一個shared_ptr的指針指向改為weak_ptr的指針指向，即打破了循環引用。
template class weak_ptr {
public:
typedef Ty element_type; //指針基類型
//構造函數
weak_ptr();                               //空指針
weak_ptr(const weak_ptr&);    //拷貝構造
template weak_ptr(const weak_ptr&); //類型轉換的拷貝構造
template weak_ptr(const shared_ptr&); //從shared_ptr拷貝構造
//賦值運算符
weak_ptr& operator=(const weak_ptr&);
template weak_ptr& operator=(const weak_ptr&);
template weak_ptr& operator=(shared_ptr&);
void swap(weak_ptr&); //交換對象的內容
void reset();                   //放棄指向資源，當前對象變為空的弱指針
long use_count() const; //返回資源的引用計數
bool expired() const;     //判斷指向的資源是否還存在（或已經被釋放）
shared_ptr lock() const; // 獲取對資源的專屬擁有
};

**auto_ptr**
auto_ptr，即自動指針，在C++11標準是過時的類模板。

**其他Helper類**

**default_delete=== 
作為使用operator new分配內存的unique_ptr對象的deleter。有兩種形式：
*為指針： template struct default_delete; 函數調用成員運算符調用delete
*為指針數組： template struct default_delete; 函數調用成員運算符模板調用delete
示例：
#include 
#include 
#include 

int main()
{
//    {
//        std::shared_ptr shared_bad(new int10);
//    } // the destructor calls delete, undefined behavior

{
std::shared_ptr shared_good(new int10, std::default_delete
());
} // the destructor calls delete, ok

{
std::unique_ptr ptr(new int(5));
} // unique_ptr uses default_delete

{
std::unique_ptr ptr(new int10);
} // unique_ptr uses default_delete

// default_delete can be used anywhere a delete functor is needed
std::vector v;
for(int n = 0; n ());
}

**allocator**
allocator是STL中非常常用的類模板，用於定製內存的分配、釋放、管理。目的是封裝STL容器在內存管理上的低層細節，所以用戶程序不應該直接調用allocator去管理內存，除非是正在定製容器。allocator將內存的分配與對象的構造初始化解耦，分別用allocate、construct兩個成員函數完成；同樣將內存的釋放與對象的析構銷燬解耦，分別用deallocat、destroy兩個成員函數完成。自定義的allocator的實現，必須滿足C++11標準的17.6.3.5節中的“Table 28 —— Allocator requirements”，簡單說就是要在類中定義若干類型名、模板成員名、成員函數、運算符函數。中定義的allocator類模板做一些使用全局malloc/free函數表達式的內存的分配、釋放的平常操作：
template class  allocator : public _Allocator_base
	{	 
public:
/*類型定義。容器類常常直接從它的allocator提取這些類型——  */
typedef _Allocator_base _Mybase;                  //基類型
	typedef typename _Mybase::value_type value_type;//值類型
	typedef value_type _FARQ *pointer;                         //指針類型
	typedef value_type _FARQ& reference;                    //引用類型
	typedef const value_type _FARQ *const_pointer;     //常量指針類型
	typedef const value_type _FARQ& const_reference;//常量引用類型
	typedef size_t size_type;                                            //size類型
	typedef ptrdiff_t difference_type;                                 //地址差值類型
/*類型操作函數：  */ 
	template
		struct rebind //用於重綁定的成員模板： convert this type to allocator。
//因為容器類需要動態申請內存的往往不是value_type，而是諸如List Node這樣的其他類型
		{	
		typedef allocator other;
		};
	pointer address(reference _Val) const
		{	// 把mutuable引用變換為地址返回
		return ((pointer) &(char&)_Val);
		}
	const_pointer address(const_reference _Val) const
		{	//把只讀引用變換為只讀地址返回
		return ((const_pointer) &(char&)_Val);
		}
/*構造函數：*/   
	allocator() throw( )
		{	 //缺省構造，不拋出異常
		}
	allocator(const allocator&) throw()
		{	// 空的拷貝構造
		}
	template
		allocator(const allocator&) throw()
		{	//從相關的allocator做拷貝構造，內容為空
		}
	template
		allocator& operator=(const allocator&)
		{	//從相關的allocator做拷貝賦值運算符，內容為空
		return (*this);
		}
/*以下為業務函數： */
	void deallocate(pointer _Ptr, size_type) //釋放內存，並不析構對象。第二個參數為元素的項數
		{	// deallocate object at _Ptr, ignore size 
		::operator delete(_Ptr);
		}
	pointer allocate(size_type _Count) //獲取內存資源，並不調用對象的構造函數
		{	// allocate array of _Count elements
		return (_Allocate(_Count, (pointer)0)); 
		 }
	pointer allocate(size_type _Count, const void _FARQ *)
		{	// allocate array of _Count elements, ignore hint 為高性能而設計的allocator可能會利用第二個參數的提示
		return (allocate(_Count));
		}
	void construct(pointer _Ptr, const _Ty& _Val) // construct object at _Ptr with value _Val 
		{	//實際上調用了“帶位置的new運算符表達式”，實現在特定位置上調用構造函數。 
		_Construct(_Ptr, _Val);
		}
	void construct(pointer _Ptr, _Ty&& _Val) //construct object at _Ptr with right-value _Val
		{	 實際上調用了“帶位置的new運算符表達式”，以及右值完美轉發，實現在特定位置上調用構造函數。
		::new ((void _FARQ *)_Ptr) _Ty(_STD forward(_Val));
		}
	template
		void construct(pointer _Ptr, _Other&& _Val) // construct object at _Ptr with value _Val， 帶類型轉換
		{	
		::new ((void _FARQ *)_Ptr) _Ty(_STD forward(_Val));
		}
	void destroy(pointer _Ptr)
		{	// 摧毀在地址 _Ptr的對象，但不釋放內存
		_Destroy(_Ptr);
		}
	_SIZT max_size() const _THROW0()
		{	// 估計allocator能分配的數據對象的最大可能數目
		_SIZT _Count = (_SIZT)(-1) / sizeof (_Ty);
		return (0 

**allocator_traits**
allocator_traits是對allocator的包裝。

**bad_weak_ptr**
bad_weak_ptr是個異常類。在用弱指針拷貝構造共享指針時，如果弱指針是expired，那麼拷貝構造函數拋出bad_weak_ptr異常。

**enable_shared_from_this**
enable_shared_from_this是一個helper類模板，用於作為數據類的基類。當數據類的對象已經被shared_ptr所擁有，如果需要從該數據類對象獲得其shared_ptr指針，就需要調用作為基類的enable_shared_from_this的成員函數shared_from_this。例如：
struct Data : public enable_shared_from_this { };
int main() {
shared_ptr a (new Data);
Data& r = *a;
shared_ptr b = r.shared_from_this();  
}
在上例中，b與a共同擁有對數據類對象的同一套引用計數，因此是正確的。如果如此構造b：
 shared_ptr b( &r);
則對同一個數據類對象，弄出了兩套引用計數。這會導致當一套引用計數變為0而銷燬數據類對象時，另外一套引用計數的shared_ptr成為“懸空”的錯誤。
Microsoft Visual C++ 2010是在enable_shared_from_this類模板中定義一個數據類型_EStype。shared_ptr的對象在調用構造函數時，最後將調用一個函數_Enable_shared(_Ty *_Ptr, _Ref_count_base *_Refptr），其中第一個參數是數據類對象的指針，第二個參數是引用計數控制塊的指針。利用模板元編程的參數推導的特性，編譯器選擇_Enable_shared，或是匹配下述模板函數
template inline void _Enable_shared(_Ty *_Ptr, _Ref_count_base *_Refptr, typename _Ty::_EStype * = 0)
或是匹配下述普通函數
inline void _Enable_shared(const volatile void *, const volatile void *) { }
前者把enable_shared_from_this類中把一個弱指針指向了shared_ptr的引用計數控制塊。從而實現了enable_shared_from_this類的語義。

**pointer_traits**
pointer_traits是一個類模板，描述指針類型所需要的一些類型的定義。
*成員類型
**pointer 指針類型
**element_type 指針的基類型
**difference_type 一般是std::ptrdiff_t
**rebind 成員類模板，指向需要綁定的其它類型
*靜態成員函數
**pointer_to 從引用類型返回其相應的指針類型，一般為std::addressof(r)

**raw_storage_iterator**
raw_storage_iterator是個類模板，用於表示指向內存的一個前向迭代器。其賦值運算符在當前所指向內存上調用值類型的構造函數，生成一個對象。

**函數**
void* align( std::size_t alignment,std::size_t size,void*& ptr,std::size_t& space );在一塊內存（ptr所指）中，按照對齊要求slignment，找到一塊長度為size的，並重置ptr為該內存起始地址，space為該內存長度。
*allocate_shared 這是shared_ptr的工廠函數，指定內存分配器allocator與數據對象的初始化參數，創建數據對象及shared_ptr。
*const_pointer_cast 用於shared_ptr對象的const的類型轉換。
*declare_no_pointers 用於垃圾回收。告知垃圾收集器在指定的內存範圍內不含可跟蹤的指針。
*declare_reachable 用於垃圾回收。令垃圾收集器知道參數指針是指向一塊聲明為可達的動態分配內存。聲明為可達的（declared reachable）完全對象，是指該對象作為形參所指，declare_reachable調用的次數超過undeclare_reachable調用次數。聲明為可達的一塊動態分配內存不能被垃圾收集器釋放，即使它看起來沒有可達的訪問方法。
*dynamic_pointer_cast  對shared_ptr對象的運行時動態轉換類型。
*get_deleter 返回shared_ptr對象的deleter。
*get_pointer_safety 用於垃圾回收。返回當前的垃圾回收器採用的指針類型。
*get_temporary_buffer 對給定類型、給定對象數目，分配一塊臨時的內存存儲。
*make_shared 這是shared_ptr的工廠函數，使用給定的數據對象的初始化參數，創建數據對象及shared_ptr。
*owner_less 混合比較shared_ptr對象與weak_ptr對象的序關係。
*pointer_safety 用於垃圾回收。是get_pointer_safety的返回值的枚舉類型。
*return_temporary_buffer 釋放由get_temporary_buffer分配的臨時性的內存塊。
*static_pointer_cast 編譯時靜態轉換shared_ptr的值類型。
*swap 交換兩個shared_ptr對象或交換兩個weak_ptr對象.
*undeclare_no_pointers 用於垃圾回收。告訴垃圾回收器，在指定範圍的內存中，存著可跟蹤指針。
*undeclare_reachable 用於垃圾回收。告訴垃圾回收器，被形參指針所指的動態分配內存塊，撤銷一次declare_reachable操作。如果動態分配內存塊上沒有declare_reachable操作，則垃圾收集器如果判斷它已經是不可達的狀態（即沒有手段訪問這塊內存）就可把它當垃圾回收。 
*uninitialized_copy 把輸入iterator所給出的一個內存範圍內的對象數組的每個元素，逐個拷貝構造到前向的目標iterator所指的內存上。 
*uninitialized_copy_n 把輸入iterator所給出的一個內存地址開始的對象數組的n個元素，逐個拷貝構造到前向的目標iterator所指的內存上。 
*uninitialized_fill 在輸入iterator所給出的一個內存範圍內，用給定的對象去拷貝構造多個對象。 
*uninitialized_fill_n 在輸入iterator所給出的一個內存開始地址處，用給定的對象去拷貝構造指定的n個對象。

**例子**

**共享指針**
#include 
#include 
class Test
{
public:
Test()
{
std::cout  p1 = std::make_shared();
std::cout  p2 = p1;
std::cout 

**弱指針例子**
#include 
#include 
class TestB;
class TestA
{
public:
TestA()
{
std::cout  test_ptr)
{
m_TestB_Ptr = test_ptr;
}
void TestWork()
{
std::cout  m_TestB_Ptr;
};
class TestB
{
public:
TestB()
{
std::cout  test_ptr)
{
m_TestA_Ptr = test_ptr;
}
void TestWork()
{
std::cout  tmp = m_TestA_Ptr.lock();
tmp->TestWork();
std::cout  m_TestA_Ptr;
};
int main()
{
std::shared_ptr ptr_a = std::make_shared();
std::shared_ptr ptr_b = std::make_shared();
ptr_a->ReferTestB(ptr_b);
ptr_b->ReferTestB(ptr_a);
std::cout 

**獨佔指針的例子**
#include 
int main()
{
std::unique_ptr pInt;
pInt.reset(new int());
int *p = pInt.release(); //釋放所有權
//由於unique_ptr有std::unique_ptr的重載函數，所以它可以用來管理數組資源
std::unique_ptr pArray(new int3{1,3,3}); 
}

**參考文獻**
 《Boost程序庫完全開發指南——深入C++“準”標準庫》第3章 內存管理 3.4 shared_ptr 作者: 羅劍鋒  電子工業出版社 2010年9月版 ISBN 9787121115776