欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c++11 新特性——智能指針使用詳解

 更新時(shí)間:2021年02月05日 08:38:18   作者:鬼谷子com  
這篇文章主要介紹了c++11 新特性——智能指針使用的相關(guān)資料,幫助大家更好的理解和使用c++,感興趣的朋友可以了解下

c++11添加了新的智能指針,unique_ptr、shared_ptr和weak_ptr,同時(shí)也將auto_ptr置為廢棄(deprecated)。

但是在實(shí)際的使用過(guò)程中,很多人都會(huì)有這樣的問(wèn)題:

  1. 不知道三種智能指針的具體使用場(chǎng)景
  2. 無(wú)腦只使用shared_ptr
  3. 認(rèn)為應(yīng)該禁用raw pointer(裸指針,即Widget*這種形式),全部使用智能指針

初始化方法

class A
{
public:
  A(int size){ this->size = size; }
  A(){}
  void Show()
  {
    std::cout << "A::" << size << __FUNCTION__ << std::endl;
  }
private:
  int size = 5;
};
...
  //[1]
	auto p1 = std::make_shared<int>();
  auto p2 = std::make_shared<A>();
  //[2]
  std::shared_ptr<int> p3(new int(5));
  std::shared_ptr<A> p4(new A());
  //[3]
  std::shared_ptr<int> p5;
  p5.reset(new int(5));
  std::shared_ptr<A> p6;
  p6.reset(new A());

推薦使用第一種方法~

使用場(chǎng)景

  • unique_ptr

忘記delete

class Box{
public:
  Box() : w(new Widget())
  {}
  ~Box()
  {
    // 忘記delete w
  }
private:
  Widget* w;
};

異常安全

void process()
{
  Widget* w = new Widget();
  w->do_something(); // 可能會(huì)發(fā)生異常
  delete w;
}
  • shared_ptr

shared_ptr通常使用在共享權(quán)不明的場(chǎng)景。有可能多個(gè)對(duì)象同時(shí)管理同一個(gè)內(nèi)存時(shí)。
對(duì)象的延遲銷毀。陳碩在《Linux多線程服務(wù)器端編程》中提到,當(dāng)一個(gè)對(duì)象的析構(gòu)非常耗時(shí),甚至影響到了關(guān)鍵線程的速度??梢允褂肂lockingQueue<std::shared_ptr<void>>將對(duì)象轉(zhuǎn)移到另外一個(gè)線程中釋放,從而解放關(guān)鍵線程。

  • weak_ptr

weak_ptr是為了解決shared_ptr雙向引用的問(wèn)題。即:

class B;
struct A{
  shared_ptr<B> b;
};
struct B{
  shared_ptr<A> a;
};
auto pa = make_shared<A>();
auto pb = make_shared<B>();
pa->b = pb;
pb->a = pa;

pa和pb存在著循環(huán)引用,根據(jù)shared_ptr引用計(jì)數(shù)的原理,pa和pb都無(wú)法被正常的釋放。

對(duì)于這種情況, 我們可以使用weak_ptr:

class B;
struct A{
  shared_ptr<B> b;
};
struct B{
  weak_ptr<A> a;
};
auto pa = make_shared<A>();
auto pb = make_shared<B>();
pa->b = pb;
pb->a = pa;

weak_ptr不會(huì)增加引用計(jì)數(shù),因此可以打破shared_ptr的循環(huán)引用。

通常做法是parent類持有child的shared_ptr, child持有指向parent的weak_ptr。這樣也更符合語(yǔ)義。

性能

1.unique_ptr

因?yàn)镃++的zero cost abstraction的特點(diǎn),unique_ptr在默認(rèn)情況下和裸指針的大小是一樣的。

所以內(nèi)存上沒(méi)有任何的額外消耗,性能是最優(yōu)的。

