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操作,可以放心地使用了。
不過這麼做的缺點也是很明顯的:
- 我們想管理的值是int[]類型的,然而事實上傳給模闆參數的是int
- 需要顯示提供delete functor
- 不能使用
,無法保證異常安全std::make_shared
- 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
就能安全而便捷地管理動态數組了。