C++深入分析講解智能指針
1.簡介
程序運行時存在靜態(tài)空間、棧和堆區(qū),用堆來存儲動態(tài)分配空間的對象即那些在程序運行時分配空間的對象,若該對象不再使用,我們必須顯式的銷毀它們,避免內(nèi)存泄漏。
智能指針是一個可以像指針一樣工作的對象,有unique_ptr(獨占指針),shared_ptr與weak_ptr等智能指針,定義在<memory>頭文件中,可以對動態(tài)資源進行管理。
保證以構(gòu)造的對象最終會銷毀,即它的析構(gòu)函數(shù)最終會被調(diào)用。
注意:
1.為了避免內(nèi)存泄漏,通過智能指針管理的對象應(yīng)該沒有其他的引用指向它們.
2.智能指針不支持指針的算術(shù)運算
2.unique_ptr指針(獨占指針)
我們大多數(shù)場景下用到的都是unique_ptr。
其在默認情況下和普通指針的大小是相同,內(nèi)存上沒有任何的額外消耗,性能最優(yōu)。
注意:
1.不能使用其他unique_ptr對象的值來初始化一個unique_ptr。也不能將一個unique_ptr對象賦值給另外一個。這樣的操作將導(dǎo)致兩個獨占指針共享相同對象的所有權(quán)。
2.unique_ptr代表的是專屬所有權(quán),如果想要把一個unique_ptr的內(nèi)存交給另外一個unique_ptr對象管理。
只能使用std::move轉(zhuǎn)移當(dāng)前對象的所有權(quán)。轉(zhuǎn)移之后,當(dāng)前對象不再持有此內(nèi)存,新的對象將獲得專屬所有權(quán)。
3.若unique_ptr指向的是一個對象數(shù)組的話,要確保調(diào)用delete[]來處理被解除分配的數(shù)組,則應(yīng)該在對象類型后面包含一對空的方括號[]。
#include<iostream>
#include<memory>
using namespace std;
int main()
{
unique_ptr<int> up1(new int(11));
cout << "up = " << *up1 << endl;
//將up1的獨占權(quán)轉(zhuǎn)移給up2,up1不能再操作堆區(qū)空間
unique_ptr<int> up2 = std::move(up1);
cout << "up2 = " << *up2 << endl;
//up2.reset();//若為無參作用是顯示釋放堆區(qū)內(nèi)容
up2.reset(new int(22));//若為有參,先釋放原來堆區(qū)內(nèi)容,重新給up2綁定一個新的堆區(qū)內(nèi)容
cout << "up2 = " << *up2 << endl;
//釋放控制權(quán),但不釋放堆區(qū)內(nèi)存
int* p = up2.release();
cout <<"p = "<< *p << endl;
delete p;
p = nullptr;
return 0;
}#include<iostream>
#include<memory>
using namespace std;
int main()
{
//指向數(shù)組的獨占指針
unique_ptr<int[] > up(new int[5]);
for (int k = 0; k < 5; k++)
{
up[k] = k+1;
}
for (int k = 0; k < 5; k++)
{
cout << up[k] << " ";
}
cout << endl;
return 0;
}3.shared_ptr指針(共享所有權(quán))
多個shared_ptr智能指針可以共同使用同一塊堆內(nèi)存。由于該類型智能指針在實現(xiàn)上采用的是引用計數(shù)機制,
即便有一個shared_ptr指針放棄了堆內(nèi)存的"使用權(quán)"(引用計數(shù)減1)也不會影響其他指向同一堆內(nèi)存的shared_ptr指針(只有引用計數(shù)為0時,堆內(nèi)存才會被自動釋放)
#include<iostream>
#include<memory>
using namespace std;
int main()
{
shared_ptr<int> sp1(new int(11));
shared_ptr<int>sp2(sp1);//拷貝構(gòu)造
cout << "num = " << sp2.use_count() << endl;//打印計數(shù)器 2
sp1.reset();
cout << "num = " << sp2.use_count() << endl;//1
cout << *sp2 << endl;//11
sp1.reset();
cout << "num = " << sp1.use_count() << endl;//0
return 0;
}shared_ptr的內(nèi)存占用是裸指針的兩倍。因為除了要管理一個裸指針外,還要維護一個引用計數(shù)。 因此相比于unique_ptr, shared_ptr的內(nèi)存占用更高。
4.weak_ptr(輔助作用)
該類型指針通常不單獨使用(沒有實際用處),只能和shared_ptr搭配使用。我們可以將weak_ptr視為shared_ptr指針的一種輔助工具。
借助weak_ptr類型指針,我們可以獲取shared_ptr指針的一些狀態(tài)信息,比如有多少指向相同的shared_ptr指針,shared_ptr指針指向的堆內(nèi)存是否已經(jīng)被釋放等。
當(dāng)weak_ptr類型指針的指向和某一shared_ptr指針相同時,weak_ptr并不會使所指堆內(nèi)存的引用計數(shù)加1
當(dāng)weak_ptr指針被釋放時,之前所指堆內(nèi)存的引用計數(shù)也不會因此而減1.也就是說,weak_ptr并不會影響所指堆內(nèi)存空間的引用計數(shù)。
weak_ptr<T>模板類中沒有重載*和->運算符 , weak_ptr 類型指針只能訪問所指的堆內(nèi)存,而無法修改它
#include<iostream>
#include<memory>
using namespace std;
int main()
{
shared_ptr<int>sp1(new int(11));
shared_ptr<int>sp2(sp1);
weak_ptr<int>wp = sp1;
cout << wp.use_count() << endl;
shared_ptr<int>sp3 = wp.lock();
//lock() 若當(dāng)前weak_ptr已經(jīng)過期,則該函數(shù)會返回一個空的shared_ptr指針.反之,該函數(shù)返回一個和當(dāng)前weak_ptr指向相同的shared_ptr。
cout << wp.use_count() << endl;
if (sp3 == nullptr)
{
cout << "堆區(qū)空間已經(jīng)釋放" << endl;
}
else
{
//cout << *wp << endl;//err
cout << *sp3 << endl;//間接訪問
}
return 0;
}5.自實現(xiàn)初級版智能指針
#include<iostream>
using namespace std;
class Person
{
public:
Person(int age)
{
cout << "有參構(gòu)造函數(shù)調(diào)用" << endl;
m_age = age;
}
void showage()
{
cout << "年齡為:" << this->m_age << endl;
}
~Person()
{}
int m_age;
};
//利用智能指針管理new出來的內(nèi)存的釋放
class Smartpoint
{
public:
Smartpoint(Person* p)
{
this->m_person = p;
}
//重載->運算符
Person* operator->()
{
return this->m_person;
}
//重載*運算符
Person& operator*()
{
return *m_person;
}
~Smartpoint()
{
if (this->m_person != NULL)
{
//cout << "析構(gòu)函數(shù)調(diào)用" << endl;
delete this->m_person;
}
}
private:
Person* m_person;
};
int main()
{
Smartpoint sp(new Person(18));
sp->showage();
(*sp).showage();
return 0;
}6.總結(jié)
在實際項目開發(fā)中建議使用智能指針,而非裸指針,這在后面的文章中會進行具體的講解。
到此這篇關(guān)于C++深入分析講解智能指針的文章就介紹到這了,更多相關(guān)C++智能指針內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ 使用CRC32檢測內(nèi)存映像完整性的實現(xiàn)步驟
當(dāng)我們使用動態(tài)補丁的時候,那么內(nèi)存中同樣不存在校驗效果,也就無法抵御對方動態(tài)修改機器碼了,為了防止解密者直接對內(nèi)存打補丁,我們需要在硬盤校驗的基礎(chǔ)上,增加內(nèi)存校驗,防止動態(tài)補丁的運用。2021-06-06
C++類與對象深入之靜態(tài)成員與友元及內(nèi)部類詳解
朋友們好,這篇播客我們繼續(xù)C++的初階學(xué)習(xí),現(xiàn)在對我們對C++的靜態(tài)成員,友元,內(nèi)部類知識點做出總結(jié),整理出來一篇博客供我們一起復(fù)習(xí)和學(xué)習(xí),如果文章中有理解不當(dāng)?shù)牡胤?還希望朋友們在評論區(qū)指出,我們相互學(xué)習(xí),共同進步2022-06-06
在Visual Studio中用C++語言創(chuàng)建DLL動態(tài)鏈接庫圖文教程
這篇文章主要介紹了在Visual Studio中用C++語言創(chuàng)建DLL動態(tài)鏈接庫圖文教程,本文詳細講解了DLL庫的創(chuàng)建過程,并給出了代碼示例,需要的朋友可以參考下2014-09-09
C/C++函數(shù)調(diào)用的幾種方式總結(jié)
本篇文章主要是對C/C++函數(shù)調(diào)用的幾種方式進行了詳細的總結(jié)介紹,需要的朋友可以過來參考下,希望對大家有所幫助2013-12-12
matlab模擬退火算法單約束車間流水線調(diào)度解決實現(xiàn)及示例
這篇文章主要為大家介紹了matlab模擬退火算法求解單約束車間流水線調(diào)度的實現(xiàn)及示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-02-02

