1. 程式人生 > >C++之智慧指標std::shared_ptr簡單使用和理解

C++之智慧指標std::shared_ptr簡單使用和理解

1  智慧指標std::shared_ptr相關知識和如何使用

我們這裡先說下智慧指標std::shared_ptr,因為我看到我我們專案c++程式碼裡面用得很多,我不是不會,所以記錄學習下

先讓ubuntu終端支援c++11,如果自己的電腦還沒配置號,可以先看下我的這篇部落格linux之讓終端支援C++11/14編譯cpp檔案

 

1)  所在的標頭檔案

#include <memory>

 

2)  介紹:

     shared_ptr是一種智慧指標(smart pointer),作用有如同指標,但會記錄有多少個shared_ptrs共同指向一個物件。這便是所謂的引用計數(reference counting),比如我們把只能指標賦值給另外一個物件,那麼物件多了一個智慧指標指向它,所以這個時候引用計數會增加一個,我們可以用shared_ptr.use_count()函式檢視這個智慧指標的引用計數,一旦最後一個這樣的指標被銷燬,也就是一旦某個物件的引用計數變為0,這個物件會被自動刪除,當我們程式結束進行return的時候,智慧指標的引用計數會減1,不知道我理解有沒有問題.有的話請老鐵們指出.

 

3)  share_ptr的三種初始化方法
     1.通過一個指向堆上申請的空間的指標初始化(切記不要用棧上的指標,否則,當智慧指標全部釋放控制權(棧中的物件離開作用域本身就會析構一次),將會析構物件,導致出錯)

     比如如下

     int a = new int(100);

     std::shared_ptr ptr(a); //我們不能寫成std::shared_ptr ptr = a;這樣寫錯誤,不行你編譯執行看下,編譯不過

 

     2.  通過make_shared函式得到

std::shared_ptr<int> ptr1 = std::make_shared<int>(15);

     3 拷貝初始化

	std::shared_ptr<int> ptr2(ptr1);
	//std::shared_ptr<int> ptr2 = ptr1;這樣賦值是錯誤的,只要是智慧指標,這樣直接用=賦值是有問題的必須std::shared_ptr<int> ptr2(ptr1);

 

4)  reset函式

    當只能指標呼叫了reset函式的時候,就不會再指向這個物件了,所以如果還有其它智慧指標指向這個物件,那麼另外一個智慧指標的use_count()函式結果會減1

 

5)  智慧指標的enable_shared_from_thisshared_from_this

為什麼要用到enable_shared_from_this和shared_from_this,比如我們寫一個普通的類,有解構函式,一個智慧指標指向類物件的時候,我們解構函式會析購一次,然後智慧指標會析構一次,析構兩次就有問題,如下寫法

Student{
	Student(){}
	~Student()
	{
		std::cout << "~Student被呼叫" << std::endl;	
	}
	std::shared_ptr<Student> getStudent()
	{
		return std::shared_ptr<Student>(this);	
	} 
};

所以我們一般用這個類繼續enable_shared_from_this<Student>,然後getStudent函式的時候返回shared_from_this()這個就行

 

6 ) 如何判斷智慧指標是否為null,我麼可以使用get()函式,比如

std::shared_ptr<int> ptr(new int(100));
if (ptr.get()) {
    std::cout << "ptr is not null" << std::endl;
} else {
    std::cout << "ptr is null" << std::enel;
}

 

 

 

 

 

2  測試Demo

#include <iostream>
#include <memory>


using namespace std;

class Student : public enable_shared_from_this<Student>
{
public:
        Student() {}
	~Student()
	{
		std::cout << "~Student被呼叫" << std::endl;	
	}
	std::shared_ptr<Student> getStudent()
	{
		return shared_from_this();	
	} 
	std::string name;
	void setName(std::string name);
	std::string getName();
};

void Student::setName(std::string name)
{
	this->name = name;	
}

std::string Student::getName()
{
	return name;	
}

int main()
{
	int *p = new int(10);	
	//std::shared_ptr<int> ptr = p;這樣賦值是錯誤的額,只要是智慧指標,這樣直接用=賦值是有問題的必須std::shared_ptr<int> ptr(p);
	std::shared_ptr<int> ptr(p);
	std::shared_ptr<int> ptr1 = std::make_shared<int>(15);
	std::shared_ptr<int> ptr2(ptr1);
	//std::shared_ptr<int> ptr2 = ptr1;這樣賦值是錯誤的,只要是智慧指標,這樣直接用=賦值是有問題的必須std::shared_ptr<int> ptr2(ptr1);
	std::cout << "ptr.use_count() is:" << ptr.use_count() << "  *ptr is:" << *ptr << std::endl;
	std::cout << "ptr1.use_count() is:" << ptr1.use_count() << "  *ptr1 is:" << *ptr1 << std::endl;
	std::cout << "ptr2.use_count() is:" << ptr2.use_count() << "  *ptr2 is:" << *ptr2 << std::endl;
	
	ptr2.reset();
	//這是時候ptr2已經銷燬,指向的物件引用計數會減1,這個指標的不再指向任何物件,所以我們不能使用*ptr2了,下面一行程式碼使用肯定會報錯,我先註釋掉
	//std::cout << "ptr2.use_count() is:" << ptr2.use_count() << "*ptr2 is:" << *ptr2 << std::endl;
        std::cout << "ptr1.use_count() is:" << ptr1.use_count() << "   *ptr1 is:" << *ptr1 << std::endl;
	Student *stu = new Student();
	std::shared_ptr<Student> ptr_stu(stu);
	std::string name = "chenyu";
	ptr_stu->setName(name);
	std::string result = ptr_stu->getName();
        std::cout << "ptr_stu.use_count() is:" << ptr_stu.use_count() << std::endl;
	std::cout << "my name is:" << result << std::endl;
        return 0;
}

 

 

 

 

3  執行結果以及分析

ptr.use_count() is:1  *ptr is:10
ptr1.use_count() is:2  *ptr1 is:15
ptr2.use_count() is:2  *ptr2 is:15
ptr1.use_count() is:1   *ptr1 is:15
ptr_stu.use_count() is:1
my name is:chenyu
~Student被呼叫

很明顯呼叫了reset之後,引用技術減1了,然後程式在return的時候,ptr和ptr1和ptr_stu的引用計數會變為0,所以指向的物件就會自動銷燬,所以不會導致記憶體洩漏