2.shared_ptr

  1. 存占用高 shared_ptr的內(nèi)存占用是裸指針的兩倍。因?yàn)槌艘芾硪粋€(gè)裸指針外,還要維護(hù)一個(gè)引用計(jì)數(shù)。 因此相比于unique_ptr, shared_ptr的內(nèi)存占用更高
  2. 原子操作性能低 考慮到線程安全問(wèn)題,引用計(jì)數(shù)的增減必須是原子操作。而原子操作一般情況下都比非原子操作慢。
  3. 使用移動(dòng)優(yōu)化性能 shared_ptr在性能上固然是低于unique_ptr。而通常情況,我們也可以盡量避免shared_ptr復(fù)制。 如果,一個(gè)shared_ptr需要將所有權(quán)共享給另外一個(gè)新的shared_ptr,而我們確定在之后的代碼中都不再使用這個(gè)shared_ptr,那么這是一個(gè)非常鮮明的移動(dòng)語(yǔ)義。 對(duì)于此種場(chǎng)景,我們盡量使用std::move,將shared_ptr轉(zhuǎn)移給新的對(duì)象。因?yàn)橐苿?dòng)不用增加引用計(jì)數(shù),因此性能比復(fù)制更好。

對(duì)象所有權(quán)

首先需要理清楚的概念就是對(duì)象所有權(quán)的概念。所有權(quán)在rust語(yǔ)言中非常嚴(yán)格,寫rust的時(shí)候必須要清楚自己創(chuàng)建的每個(gè)對(duì)象的所有權(quán)。

但是C++比較自由,似乎我們不需要明白對(duì)象的所有權(quán),寫的代碼也能正常運(yùn)行。但是明白了對(duì)象所有權(quán),我們才可以正確管理好對(duì)象生命周期和內(nèi)存問(wèn)題。

C++引入了智能指針,也是為了更好的描述對(duì)象所有權(quán),簡(jiǎn)化內(nèi)存管理,從而大大減少我們C++內(nèi)存管理方面的犯錯(cuò)機(jī)會(huì)。

  • unique_ptr

我們大多數(shù)場(chǎng)景下用到的應(yīng)該都是unique_ptr。

unique_ptr代表的是專屬所有權(quán),即由unique_ptr管理的內(nèi)存,只能被一個(gè)對(duì)象持有。

所以,unique_ptr不支持復(fù)制和賦值,如下:

auto w = std::make_unique<Widget>();
auto w2 = w; // 編譯錯(cuò)誤

如果想要把w復(fù)制給w2, 是不可以的。因?yàn)閺?fù)制從語(yǔ)義上來(lái)說(shuō),兩個(gè)對(duì)象將共享同一塊內(nèi)存。

因此,unique_ptr只支持移動(dòng), 即如下:

auto w = std::make_unique<Widget>();
auto w2 = std::move(w); // w2獲得內(nèi)存所有權(quán),w此時(shí)等于nullptr

unique_ptr代表的是專屬所有權(quán),如果想要把一個(gè)unique_ptr的內(nèi)存交給另外一個(gè)unique_ptr對(duì)象管理。只能使用std::move轉(zhuǎn)移當(dāng)前對(duì)象的所有權(quán)。轉(zhuǎn)移之后,當(dāng)前對(duì)象不再持有此內(nèi)存,新的對(duì)象將獲得專屬所有權(quán)。

如上代碼中,將w對(duì)象的所有權(quán)轉(zhuǎn)移給w2后,w此時(shí)等于nullptr,而w2獲得了專屬所有權(quán)。

  • shared_ptr

在使用shared_ptr之前應(yīng)該考慮,是否真的需要使用shared_ptr, 而非unique_ptr。

shared_ptr代表的是共享所有權(quán),即多個(gè)shared_ptr可以共享同一塊內(nèi)存。

因此,從語(yǔ)義上來(lái)看,shared_ptr是支持復(fù)制的。如下:

auto w = std::make_shared<Widget>();
{
  auto w2 = w;
  cout << w.use_count() << endl; // 2
} 
cout << w.use_count() << endl; // 1

shared_ptr內(nèi)部是利用引用計(jì)數(shù)來(lái)實(shí)現(xiàn)內(nèi)存的自動(dòng)管理,每當(dāng)復(fù)制一個(gè)shared_ptr,引用計(jì)數(shù)會(huì)+1。當(dāng)一個(gè)shared_ptr離開(kāi)作用域時(shí),引用計(jì)數(shù)會(huì)-1。當(dāng)引用計(jì)數(shù)為0的時(shí)候,則delete內(nèi)存。

同時(shí),shared_ptr也支持移動(dòng)。從語(yǔ)義上來(lái)看,移動(dòng)指的是所有權(quán)的傳遞。如下:

auto w = std::make_shared<Widget>();
auto w2 = std::move(w); // 此時(shí)w等于nullptr,w2.use_count()等于1

我們將w對(duì)象move給w2,意味著w放棄了對(duì)內(nèi)存的所有權(quán)和管理,此時(shí)w對(duì)象等于nullptr。

而w2獲得了對(duì)象所有權(quán),但因?yàn)榇藭r(shí)w已不再持有對(duì)象,因此w2的引用計(jì)數(shù)為1。

指針作為函數(shù)傳參

只在函數(shù)使用指針,但并不保存

假如我們只需要在函數(shù)中,用這個(gè)對(duì)象處理一些事情,但不打算涉及其生命周期的管理,不打算通過(guò)函數(shù)傳參延長(zhǎng)shared_ptr的生命周期。

對(duì)于這種情況,可以使用raw pointer或者const shared_ptr&。

即:

void func(Widget*);
void func(const shared_ptr<Widget>&)

​ 實(shí)際上第一種裸指針的方式可能更好,從語(yǔ)義上更加清楚,函數(shù)也不用關(guān)心智能指針的類型。

在函數(shù)中保存智能指針

假如我們需要在函數(shù)中把這個(gè)智能指針保存起來(lái),這個(gè)時(shí)候建議直接傳值。void func(std::shared_ptr ptr);這樣的話,外部傳過(guò)來(lái)值的時(shí)候,可以選擇move或者賦值。函數(shù)內(nèi)部直接把這個(gè)對(duì)象通過(guò)move的方式保存起來(lái)。 這樣性能更好,而且外部調(diào)用也有多種選擇。

為什么要用shared_from_this

我們往往會(huì)需要在類內(nèi)部使用自身的shared_ptr,例如:

class A
{
public:
private:
  std::shared_ptr<widget> widget;
}

class Widget
{
public:
  void do_something(A& a)
  {
    a.widget = std::make_shared<Widget>(this);
  }
}

我們需要把當(dāng)前shared_ptr對(duì)象同時(shí)交由對(duì)象a進(jìn)行管理。意味著,當(dāng)前對(duì)象的生命周期的結(jié)束不能早于對(duì)象a。因?yàn)閷?duì)象a在析構(gòu)之前還是有可能會(huì)使用到a.widget。

如果我們直接a.widget = this;, 那肯定不行, 因?yàn)檫@樣并沒(méi)有增加當(dāng)前shared_ptr的引用計(jì)數(shù)。shared_ptr還是有可能早于對(duì)象a釋放。

如果我們使用a.widget = std::make_shared<Widget>(this);,肯定也不行,因?yàn)檫@個(gè)新創(chuàng)建的shared_ptr,跟當(dāng)前對(duì)象的shared_ptr毫無(wú)關(guān)系。當(dāng)前對(duì)象的shared_ptr生命周期結(jié)束后,依然會(huì)釋放掉當(dāng)前內(nèi)存,那么之后a.widget依然是不合法的。

對(duì)于這種,需要在對(duì)象內(nèi)部獲取該對(duì)象自身的shared_ptr, 那么該類必須繼承std::enable_shared_from_this<T>。代碼如下:

class Widget : public std::enable_shared_from_this<Widget>
{
public:
  void do_something(A& a)
  {
    a.widget = shared_from_this();
  }  
}

這樣才是合法的做法。

總結(jié)

1.重點(diǎn)理解三種智能指針的使用場(chǎng)景,

  • unique_ptr性能高,沒(méi)有特殊要求的話可以直接用來(lái)取代raw pointer(原始指針)。
  • shared_ptr開(kāi)銷大,在前者不能滿足的場(chǎng)景例如需要多個(gè)智能指針同時(shí)擁有同一個(gè)控件的所有權(quán)的時(shí)候使用。
  • weak_ptr不單獨(dú)使用,通常用來(lái)配合shared_ptr使用,避免循環(huán)引用的問(wèn)題。

2.優(yōu)點(diǎn):

不用手動(dòng)管理內(nèi)存,尤其是根本不知道釋放時(shí)機(jī)的時(shí)候

3.缺點(diǎn):

shared_ptr的內(nèi)存占用高(多了一個(gè)引用計(jì)數(shù)),對(duì)多線程不友好(對(duì)引用計(jì)數(shù)的操作要原子性)

寫起來(lái)麻煩

以上就是c++11 新特性——智能指針使用詳解的詳細(xì)內(nèi)容,更多關(guān)于c++ 智能指針的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++實(shí)現(xiàn)LeetCode(61.旋轉(zhuǎn)鏈表)

    C++實(shí)現(xiàn)LeetCode(61.旋轉(zhuǎn)鏈表)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(61.旋轉(zhuǎn)鏈表),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 實(shí)現(xiàn)C語(yǔ)言常用字符串庫(kù)函數(shù)

    實(shí)現(xiàn)C語(yǔ)言常用字符串庫(kù)函數(shù)

    這篇文章主要為大家介紹了如何實(shí)現(xiàn)C語(yǔ)言常用字符串庫(kù)函數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2021-11-11
  • C語(yǔ)言常見(jiàn)排序算法歸并排序

    C語(yǔ)言常見(jiàn)排序算法歸并排序

    這篇文章主要介紹了C語(yǔ)言常見(jiàn)排序算法歸并排序,歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法的一個(gè)非常典型的應(yīng)用
    2022-07-07
  • C++?OpenMP簡(jiǎn)單介紹

    C++?OpenMP簡(jiǎn)單介紹

    這篇文章主要介紹了C++?OpenMP簡(jiǎn)介,OpenMP?還支持自定義數(shù)據(jù)類型的歸約操作,需要通過(guò)omp?declare?reduction指令來(lái)聲明自定義操作符和數(shù)據(jù)類型的歸約方式,感興趣的朋友一起看看吧
    2023-05-05
  • 詳解C語(yǔ)言fscanf函數(shù)讀取文件教程及源碼

    詳解C語(yǔ)言fscanf函數(shù)讀取文件教程及源碼

    這篇文章主要為大家介紹了詳解C語(yǔ)言算法fscanf讀取文件示例教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • Windows的鉤子機(jī)制詳解

    Windows的鉤子機(jī)制詳解

    這篇文章主要介紹了Windows的鉤子機(jī)制,對(duì)于初學(xué)者進(jìn)一步了解windows程序設(shè)計(jì)中鉤子的原理及運(yùn)用有很大的幫助,需要的朋友可以參考下
    2014-07-07
  • C++淺析函數(shù)重載是什么

    C++淺析函數(shù)重載是什么

    C++?允許多個(gè)函數(shù)擁有相同的名字,只要它們的參數(shù)列表不同就可以,這就是函數(shù)的重載(Function?Overloading),借助重載,一個(gè)函數(shù)名可以有多種用途
    2022-08-08
  • 用C語(yǔ)言實(shí)現(xiàn)單鏈表的各種操作(一)

    用C語(yǔ)言實(shí)現(xiàn)單鏈表的各種操作(一)

    本篇文章是對(duì)用C語(yǔ)言實(shí)現(xiàn)單鏈表的各種操作進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)不掛科指南之線性表詳解

    C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)不掛科指南之線性表詳解

    線性表是由?n(n≥0)個(gè)數(shù)據(jù)元素組成的有窮序列,這篇文章主要來(lái)和大家來(lái)了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)中的線性表,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-09-09
  • Qt實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出到xls的示例代碼

    Qt實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出到xls的示例代碼

    導(dǎo)入導(dǎo)出數(shù)據(jù)到csv由于語(yǔ)法簡(jiǎn)單,適用場(chǎng)景有限,于是本文將為大家介紹Qt如何實(shí)現(xiàn)導(dǎo)出數(shù)據(jù)到xls,感興趣的小伙伴可以跟隨小編一起試一試
    2022-01-01

最新評(píng)論