1. 程式人生 > 其它 >C++ 智慧指標

C++ 智慧指標

智慧指標概念
C/C++ 語言最為人所詬病的特性之一就是存在記憶體洩露問題,因此後來的大多數語言都提供了內建記憶體分配與釋放功能,有的甚至乾脆對語言的使用者遮蔽了記憶體指標這一概念。這裡不置貶褒,手動分配記憶體與手動釋放記憶體有利也有弊,自動分配記憶體和自動釋放記憶體亦如此,這是兩種不同的設計哲學。有人認為,記憶體如此重要的東西怎麼能放心交給使用者去管理呢?而另外一些人則認為,記憶體如此重要的東西怎麼能放心交給系統去管理呢?在 C/C++ 語言中,記憶體洩露的問題一直困擾著廣大的開發者,因此各類庫和工具的一直在努力嘗試各種方法去檢測和避免記憶體洩露,如 boost,智慧指標技術應運而生。

智慧指標主要用於管理在堆上分配的記憶體,它將普通的指標封裝為一個棧物件。當棧物件的生存週期結束後,會在解構函式中釋放掉申請的記憶體,從而防止記憶體洩漏

。簡要的說,智慧指標利用了 C++ 的 RAII 機制,在智慧指標物件作用域結束後,會自動做記憶體釋放的相關操作,不需要我們再手動去操作記憶體。

RAII是C++的發明者Bjarne Stroustrup提出的概念,RAII全稱是“Resource Acquisition is Initialization”,直譯過來是“資源獲取即初始化”,也就是說在建構函式中申請分配資源,在解構函式中釋放資源。因為C++的語言機制保證了,當一個物件建立的時候,自動呼叫建構函式,當物件超出作用域的時候會自動呼叫解構函式。所以,在RAII的指導下,我們應該使用類來管理資源,將資源和物件的生命週期繫結。

C++ 中有四種智慧指標:auto_pt、unique_ptr、shared_ptr、weak_ptr

其中後三個是 C++11 支援,第一個已經被 C++11 棄用且被 unique_prt 代替,不推薦使用。下文將對其逐個說明。

std::auto_ptr

在這個年代討論 std::auto_ptr 不免有點讓人懷疑是不是有點過時了,確實如此,隨著 C++11 標準的出現(最新標準是 C++20),std::auto_ptr 已經被徹底放棄,取而代之是 std::unique_ptr。然而,之所以還向介紹一下 std::auto_ptr 的用法以及它的設計不足之處是想更多瞭解 C++ 語言中智慧指標的發展過程,一項技術如果我們瞭解它過去的樣子和發展的軌跡,我們就能更好地掌握它。

std::auto_ptr 的基本用法如下程式碼所示:

#include <iostream>
#include <memory>
using namespace std;
int main()
{
    //初始化方式1
    std::auto_ptr<int> ap1(new int(8));
    //初始化方式2
    std::auto_ptr<int> ap2;
    ap2.reset(new int(8));
    cout << *ap1 << ", " << *ap2 << endl;
    return 0;
}

輸出:

8, 8

智慧指標物件 ap1 和 ap2 均持有一個在堆上分配 int 物件,其值均是 8,這兩塊堆記憶體均可以在 ap1 和 ap2 釋放時得到釋放。這是 std::auto_ptr 的基本用法。

std::auto_ptr 真正讓人容易誤用的地方是其不常用的複製語義,即當複製一個 std::auto_ptr 物件時(拷貝複製或 operator= 複製),原物件所持有的堆記憶體物件也會轉移給複製出來的物件。示例程式碼如下: