Memory (C++標準庫)

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

## 運算符

- operator!= 測試allocator、智能指針是否不等
- operator==測試allocator、智能指針是否相等
- operator>= 測試智能指針所指向的數據對象地址
- operator< 測試智能指針所指向的數據對象地址
- operator<= 測試智能指針所指向的數據對象地址
- operator> 測試智能指針所指向的數據對象地址
- operator<< 向流對象輸出智能指針所指向的數據對象地址

## 智能指針

智能指針是指當指針對象的生命期結束析構時，同時把指針所指的對象也delete或者引用計數減1。

### unique_ptr

unique_ptr是個類模板。unique_ptr指針對象獨占式地引用所指的數據對象。不能複製構造（copy ctor），也不能複製賦值，也就是對其無法進行複製，不能得到指向同一個對象的兩個unique_ptr；但是可以移動構造和移動賦值。當unique_ptr指針對象離開其作用域，生命期結束時，自動使用內部給定的刪除器（deleter）delete所指向的數據對象。unique_ptr十分依賴於右值引用和移動語義。

```cpp
template<class Type, class Del = default_delete<Type> >
    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<is_reference<Del>::value, Del,typename add_reference<const Del>::type>::type _Deleter);          //44
        unique_ptr (pointer _Ptr,typename remove_reference<Del>::type&& _Deleter); //55
        unique_ptr (unique_ptr&& _Right); //66
        template<class Type2, Class Del2> unique_ptr (unique_ptr<Type2, Del2>&& _Right); //77
//析构函数
    ~unique_ptr ();
//
    unique_ptr& operator= (unique_ptr&& _Right); //右值赋值
    template<class Type2, Class Del2> unique_ptr& operator= (unique_ptr<Type2, Del2>&& _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。

```cpp
template<class Ty>
   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<class Other> explicit shared_ptr(Other * ptr); //55 由其他指针初始化，构造失败时自动调用delete ptr
    template<class Other, class D> shared_ptr(Other * ptr, D dtor); //66 由其他指针初始化，dtor是个可调用的函数对象，构造失败时自动调用dtor(ptr)
    template<class D> shared_ptr(nullptr_t, D dtor); //77 空指针，并指定deleter
    template<class Other, class D, class A> shared_ptr(Other *ptr, D dtor, A alloc);//88 alloc管理shared_ptr控制块的内存分配与释放，构造失败时自动调用dtor(ptr)
    template<class D, class A> shared_ptr(nullptr_t, D dtor, A alloc);//99 空指针
    template<class Other> shared_ptr(const shared_ptr<Other>& sp); //0A  拷贝构造+类型转换
    template<class Other> shared_ptr(const shared_ptr<Other>&& sp); //0B 移动构造+类型转换
    template<class Other>  explicit shared_ptr(const weak_ptr<Other>& wp); //0C 由弱指针拷贝构造
    template<class Other>  shared_ptr(auto_ptr<Other>& ap); //0D 由auto_ptr指针拷贝构造
    template<class Other, class D> shared_ptr(unique_ptr<Other, D>&& up); //0E 由unique_ptr移动构造
    template<class Other> shared_ptr(const shared_ptr<Other>& sp, Ty *ptr); //0F 
    template<class Other, class D>shared_ptr(const unique_ptr<Other, D>& up) = delete;//10 禁用const unique_ptr作为移动构造函数
    ~shared_ptr(); // 析构函数
    shared_ptr& operator=(const shared_ptr& sp); //赋值运算符
    template<class Other> shared_ptr& operator=(const shared_ptr<Other>& sp); //类型转换的赋值运算符
    shared_ptr& operator=(shared_ptr&& sp); //右值引用的移动语义
    template<class Other> shared_ptr& operator=(shared_ptr<Other>&& sp); //右值引用+类型转换
    template<class Other> shared_ptr& operator=(auto_ptr< Other >&& ap); //右值引用+auto_ptr类型转换
    template <class Other, class D> shared_ptr& operator=(const unique_ptr< Other, D>& up) = delete; //禁止const型unique_ptr移动赋值给shared_ptr
    template <class Other, class D> shared_ptr& operator=(unique_ptr<Other, D>&& up);//右值引用的移动语义+类型转换
    void swap(shared_ptr& sp); //交换两个指针的内容
