C++ 補充 & C++ 11 - C++智能指針shared_ptr 使用詳解 (C++11)

shared_ptr 使用詳解 (C++11)

熟悉了unique_ptr 後,其實我們發現unique_ptr 這種排他型的內存管理並不能適應所有情況,有很大的侷限!如果需要多個指針變量共享怎麼辦?

如果有一種方式,可以記錄引用特定內存對象的智能指針數量,當複製或拷貝時,引用計數加1,當智能指針析構時,引用計數減1,如果計數爲零,代表已經沒有指針指向這塊內存,那麼我們就釋放它!這就是 shared_ptr 採用的策略!

在這裏插入圖片描述

構造函數

shared_ptr sp ; //空的shared_ptr,可以指向類型爲T的對象
shared_ptr sp1(new T()) ;//定義shared_ptr,同時指向類型爲T的對象
shared_ptr<T[]> sp2 ; //空的shared_ptr,可以指向類型爲T[的數組對象 C++17後支持
shared_ptr<T[]> sp3(new T[]{…}) ;//指向類型爲T的數組對象 C++17後支持
shared_ptr sp4(NULL, D()); //空的shared_ptr,接受一個D類型的刪除器,使用D
釋放內存
shared_ptr sp5(new T(), D()); //定義shared_ptr,指向類型爲T的對象,接受一個D 類型的刪除器,使用D刪除器來釋放內存

初始化

方式一 構造函數
shared_ptrr up1(new int(10)); //int(10) 的引用計數爲1
shared_ptrr up2(up1); //使用智能指針up1構造up2, 此時int(10) 引用計數爲2

方式二 使用make_shared 初始化對象,分配內存效率更高
make_shared函數的主要功能是在動態內存中分配一個對象並初始化它,返回指向此對象的shared_ptr; 用法:
make_shared<類型>(構造類型對象需要的參數列表);
shared_ptr p4 = make_shared(2); //多個參數以逗號’,'隔開,最多接受十個
shared_ptr p4 = make_shared(“字符串”);

demo 代碼(一)

#include <iostream>
#include <stdio.h>
#include <memory>

using namespace std;

class Person
{
public:
	Person(int v)
	{
		this->no = v;
		cout << "Construct" << no << endl;
	}

	~Person()
	{
		cout << "Destruct" << no << endl;
	}
	
private:
	int no;

};

int main(void)
{
	shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
	shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */

	cout << "sp1 ref_counter: " << sp1.use_count() << endl;
	cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */

	sp1 = sp2;
	cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;

	shared_ptr<Person> sp3(sp1);
	cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;

	system("pause");
	return 0;
}

運行結果:
在這裏插入圖片描述

demo 代碼(二)

#include <iostream>
#include <stdio.h>
#include <memory>

using namespace std;

class Person
{
public:
	Person(int v)
	{
		this->no = v;
		cout << "Construct" << no << endl;
	}

	~Person()
	{
		cout << "Destruct" << no << endl;
	}
	
private:
	int no;

};

int main(void)
{
	shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
	shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */

	cout << "sp1 ref_counter: " << sp1.use_count() << endl;
	cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */

	sp1 = sp2;
	cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;

	shared_ptr<Person> sp3(sp1);
	cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;

	/* 數組對象的管理 */
	shared_ptr<Person[]> sp4(new Person[5]{ 3,4,5,6,7 }); /* delete [] */

	system("pause");
	return 0;
}

運行結果:
在這裏插入圖片描述

demo 代碼(三)

#include <iostream>
#include <stdio.h>
#include <memory>

using namespace std;

class Person
{
public:
	Person(int v)
	{
		this->no = v;
		cout << "Construct" << no << endl;
	}

	~Person()
	{
		cout << "Destruct" << no << endl;
	}
	
private:
	int no;

};

class DestructPerson
{
public:
	void operator()(Person* pt)
	{
		cout << "DestructPerson" << endl;
		delete pt;
	}
};


int main(void)
{
	shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
	shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */

	cout << "sp1 ref_counter: " << sp1.use_count() << endl;
	cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */

	sp1 = sp2;
	cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;

	shared_ptr<Person> sp3(sp1);
	cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;

	/* 數組對象的管理 */
	shared_ptr<Person[]> sp4(new Person[5]{ 3,4,5,6,7 }); /* delete [] */

	shared_ptr<Person> sp8(new Person(8), DestructPerson()); /* 調用 DestructPerson 釋放對象 */

	/* 使用 make_shared 函數模板初始化 */
	shared_ptr<Person> sp9;
	sp9 = make_shared<Person>(9);
	cout << "after sp9 = mke_shared<Person>(9), sp9 ref_counter: " << sp9.use_count() << endl;

	system("pause");
	return 0;
}

運行結果:
在這裏插入圖片描述

demo 代碼(四)

#include <iostream>
#include <stdio.h>
#include <memory>

using namespace std;

class Person
{
public:
	Person(int v)
	{
		this->no = v;
		cout << "Construct" << no << endl;
	}

	~Person()
	{
		cout << "Destruct" << no << endl;
	}
	
private:
	int no;

};

class DestructPerson
{
public:
	void operator()(Person* pt)
	{
		cout << "DestructPerson" << endl;
		delete pt;
	}
};


int main(void)
{
	shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
	shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */

	cout << "sp1 ref_counter: " << sp1.use_count() << endl;
	cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */

	sp1 = sp2;
	cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;

	shared_ptr<Person> sp3(sp1);
	cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;

	/* 數組對象的管理 */
	shared_ptr<Person[]> sp4(new Person[5]{ 3,4,5,6,7 }); /* delete [] */

	shared_ptr<Person> sp8(new Person(8), DestructPerson()); /* 調用 DestructPerson 釋放對象 */

	/* 使用 make_shared 函數模板初始化 */
	shared_ptr<Person> sp9;
	sp9 = make_shared<Person>(9);
	cout << "after sp9 = mke_shared<Person>(9), sp9 ref_counter: " << sp9.use_count() << endl;

	shared_ptr<Person> sp10;
	Person* p10 = new Person(10);
	sp9.reset(p10);
	cout << "after sp9.reset(p10), sp9 ref_counter: " << sp9.use_count() << endl;


	system("pause");
	return 0;
}

執行:

在這裏插入圖片描述

demo 代碼(五)

#include <iostream>
#include <stdio.h>
#include <memory>

using namespace std;

class Person
{
public:
	Person(int v)
	{
		this->no = v;
		cout << "Construct" << no << endl;
	}

	~Person()
	{
		cout << "Destruct" << no << endl;
	}

	int no;

};

class DestructPerson
{
public:
	void operator()(Person* pt)
	{
		cout << "DestructPerson" << endl;
		delete pt;
	}
};


int main(void)
{
	shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
	shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */

	cout << "sp1 ref_counter: " << sp1.use_count() << endl;
	cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */

	sp1 = sp2;
	cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;

	shared_ptr<Person> sp3(sp1);
	cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;

	/* 數組對象的管理 */
	shared_ptr<Person[]> sp4(new Person[5]{ 3,4,5,6,7 }); /* delete [] */

	shared_ptr<Person> sp8(new Person(8), DestructPerson()); /* 調用 DestructPerson 釋放對象 */

	/* 使用 make_shared 函數模板初始化 */
	shared_ptr<Person> sp9;
	sp9 = make_shared<Person>(9);
	cout << "after sp9 = mke_shared<Person>(9), sp9 ref_counter: " << sp9.use_count() << endl;

	shared_ptr<Person> sp10 = sp9;
	Person* p10 = new Person(10);
	sp9.reset(p10);
	cout << "after sp9.reset(p10), sp9 ref_counter: " << sp9.use_count() << endl;

	/* 交換 swap 用法 */
	std::swap(sp9, sp10);

	cout << "交換後, sp9: " << sp9->no << "sp10: " << sp10->no << endl;

	sp9.swap(sp10);
	cout << "sp9. swap(sp10) 交換後, sp9: " << sp9->no << " sp10: " << sp10->no << endl;

	system("pause");
	return 0;
}

運行結果:

在這裏插入圖片描述

賦值

shared_ptrr up1(new int(10)); //int(10) 的引用計數爲1
shared_ptr up2(new int(11)); //int(11) 的引用計數爲1
up1 = up2;//int(10) 的引用計數減1,計數歸零內存釋放,up2共享int(11)給up1, int(11)
的引用計數爲2

主動釋放對象

shared_ptrr up1(new int(10));
up1 = nullptr ;//int(10) 的引用計數減1,計數歸零內存釋放

up1 = NULL; //作用同上

重置

up.reset() ; //將p重置爲空指針,所管理對象引用計數 減1
up.reset(p1); //將p重置爲p1(的值),p 管控的對象計數減1,p接管對p1指針的管控
up.reset(p1,d); //將p重置爲p(的值),p 管控的對象計數減1並使用d作爲刪除器

交換

std::swap(p1,p2); //交換p1 和p2 管理的對象,原對象的引用計數不變
p1.swap(p2); //同上

使用陷阱

shared_ptr作爲被管控的對象的成員時,小心因循環引用造成無法釋放資源!

#include <stdio.h>
#include <iostream>
#include <string>
#include <memory>
#include <vector>

using namespace std;

class girl;

class boy
{
public:
	boy()
	{
		cout << "boy construct!" << endl;
	}

	~boy()
	{
		cout << "boy destruct!" << endl;
	}

	void set_girl_friend(shared_ptr<girl>& g)
	{
		this->girl_friend = g;
	}

private:
	shared_ptr<girl> girl_friend;
};

class girl
{
public:
	girl()
	{
		cout << "girl construct !" << endl;
	}

	~girl()
	{
		cout << "girl destruct!" << endl;
	}

	void set_boy_friend(shared_ptr<boy>& b)
	{
		this->boy_friend = b;
	}

private:
	shared_ptr<boy> boy_friend;
};

void use_trap()
{
	shared_ptr<girl> sp_girl(new girl()); /* 白娘子 */
	shared_ptr<boy> sp_boy(new boy()); /* 許仙 */

	sp_girl->set_boy_friend(sp_boy);
	sp_boy->set_girl_friend(sp_girl);

}


int main()
{
	use_trap();

	system("pause");
	return 0;
}

結語:

這時間, 快高考了!!!

時間: 2020-07-03

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章