【9】C++四個智能指針

1 智能指針的作用

智能指針的作用是管理一個指針,因爲存在以下這種情況:申請的空間在函數結束時忘記釋放,造成內存泄漏。所以智能指針的作用原理就是在函數結束時自動釋放內存空間,不需要手動釋放內存空間。對於編譯器來說,智能指針實際上是一個棧對象,並非指針類型,在棧對象生命期即將結束時,智能指針通過析構函數釋放有它管理的堆內存。所有智能指針都重載了“operator->”操作符,直接返回對象的引用,用以操作對象。訪問智能指針原來的方法則使用“.”操作符。智能指針不等同與普通指針。

2智能指針分類

STL 一共給我們提供了四種智能指針:auto_ptr、unique_ptr、shared_ptr 和 weak_ptr,auto_ptr 是 C++98 提供的解決方案,C+11 已將其摒棄,並提出了 unique_ptr 作爲 auto_ptr 替代方案。

3各種智能指針介紹

3.1 unique_ptr

目的:將對象限制爲由一個所有者(指針)所有,因爲多個所有權會使程序邏輯變得複雜(即只准有一個指針訪問對象)
unique_ptr 的構造和移動:
在這裏插入圖片描述

unique_ptr的基本操作有:

// Automaticptr.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
#include "pch.h"
#include <iostream>
#include <memory>//智能指針頭文件

using namespace std;

struct Task {
	int mId;
	Task(int id) :mId(id) {
		std::cout << "Task::Constructor" << std::endl;
	}
	~Task() {
		std::cout << "Task::Destructor" << std::endl;
	}
};

int main()
{
	// 通過原始指針創建 unique_ptr 實例
	std::unique_ptr<Task> taskPtr(new Task(23));
	//通過 unique_ptr 訪問其成員
	int id = taskPtr->mId;
	cout << id <<endl;
	
	//普通指針
	char str[] = "hjdjdt";
	char *ptr =str;
	cout << ptr << endl;
	//[1]unique_ptr
	//目的:將對象限制爲由一個所有者所有,即一個指針指向一個對象,不容許多個指針指向一個對象
	//構造智能指針
	auto ptrA = make_unique<string>("guih"); //C++ 14 引入的新函數
	cout <<"智能指針 ptrA:" <<ptrA << endl;
	//cout << "智能指針 ptrA:" << ptrA.get << endl;
	//變更智能指針
	auto ptrB = move(ptrA);
	cout << "智能指針 ptrA:" << ptrA << endl;//ptrA被清空
	cout << "智能指針 ptrB:" << ptrB << endl;//ptrA被賦值給ptrB
	
	//創建空的智能指針
	unique_ptr<int> ptrC;
	//綁定動態對象,創建時沒有賦值,需要重新綁定
	ptrC.reset(new int(3));
	
	//創建時指定動態對象
	unique_ptr<int> ptrD(new int(4));

	// 所有權的變化
	int *p_i = ptrD.release();	//釋放所有權  
	unique_ptr<string> u_s(new string("abc"));

	//所有權轉移(通過移動語義),u_s所有權轉移後,變成“空指針” 
	unique_ptr<string> u_s2 = move(u_s); 

	//所有權轉移 先釋放在設置爲空指針
	u_s2.reset(u_s.release());	

	//顯式銷燬所指對象,同時智能指針變爲空指針。與u_s2.reset()等價
	u_s2 = nullptr;
	system("pause");
	return 0;
}

3.2 auto_ptr

auto_ptr 在 C++98 中引入,定義在頭文件。其功能和用法類似於 unique_ptr,由 new expression 獲得對象,在 auto_ptr 對象銷燬時,他所管理的對象也會自動被 delete 掉。auto_ptr 從 C++98 使用至今,從 C++11 開始,引入unique_ptr 來替代 auto_ptr 。
替換的原因:
(1)安全考慮
避免因潛在的內存問題導致程序崩潰 。使用 unique_ptr 時編譯出錯,與 auto_ptr 一樣,unique_ptr 也採用所有權模型,但在使用 unique_ptr 時,程序不會等到運行階段崩潰
(2)unique_ptr 安全而且靈活
unique_ptr 是個臨時右值,編譯器允許拷貝語義,原始指針賦值給新的指針時,原始指針會自動被清除。
(3)擴展 auto_ptr 不能完成的功能
(a)unique_ptr 可放在容器中,彌補了 auto_ptr 不能作爲容器元素的缺點。
(b)管理動態數組,因爲 unique_ptr 有 unique_ptr<X[]> 重載版本,銷燬動態對象時調用 delete[]。
(c)自定義資源刪除操作(Deleter)。unique_ptr 默認的資源刪除操作是 delete/delete[],若需要,可以進行自定義

3.3 shared_ptr

shared_ptr 是一個標準的共享所有權的智能指針,允許多個指針指向同一個對象。原理:shared_ptr維護了一個指向control block的指針對象,來記錄引用個數。
shared_ptr 是爲了解決 auto_ptr 在對象所有權上的侷限性(auto_ptr 是獨佔的),在使用引用計數的機制上提供了可以共享所有權的智能指針,當然這需要額外的開銷:
(1)shared_ptr 對象除了包括一個所擁有對象的指針外,還必須包括一個引用計數代理對象的指針;
(2)時間上的開銷主要在初始化和拷貝操作上, * 和 -> 操作符重載的開銷跟 auto_ptr 是一樣;
(3)開銷並不是我們不使用 shared_ptr 的理由,,永遠不要進行不成熟的優化,直到性能分析器告訴你這一點。

3.4 weak_ptr

weak_ptr用於避免shared_ptr相互指向產生的環形結構,造成的內存泄漏。weak_ptr count是弱引用個數;弱引用個數不影響shared count和對象本身,shared count爲0時則直接銷燬。
weak_ptr 被設計爲與 shared_ptr 共同工作,可以從一個 shared_ptr 或者另一個 weak_ptr 對象構造而來。weak_ptr 是爲了配合 shared_ptr 而引入的一種智能指針,它更像是 shared_ptr 的一個助手而不是智能指針,因爲它不具有普通指針的行爲,沒有重載 operator* 和 operator-> ,因此取名爲 weak,表明其是功能較弱的智能指針。它的最大作用在於協助 shared_ptr 工作,可獲得資源的觀測權,像旁觀者那樣觀測資源的使用情況。觀察者意味着 weak_ptr 只對 shared_ptr 進行引用,而不改變其引用計數,當被觀察的 shared_ptr 失效後,相應的 weak_ptr 也相應失效。

4 智能指針選擇原則

(1)如果程序要使用多個指向同一個對象的指針,應選擇shared_ptr。
(2)如果程序不需要多個指向同一個對象的指針,則可使用unique_ptr。

5 參考文獻

C++ 智能指針詳解
C++ STL 四種智能指針:https://blog.csdn.net/k346k346/article/details/81478223#comments
C++11的智能指針(常見面試問題):https://blog.csdn.net/xy_cpp/article/details/81750575?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

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