在前面一篇文章中,我們了解了 C++11 中引入的智能指針之一 shared_ptr 和 weak_ptr ,今天,我們來介紹一下另一種智能指針 unique_ptr 。
往期文章參考:
- 【C++11新特性】 C++11 智能指針之shared_ptr
- 【C++11新特性】 C++11智能指針之weak_ptr
unique_ptr介紹
unique是獨特的、唯一的意思,故名思議,unique_ptr可以“獨占”地擁有它所指向的對象,它提供一種嚴格意義上的所有權。
這一點和我們前面介紹的 shared_ptr 類型指針有很大的不同:shared_ptr 允許多個指針指向同一對象,而 unique_ptr 在某一時刻隻能有一個指針指向該對象。
unique_ptr 儲存指向某個對象的指針,當它本身被删除或者離開其作用域時會自動釋放其指向對象所占用的資源。
1、如何建立unique_ptr
unique_ptr 不像shared_ptr一樣擁有标準庫函數make_shared來建立一個shared_ptr執行個體。
要想建立一個 unique_ptr,我們需要将一個 new 操作符傳回的指針傳遞給unique_ptr的構造函數。
示例:
int main(){
// 建立一個unique_ptr執行個體
unique_ptr<int> pInt(new int(5));
cout << *pInt;
}
2、無法進行複制構造和指派操作
unique_ptr沒有 copy 構造函數,不支援普通的拷貝和指派操作。
示例:
int main(){
// 建立一個unique_ptr執行個體
unique_ptr<int> pInt(new int(5));
unique_ptr<int> pInt2(pInt); // 報錯
unique_ptr<int> pInt3 = pInt; // 報錯
}
3、可以進行移動構造和移動指派操作
unique_ptr雖然沒有支援普通的拷貝和指派操作,但卻提供了一種移動機制來将指針的所有權從一個unique_ptr轉移給另一個unique_ptr。
如果需要轉移所有權,可以使用std::move()函數。
示例:
int main(){
unique_ptr<int> pInt(new int(5));
unique_ptr<int> pInt2 = std::move(pInt); // 轉移所有權
//cout << *pInt << endl; // 出錯,pInt為空
cout << *pInt2 << endl;
unique_ptr<int> pInt3(std::move(pInt2));
}
4、可以傳回unique_ptr
unique_ptr不支援拷貝操作,但卻有一個例外:可以從函數中傳回一個unique_ptr。
示例:
unique_ptr<int> clone(int p)
{
unique_ptr<int> pInt(new int(p));
return pInt; // 傳回unique_ptr
}
int main(){
int p = 5;
unique_ptr<int> ret = clone(p);
cout << *ret << endl;
}
unique_ptr使用場景
1、為動态申請的資源提供異常安全保證
我們先來看看下面這一段代碼:
void Func()
{
int *p = new int(5);
// ...(可能會抛出異常)
delete p;
}
這是我們傳統的寫法:當我們動态申請記憶體後,有可能我們接下來的代碼由于抛出異常或者提前退出(if語句)而沒有執行delete操作。
解決的方法是使用unique_ptr來管理動态記憶體,隻要unique_ptr指針建立成功,其析構函數都會被調用。確定動态資源被釋放。
void Func()
{
unique_ptr<int> p(new int(5));
// ...(可能會抛出異常)
}
2、傳回函數内動态申請資源的所有權
示例如下:
unique_ptr<int> Func(int p)
{
unique_ptr<int> pInt(new int(p));
return pInt; // 傳回unique_ptr
}
int main() {
int p = 5;
unique_ptr<int> ret = Func(p);
cout << *ret << endl;
// 函數結束後,自動釋放資源
}
3、在容器中儲存指針
int main() {
vector<unique_ptr<int>> vec;
unique_ptr<int> p(new int(5));
vec.push_back(std::move(p)); // 使用移動語義
}
4、管理動态數組
标準庫提供了一個可以管理動态數組的unique_ptr版本。
int main(){
unique_ptr<int[]> p(new int[5] {1, 2, 3, 4, 5});
p[0] = 0; // 重載了operator[]
}
作者:Fred^_^