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就能安全而便捷地管理動態數組了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM