小古銀的官方網站(完整教程):http://www.xiaoguyin.com/
C++入門教程視頻:https://www.bilibili.com/video/av20868986/
目錄
智能指針就是爲了方便釋放堆內存和解決各種需要程序員注意的細節而出現的,智能指針不強制程序員手動釋放堆內存。當智能指針離開作用域時,智能指針會自動釋放它指向的堆內存。這篇教程將講解如何簡單地使用智能指針。
獨佔指針
類std::unique_ptr
是獨佔指針的類型,獨佔指針是智能指針的一種,它在memory
標準庫中。
基礎示例
先來看看獨佔指針的創建和使用:
#include <iostream> // std::cout std::endl std::boolalpha
#include <memory> // std::unique_ptr
int main(void)
{
// 創建默認的獨佔指針,默認的獨佔指針被初始化爲nullptr
std::unique_ptr<int> pointer1;
std::cout << std::boolalpha << "默認獨佔指針被初始化爲nullptr:" << (pointer1 == nullptr) << std::endl;
// 申請堆內存並且初始化內存數據爲2333, 然後將內存地址賦值給pointer1
pointer1 = std::make_unique<int>(2333);
std::cout << *pointer1 << std::endl;
// 申請堆內存並且初始化內存數據爲666, 然後將內存地址初始化給pointer2
auto pointer2 = std::make_unique<int>(666);
std::cout << *pointer2 << std::endl;
return 0;
}
輸出結果:
默認獨佔指針被初始化爲nullptr:true
2333
666
基礎講解
以下是創建默認的獨佔指針pointer
,用來保存int
類型的內存地址。默認創建的獨佔指針會被初始化爲指針空值nullptr
:
std::unique_ptr<int> pointer;
以下這個函數是申請int
類型的堆內存並且保存到一個獨佔指針中,然後返回這個獨佔指針:
std::make_unique<int>(666);
函數裏的參數是函數<>
裏類型的構造參數,上面的這個函數內部實現的功能類似於new int(666);
;當函數不填寫參數時,即std::make_unique<int>();
,就相當於new int();
。
以上就是創建獨佔指針的方法,而使用方法和普通的指針一樣。
基礎補充
類std::unique_ptr
聲明的指針獨佔一份堆內存。也就是說,一份堆內存同一時間只能由一個獨佔指針保存它的地址,其他指針都不能通過賦值來保存這份堆內存的地址;如果想用其他獨佔指針保存這份堆內存,則只能通過轉移來賦值。先看看一個簡單的栗子:
#include <iostream> // std::cout std::endl std::boolalpha
#include <memory> // std::unique_ptr
int main(void)
{
auto pointer1 = std::make_unique<int>(666);
// auto pointer2 = pointer1; // 賦值操作, 去掉開頭註釋編譯將會報錯
auto pointer2 = std::move(pointer1); // 轉移操作
std::cout << std::boolalpha << (pointer1 == nullptr) << std::endl;
std::cout << *pointer2 << std::endl;
return 0;
}
輸出結果:
true
666
共享指針
類std::shared_ptr
是共享指針的類型,共享指針是智能指針的一種,它在memory
標準庫中。
顧名思義,共享指針保存的內存地址可以共享給其他共享指針。由於它可以共享,爲了保證它的安全性,共享指針自身所需內存也比獨佔指針要多一點,而內部會比獨佔指針多小小操作,所以性能會有小小下降。共享指針的額外消耗非常小,一般可以忽略;如果系統資源對這些損耗非常敏感,可以考慮儘量使用獨佔指針。
基礎示例
#include <iostream> // std::cout std::endl std::boolalpha
#include <memory> // std::shared_ptr
int main(void)
{
// 創建默認的共享指針,默認的共享指針被初始化爲nullptr
std::shared_ptr<int> pointer1;
std::cout << std::boolalpha;
std::cout << "默認共享指針被初始化爲nullptr:" << (pointer1 == nullptr) << std::endl;
// 申請堆內存並且初始化內存數據爲2333, 然後將內存地址賦值給pointer1
pointer1 = std::make_shared<int>(2333);
std::cout << "pointer1指向的內存的值:" << *pointer1 << std::endl << std::endl;
// pointer1賦值給pointer2
auto pointer2 = pointer1;
std::cout << "pointer2保存的地址是否等於pointer1保存的地址:" << (pointer1 == pointer2) << std::endl;
std::cout << "pointer2指向的內存的值:" << *pointer2 << std::endl << std::endl;
// pointer1保存的內存地址轉移給pointer3
auto pointer3 = std::move(pointer1); //
std::cout << "轉移後pointer1是否保存指針空值:" << (pointer1 == nullptr) << std::endl;
std::cout << "pointer2保存的地址是否等於pointer3保存的地址:" << (pointer2 == pointer3) << std::endl;
std::cout << "pointer2指向的內存的值:" << *pointer2 << std::endl;
std::cout << "pointer3指向的內存的值:" << *pointer3 << std::endl;
return 0;
}
輸出結果:
默認共享指針被初始化爲nullptr:true
pointer1指向的內存的值:2333
pointer2保存的地址是否等於pointer1保存的地址:true
pointer2指向的內存的值:2333
轉移後pointer1是否保存指針空值:true
pointer2保存的地址是否等於pointer3保存的地址:true
pointer2指向的內存的值:2333
pointer3指向的內存的值:2333
基礎講解
共享指針的操作和獨佔指針的操作類似,使用函數std::make_shared
申請內存並返回一個共享指針。而共享指針可以把它保存的地址共享給其他共享指針,獨佔指針則不行。
補充知識
- 智能指針從C++11開始加入。
- 函數
std::make_unique()
從C++14開始加入。