最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

但是在實際的使用過程中,很多人都會有這樣的問題:

  1. 不知道三種智能指針的具體使用場景
  2. 無腦只使用shared_ptr
  3. 認為應該禁用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());

推薦使用第一種方法~

使用場景

  • 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(); // 可能會發(fā)生異常
  delete w;
}
  • shared_ptr

shared_ptr通常使用在共享權不明的場景。有可能多個對象同時管理同一個內存時。
對象的延遲銷毀。陳碩在《Linux多線程服務器端編程》中提到,當一個對象的析構非常耗時,甚至影響到了關鍵線程的速度??梢允褂肂lockingQueue<std::shared_ptr<void>>將對象轉移到另外一個線程中釋放,從而解放關鍵線程。

  • weak_ptr

weak_ptr是為了解決shared_ptr雙向引用的問題。即:

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)引用,根據shared_ptr引用計數(shù)的原理,pa和pb都無法被正常的釋放。

對于這種情況, 我們可以使用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不會增加引用計數(shù),因此可以打破shared_ptr的循環(huán)引用。

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

性能

1.unique_ptr

因為C++的zero cost abstraction的特點,unique_ptr在默認情況下和裸指針的大小是一樣的。

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

2.shared_ptr

  1. 存占用高 shared_ptr的內存占用是裸指針的兩倍。因為除了要管理一個裸指針外,還要維護一個引用計數(shù)。 因此相比于unique_ptr, shared_ptr的內存占用更高
  2. 原子操作性能低 考慮到線程安全問題,引用計數(shù)的增減必須是原子操作。而原子操作一般情況下都比非原子操作慢。
  3. 使用移動優(yōu)化性能 shared_ptr在性能上固然是低于unique_ptr。而通常情況,我們也可以盡量避免shared_ptr復制。 如果,一個shared_ptr需要將所有權共享給另外一個新的shared_ptr,而我們確定在之后的代碼中都不再使用這個shared_ptr,那么這是一個非常鮮明的移動語義。 對于此種場景,我們盡量使用std::move,將shared_ptr轉移給新的對象。因為移動不用增加引用計數(shù),因此性能比復制更好。

對象所有權

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

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

C++引入了智能指針,也是為了更好的描述對象所有權,簡化內存管理,從而大大減少我們C++內存管理方面的犯錯機會。

  • unique_ptr

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

unique_ptr代表的是專屬所有權,即由unique_ptr管理的內存,只能被一個對象持有。

所以,unique_ptr不支持復制和賦值,如下:

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

如果想要把w復制給w2, 是不可以的。因為復制從語義上來說,兩個對象將共享同一塊內存。

因此,unique_ptr只支持移動, 即如下:

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

unique_ptr代表的是專屬所有權,如果想要把一個unique_ptr的內存交給另外一個unique_ptr對象管理。只能使用std::move轉移當前對象的所有權。轉移之后,當前對象不再持有此內存,新的對象將獲得專屬所有權。

如上代碼中,將w對象的所有權轉移給w2后,w此時等于nullptr,而w2獲得了專屬所有權。

  • shared_ptr

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

shared_ptr代表的是共享所有權,即多個shared_ptr可以共享同一塊內存。

因此,從語義上來看,shared_ptr是支持復制的。如下:

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

shared_ptr內部是利用引用計數(shù)來實現(xiàn)內存的自動管理,每當復制一個shared_ptr,引用計數(shù)會+1。當一個shared_ptr離開作用域時,引用計數(shù)會-1。當引用計數(shù)為0的時候,則delete內存。

同時,shared_ptr也支持移動。從語義上來看,移動指的是所有權的傳遞。如下:

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

我們將w對象move給w2,意味著w放棄了對內存的所有權和管理,此時w對象等于nullptr。

而w2獲得了對象所有權,但因為此時w已不再持有對象,因此w2的引用計數(shù)為1。

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

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

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

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

即:

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

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

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

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

為什么要用shared_from_this

我們往往會需要在類內部使用自身的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);
  }
}

我們需要把當前shared_ptr對象同時交由對象a進行管理。意味著,當前對象的生命周期的結束不能早于對象a。因為對象a在析構之前還是有可能會使用到a.widget。

如果我們直接a.widget = this;, 那肯定不行, 因為這樣并沒有增加當前shared_ptr的引用計數(shù)。shared_ptr還是有可能早于對象a釋放。

如果我們使用a.widget = std::make_shared<Widget>(this);,肯定也不行,因為這個新創(chuàng)建的shared_ptr,跟當前對象的shared_ptr毫無關系。當前對象的shared_ptr生命周期結束后,依然會釋放掉當前內存,那么之后a.widget依然是不合法的。

對于這種,需要在對象內部獲取該對象自身的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();
  }  
}

這樣才是合法的做法。

總結

1.重點理解三種智能指針的使用場景,

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

2.優(yōu)點:

不用手動管理內存,尤其是根本不知道釋放時機的時候

3.缺點:

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

寫起來麻煩

以上就是c++11 新特性——智能指針使用詳解的詳細內容,更多關于c++ 智能指針的資料請關注腳本之家其它相關文章!

相關文章

  • C++實現(xiàn)LeetCode(132.拆分回文串之二)

    C++實現(xiàn)LeetCode(132.拆分回文串之二)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(132.拆分回文串之二),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-07-07
  • C++控制臺版掃雷游戲

    C++控制臺版掃雷游戲

    這篇文章主要為大家詳細介紹了C++控制臺版掃雷游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C++11中std::function基礎用法詳解

    C++11中std::function基礎用法詳解

    std::function是C++11標準庫中提供的一種可調用對象的通用類型,它可以存儲任意可調用對象,本文就來和大家講講它的基礎用法,希望對大家有所幫助
    2023-04-04
  • C語言線性表的順序表示與實現(xiàn)實例詳解

    C語言線性表的順序表示與實現(xiàn)實例詳解

    這篇文章主要介紹了C語言線性表的順序表示與實現(xiàn)實例詳解,對于學習數(shù)據結構與算法的朋友很有參考借鑒價值,需要的朋友可以參考下
    2014-07-07
  • 基于Qt編寫全能播放組件的示例代碼

    基于Qt編寫全能播放組件的示例代碼

    這篇文章主要為大家詳細介紹了如何基于Qt編寫全能播放組件,可以支持ffmpeg2/3/4/5/6/Qt4/5/6,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-06-06
  • C++中唯一三元運算符?:實例詳解

    C++中唯一三元運算符?:實例詳解

    這篇文章主要給大家介紹了關于C++中唯一三元運算符?:的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • C++實現(xiàn)簡單的掃雷游戲(控制臺版)

    C++實現(xiàn)簡單的掃雷游戲(控制臺版)

    這篇文章主要為大家詳細介紹了C++實現(xiàn)簡單的掃雷游戲,控制臺版的掃雷游戲希望大家喜歡,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • C++ boost::asio編程-異步TCP詳解及實例代碼

    C++ boost::asio編程-異步TCP詳解及實例代碼

    這篇文章主要介紹了C++ boost::asio編程-異步TCP詳解及實例代碼的相關資料,需要的朋友可以參考下
    2016-11-11
  • C++讀取配置文件的示例代碼

    C++讀取配置文件的示例代碼

    這篇文章主要介紹了C++讀取配置文件的示例代碼,幫助大家更好的理解和學習C++開發(fā),感興趣的朋友可以了解下
    2020-08-08
  • C++編程異常處理中try和throw以及catch語句的用法

    C++編程異常處理中try和throw以及catch語句的用法

    這篇文章主要介紹了C++編程異常處理中try和throw以及catch語句的用法,包括對Catch塊的計算方式的介紹,需要的朋友可以參考下
    2016-01-01

最新評論

马山县| 广元市| 望奎县| 清水县| 定远县| 上思县| 安塞县| 双流县| 镇坪县| 墨江| 深水埗区| 巨鹿县| 祁阳县| 阳春市| 吴川市| 枣庄市| 宜春市| 赤壁市| 嫩江县| 景泰县| 勐海县| 慈利县| 广宗县| 万源市| 浦城县| 宁蒗| 洞口县| 金华市| 临沭县| 乌兰浩特市| 鸡西市| 田阳县| 黄骅市| 松原市| 稻城县| 黑河市| 长垣县| 赤水市| 吴堡县| 东乌珠穆沁旗| 高雄市|