天天看點

shared_ptr和動态數組

std::shared_ptr

智能指針是c++11一個相當重要的特性,可以極大地将開發者從資源申請/釋放的繁重勞動中解放出來。

然而直到c++17前

std::shared_ptr

都有一個嚴重的限制,那就是它并不支援動态數組:

#include <memory>

std::shared_ptr<int[]> sp1(new int[10]()); // 錯誤,c++17前不能傳遞數組類型作為shared_ptr的模闆參數
std::unique_ptr<int[]> up1(new int[10]()); // ok, unique_ptr對此做了特化

std::shared_ptr<int> sp2(new int[10]()); // 錯誤,可以編譯,但會産生未定義行為,請不要這麼做
           

sp1

錯誤的原因很明顯,然而

sp2

的就沒有那麼好找了,究其原因,是因為

std::shared_ptr

對非數組類型都使用

delete p

釋放資源,顯然這對于

new int[10]

來說是不對的,對它應該使用

delete [] p

其實c++17前的解決方案并不複雜,我們可以借助

std::default_delete

,它用于提供對應類型的正确的delete操作:

std::shared_ptr<int> sp3(new int[10](), std::default_delete<int[]>());
           

現在我們提供了正确的delete操作,可以放心地使用了。

不過這麼做的缺點也是很明顯的:

  1. 我們想管理的值是int[]類型的,然而事實上傳給模闆參數的是int
  2. 需要顯示提供delete functor
  3. 不能使用

    std::make_shared

    ,無法保證異常安全
  4. c++17前shared_ptr未提供

    opreator[]

    ,是以當需要類似操作時不得不使用

    sp3.get()[index]

    的形式

事實上共享一片連續配置設定記憶體的需求是極為常見的,是以為了修正上述缺陷,c++17以及即将推出的c++2a對

std::shared_ptr

做了完善。

先說c++17的改進,shared_ptr增加了

opreator[]

,并可以使用

int[]

類的數組類型做模闆參數,是以

sp3

的定義可以簡化了:

std::shared_ptr<int[]> sp3(new int[10]());
           

對于通路配置設定的空間,可以将

sp3.get()[index]

替換為

sp3[index]

。看個具體的例子:

#include <iostream>
#include <memory>

int main()
{
    std::shared_ptr<int[]> sp(new int[5]());
    for (int i = 0; i < 5; ++i) {
        sp[i] = (i+1) * (i+1);
    }

    for (int i = 0; i < 5; ++i) {
        std::cout << sp[i] << std::endl;
    }
}
           

我們配置設定一個有5個int元素的動态數組,然後分别指派1-5的平方,然後輸出:

g++ -Wall -std=c++17 test.cpp
./a.out

1
4
9
16
25
           

使用被極大得簡化了,然而還是有點問題,那就是無法使用

std::make_shared

,而我們除非指定自己的delete functor,否則我們應該盡量使用

std::make_shared

是以c++20對此做了改進:

auto up2 = std::make_unique<int[]>(10); // 從c++14開始,配置設定一個管理有10個int元素的動态數組的unique_ptr

// c++2a中你可以這樣寫,與上一句相似,隻不過傳回的是shared_ptr
auto sp3 = std::make_shared<int[]>(10);
           

在我的編譯器上(GCC 8.2.1)還不能支援這一特性,是以很遺憾得不能提供示範了。

不過等c++2a(很可能就叫c++20)釋出後

std::shared_ptr

就能安全而便捷地管理動态數組了。

c++

繼續閱讀