1. 程式人生 > >C++Primer_Chap12_動態記憶體_筆記

C++Primer_Chap12_動態記憶體_筆記

靜態記憶體:儲存區域性static物件、類static資料成員以及定義在任何函式之外的變數。

棧記憶體:   儲存定義在函式內的非static物件

動態記憶體(堆):   儲存動態分配的物件

動態記憶體和智慧指標

    為了更安全的使用動態記憶體,,新的標準庫提供了兩種智慧指標(smart pointer,定義在memory標頭檔案中),與常規指標的區別在於負責自動釋放所指向的物件。兩種智慧指標的區別在於管理底層指標的方式:

  • shared_ptr允許多個指標指向同一個物件
  • unique_ptr"獨佔"所指向的物件
  • weak_ptr:伴隨類,一種弱引用,指向share_ptr所管理的物件。
#include <memory>
shared_ptr和unique_ptr都支援的操作

shared_ptr<T> sp

unique_ptr<T> up

空智慧指標,可以指向型別為T的物件
p 將p作為一個條件判斷,若p指向一個物件,則為true
*p 解引用p,或得它指向的物件
p->mem 等價(*p).mem
p.get() 返回p中儲存的指標。要小心使用,若智慧指標釋放了其物件,返回的指標所指向的物件也就消失了

swap( p, q)

p.swap(q)

互動p和q中的指標

share_ptr類

share_ptr獨有的操作
make_shared<T>(args) 返回一個shared_ptr,指向一個動態分配的型別為T的物件,使args初始化物件
shared_ptr<T>p(q) p是shared_ptr q的拷貝;此操作會遞增q中的計數器。q中的指標必須能轉換成*T
p = q p和q都是shared_ptr,所儲存的指標必須能相互轉換。此操作會遞減p的引用計數,遞增q的引用計數;若p的引用計數變為0,則將其管理的原記憶體釋放
p.unique() 若p.use_count()為1,返回true。否則返回false
p.use_count() 返回與p共享物件的只能指標數量:可能很慢。主要用於除錯

  每個shared_ptr都有一個關聯的計數器,通常稱為引用計數(reference count)

  • 當拷貝一個shared_ptr時,計數器會遞增。如:用一個shared_ptr初始化另一個shared_ptr,將它作為引數傳遞給一個函式以及作為函式的返回值
  • 當給share_ptr賦予一個新值或是shared_ptr被銷燬(比如一個區域性的shared_ptr離開其作用域),計數器會遞減
class StrBlob
{
	public:
		typedef std::vector<std::string>::size_type size_type;
		StrBlob();
		StrBlob( std::initializer_list<std::string> i1);
		size_type size() const { return data->size();};
		bool empty() const { return data->empty(); };
		//add element
		void push_back( const std::string &t) { data.push_back(t)};
		void pop_back();
		//visit element
		std::string& front();
		const std::string& front() const;
		std::string& back();
		const std::string& back() const;
	private:
		std::shared_ptr<std::vector<std::string>> data;
		//if data[i] illegal ,return out_of_range
		void check( size_type i, const std::string &msg) const;
};

StrBlob::StrBlob(): data(make_shared<vector<std::string>>()) {}
StrBlob::StrBlob( std::initializer_list<std::string> i1):
			data(make_shared<vector<std::string>>(i1)) { }
定義和改變shared_ptr的其他方法
shared_ptr<T> p(q) p管理內建指標q所指向的物件;q必須指向new分配的記憶體,且能轉換為T*型別
shared_ptr<T> p(u) p從unique_ptr u那裡接管了物件的所有權;將u置位空
shared_ptr<T> p(q,d) p接管了內建指標q所指向的物件的所有權。q必須能轉換為T*型別。p將使用可呼叫物件d來代替delete
shared_ptr<T> p( p2,d) p是shared_ptr p2的拷貝。唯一區別是p將用可呼叫物件d來代替delete

p.reset()

p.reset( q)

p.reset( q, d)

若p是唯一指向其物件的shared_ptr,reset會釋放物件

若傳遞了可選的引數內建指標q,會令p指向q,否則會將p置空。

若還傳遞了引數d,將會呼叫d而不是delete來釋放q

不要混合使用普通指標和智慧指標

//在函式被呼叫時ptr被建立並初始化
void process( shared_ptr<int> ptr)
{
	//使用ptr    
}    //ptr離開作用域被銷燬

shared_ptr<int> p(new int(42));        //引用計數:1
process(p);        //拷貝增加引用計數,在process中引用計數:2
int i = *p;        //正確:引用計數:1

int *x(new int(1024));
process(x);		//錯誤:不能將int *轉換成一個shared_ptr<int>
process( shared_ptr<int>(x));	//合法,但process結束後記憶體會釋放
int j = *x;			//未定義:x是一個空懸指標

  當講一個shared_ptr繫結到一個普通指標時,我們就將記憶體的管理責任交給了這個shared_ptr。一旦這麼做了,就不應該再使用內建指標來訪問shared_ptr所指向的記憶體。