//reset成员函数，把当前指向的数据对象的引用计数减1，然后指向参数表中新的数据对象
    void reset(); 
    template<class Other> void reset(Other *ptr);
    template<class Other, class D> void reset(Other *ptr, D dtor);
    template<class Other, class D, class A> 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<class Other> bool owner_before(shared_ptr<Other> const& ptr) const;
    template<class Other> bool owner_before(weak_ptr<Other> const& ptr) const;
    template<class D, class Ty>  D* get_deleter(shared_ptr<Ty> const& ptr);
};
```

### weak_ptr

弱指針weak_ptr用於指向、但不擁有（即不參加引用計數）由shared_ptr管理的資源。弱指針並不直接提供對資源的訪問。應該通過shared_ptr來訪問資源。當資源的引用計數為0（所有擁有該資源的shared_ptr對象都已被銷毀），該資源將被delete，這時如果仍然有弱指針指向該資源，則該弱指針將變為expired狀態。這實際上避免了資源的循環引用計數。對於循環的引用計數，如果把其中的一個shared_ptr的指針指向改為weak_ptr的指針指向，即打破了循環引用。

```cpp
template<class Ty> class weak_ptr {
public:
    typedef Ty element_type; //指针基类型
//构造函数
    weak_ptr();                               //空指针
    weak_ptr(const weak_ptr&);    //拷贝构造
    template<class Other> weak_ptr(const weak_ptr<Other>&); //类型转换的拷贝构造
    template<class Other> weak_ptr(const shared_ptr<Other>&); //从shared_ptr拷贝构造
//赋值运算符
    weak_ptr& operator=(const weak_ptr&);
    template<class Other> weak_ptr& operator=(const weak_ptr<Other>&);
    template<class Other> weak_ptr& operator=(shared_ptr<Other>&);

    void swap(weak_ptr&); //交换对象的内容
    void reset();                   //放弃指向资源，当前对象变为空的弱指针

    long use_count() const; //返回资源的引用计数
    bool expired() const;     //判断指向的资源是否还存在（或已经被释放）
    shared_ptr<Ty> 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

示例：

```cpp
#include <memory>
#include <vector>
#include <algorithm>
 
int main()
{
//    {
//        std::shared_ptr<int> shared_bad(new int[10]);
//    } // the destructor calls delete, undefined behavior
 
    {
        std::shared_ptr<int> shared_good(new int[10], std::default_delete<int[]>
());
    } // the destructor calls delete[], ok
 
    {
        std::unique_ptr<int> ptr(new int(5));
    } // unique_ptr<int> uses default_delete<int>
 
    {
        std::unique_ptr<int[]> ptr(new int[10]);
    } // unique_ptr<int[]> uses default_delete<int[]>
 
   // default_delete can be used anywhere a delete functor is needed
   std::vector<int*> v;
   for(int n = 0; n < 100; ++n)
      v.push_back(new int(n));
   std::for_each(v.begin(), v.end(), std::default_delete<int>());
}
```

### allocator

allocator是STL中非常常用的類模板，用於定製記憶體的分配、釋放、管理。目的是封裝STL容器在記憶體管理上的低層細節，所以使用者程序不應該直接調用allocator去管理記憶體，除非是正在定製容器。allocator將記憶體的分配與對象的構造初始化解耦，分別用allocate、construct兩個成員函數完成；同樣將記憶體的釋放與對象的析構銷毀解耦，分別用deallocat、destroy兩個成員函數完成。自定義的allocator的實現，必須滿足C++11標準的17.6.3.5節中的「Table 28 —— Allocator requirements」，簡單說就是要在類中定義若干類型名、模板成員名、成員函數、運算符函數。`<memory>`中定義的allocator類模板做一些使用全局malloc/free函數表達式的記憶體的分配、釋放的平常操作：

```cpp
template<class _Ty> class  allocator : public _Allocator_base<_Ty>
	{	 
public:
/*类型定义。容器类常常直接从它的allocator提取这些类型——  */
typedef _Allocator_base<_Ty> _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<class _Other>
		struct rebind //用于'''重绑定'''的成员模板： convert this type to allocator<_Other>。
                     //因为容器类需要动态申请内存的往往不是value_type，而是诸如List Node这样的其他类型
		{	
		typedef allocator<_Other> 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<_Ty>&) throw()
		{	// 空的拷贝构造
		}

	template<class _Other>
		allocator(const allocator<_Other>&) throw()
		{	//从相关的allocator做拷贝构造，内容为空
		}

	template<class _Other>
		allocator<_Ty>& operator=(const allocator<_Other>&)
		{	//从相关的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<_Ty>(_Val));
		}

	template<class _Other>
		void construct(pointer _Ptr, _Other&& _Val) // construct object at _Ptr with value _Val， 带类型转换
		{	
		::new ((void _FARQ *)_Ptr) _Ty(_STD forward<_Other>(_Val));
		}

	void destroy(pointer _Ptr)
		{	// 摧毁在地址 _Ptr的对象，但不释放内存
		_Destroy(_Ptr);
		}

	_SIZT max_size() const _THROW0()
		{	// 估计allocator能分配的数据对象的最大可能数目
		_SIZT _Count = (_SIZT)(-1) / sizeof (_Ty);
		return (0 < _Count ? _Count : 1);
		}
};
```

### 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`。例如：

```cpp
struct Data : public enable_shared_from_this<Data> { };

int main() {
    shared_ptr<Data> a (new Data);
    Data& r = *a;
    shared_ptr<Data> b = r.shared_from_this();  
}
```

在上例中，b與a共同擁有對數據類對象的同一套引用計數，因此是正確的。如果如此構造b：

`shared_ptr<Data> 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<class _Ty> 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個對象。

## 例子

### 共享指針

```cpp
#include <memory>
#include <iostream>
class Test
{
public:
    Test()
    {
        std::cout << "Test()" << std::endl;
    }
    ~Test()
    {
        std::cout << "~Test()" << std::endl;
    }
};
int main()
{
    std::shared_ptr<Test> p1 = std::make_shared<Test>();
    std::cout << "1 ref:" << p1.use_count() << std::endl;
    {
        std::shared_ptr<Test> p2 = p1;
        std::cout << "2 ref:" << p1.use_count() << std::endl;
    }
    std::cout << "3 ref:" << p1.use_count() << std::endl;
    return 0;
}
```

### 弱指針例子

```cpp
#include <iostream>
#include <memory>
class TestB;
class TestA
{
public:
    TestA()
    {
        std::cout << "TestA()" << std::endl;
    }
    void ReferTestB(std::shared_ptr<TestB> test_ptr)
    {
        m_TestB_Ptr = test_ptr;
    }
    void TestWork()
    {
        std::cout << "~TestA::TestWork()" << std::endl;
    }
    ~TestA()
    {
        std::cout << "~TestA()" << std::endl;
    }
private:
    std::weak_ptr<TestB> m_TestB_Ptr;
};
class TestB
{
public:
    TestB()
    {
        std::cout << "TestB()" << std::endl;
    }
    void ReferTestB(std::shared_ptr<TestA> test_ptr)
    {
        m_TestA_Ptr = test_ptr;
    }
    void TestWork()
    {
        std::cout << "~TestB::TestWork()" << std::endl;
    }
    ~TestB()
    {
  ////把std::weak_ptr类型转换成std::shared_ptr类型
        std::shared_ptr<TestA> tmp = m_TestA_Ptr.lock();
        tmp->TestWork();
        std::cout << "2 ref a:" << tmp.use_count() << std::endl;
        std::cout << "~TestB()" << std::endl;
    }
    std::weak_ptr<TestA> m_TestA_Ptr;
};
int main()
{
    std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
    std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
    ptr_a->ReferTestB(ptr_b);
    ptr_b->ReferTestB(ptr_a);
    std::cout << "1 ref a:" << ptr_a.use_count() << std::endl;
    std::cout << "1 ref b:" << ptr_a.use_count() << std::endl;
    return 0;
}
```

### 獨占指針的例子

```cpp
#include <iostream>
int main()
{
 std::unique_ptr<int> pInt;
 pInt.reset(new int());
 int *p = pInt.release(); //释放所有权
 //由于unique_ptr有std::unique_ptr<T[]>的重载函数，所以它可以用来管理数组资源
 std::unique_ptr<int[]> pArray(new int[3]{1,3,3}); 
}
```