日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > 單片機 > 程序喵大人

最近,有同學(xué)來問我,想了解C++的三種智能指針的使用場景,在項目中應(yīng)該如何選擇?

首先要了解這三種智能指針的特點,std::unique_ptr、std::shared_ptrstd::weak_ptr

std::unique_ptr

std::unique_ptr是一種獨占所有權(quán)的智能指針,意味著同一時間內(nèi)只能有一個unique_ptr指向一個特定的對象。

當(dāng)unique_ptr被銷毀時,它所指向的對象也會被銷毀。

使用場景:

  • 當(dāng)你需要確保一個對象只被一個指針所擁有時。
  • 當(dāng)你需要自動管理資源,如文件句柄或互斥鎖時。
  • 當(dāng)你不確定用哪種智能指針時,優(yōu)先選擇unique_ptr就沒毛病。

示例代碼:

#include  #include   class Test { public: Test() { std::cout << "Test::Test()\n"; } ~Test() { std::cout << "Test::~Test()\n"; } void test() { std::cout << "Test::test()\n"; } };  int main() {  std::unique_ptr  ptr(new Test());  ptr->test();  // 當(dāng)ptr離開作用域時,它指向的對象會被自動銷毀  return0; } 

std::shared_ptr

std::shared_ptr是一種共享所有權(quán)的智能指針,多個shared_ptr可以指向同一個對象。內(nèi)部使用引用計數(shù)來確保只有當(dāng)最后一個指向?qū)ο蟮?/span>shared_ptr被銷毀時,對象才會被銷毀。

使用場景:

  • 當(dāng)你需要在多個所有者之間共享對象時。
  • 當(dāng)你需要通過復(fù)制構(gòu)造函數(shù)或賦值操作符來復(fù)制智能指針時。

示例代碼:

#include  #include   class Test { public: Test() { std::cout << "Test::Test()\n"; } ~Test() { std::cout << "Test::~Test()\n"; }void test() { std::cout << "Test::test()\n"; } };  int main() {  std::shared_ptrptr1(new Test());  std::shared_ptrptr2 = ptr1;  ptr1->test();  // 當(dāng)ptr1和ptr2離開作用域時,它們指向的對象會被自動銷毀  return0; } 

std::weak_ptr

std::weak_ptr是一種不擁有對象所有權(quán)的智能指針,它指向一個由std::shared_ptr管理的對象。weak_ptr用于解決shared_ptr之間的循環(huán)引用問題。

是另外一種智能指針,它是對 shared_ptr 的補充,std::weak_ptr 是一種弱引用智能指針,用于觀察 std::shared_ptr 指向的對象,而不影響引用計數(shù)。它主要用于解決循環(huán)引用問題,從而避免內(nèi)存泄漏,另外如果需要追蹤指向某個對象的第一個指針,則可以使用 weak_ptr。

可以考慮在對象本身中維護一個指向第一個 shared_ptr 的弱引用(std::weak_ptr)。當(dāng)創(chuàng)建對象的第一個 shared_ptr 時,將這個 shared_ptr 賦值給對象的 weak_ptr 成員。這樣,在需要時,可以通過檢查對象的 weak_ptr 成員來獲取指向?qū)ο蟮牡谝粋€ shared_ptr(如果仍然存在的話).

使用場景:

  • 當(dāng)你需要訪問但不擁有由shared_ptr管理的對象時。
  • 當(dāng)你需要解決shared_ptr之間的循環(huán)引用問題時。
  • 注意weak_ptr肯定要和shared_ptr搭配使用。

示例代碼:

#include  #include   class Test { public: Test() { std::cout << "Test::Test()\n"; } ~Test() { std::cout << "Test::~Test()\n"; }void test() { std::cout << "Test::test()\n"; } };  int main() {  std::shared_ptrsharedPtr(new Test());  std::weak_ptrweakPtr = sharedPtr;   if (auto lockedSharedPtr = weakPtr.lock()) {  lockedSharedPtr->test();  }// 當(dāng)sharedPtr離開作用域時,它指向的對象會被自動銷毀  return0; } 

這三種智能指針各有其用途,選擇哪一種取決于你的具體需求。

1)智能指針方面的建議:

  • 盡量使用智能指針,而非裸指針來管理內(nèi)存,很多時候利用RAII機制管理內(nèi)存肯定更靠譜安全的多。
  • 如果沒有多個所有者共享對象的需求,建議優(yōu)先使用unique_ptr管理內(nèi)存,它相對shared_ptr會更輕量一些。
  • 在使用shared_ptr時,一定要注意是否有循環(huán)引用的問題,因為這會導(dǎo)致內(nèi)存泄漏。
  • shared_ptr的引用計數(shù)是安全的,但是里面的對象不是線程安全的,這點要區(qū)別開。

2)為什么std::unique_ptr可以做到不可復(fù)制,只可移動?

因為把拷貝構(gòu)造函數(shù)和賦值運算符標記為了delete,見源碼:

template <typename _Tp, typename _Tp_Deleter = default_delete>  class unique_ptr { // Disable copy from lvalue. unique_ptr(const unique_ptr&) = delete;  template<typename _Up, typename _Up_Deleter>  unique_ptr(const unique_ptr<_Up, _Up_Deleter>&) = delete;  unique_ptr& operator=(const unique_ptr&) = delete;  template<typename _Up, typename _Up_Deleter>  unique_ptr& operator=(const unique_ptr<_Up, _Up_Deleter>&) = delete; }; 

3)shared_ptr的原理:

每個 std::shared_ptr 對象包含兩個成員變量:一個指向被管理對象的原始指針,一個指向引用計數(shù)塊的指針(control block pointer)。

引用計數(shù)塊是一個單獨的內(nèi)存塊,引用計數(shù)塊允許多個 std::shared_ptr 對象共享相同的引用計數(shù),從而實現(xiàn)共享所有權(quán)。

當(dāng)創(chuàng)建一個新的 std::shared_ptr 時,引用計數(shù)初始化為 1,表示對象當(dāng)前被一個 shared_ptr 管理。

  1. 拷貝 std::shared_ptr:當(dāng)用一個 shared_ptr 拷貝出另一個 shared_ptr 時,需要拷貝兩個成員變量(被管理對象的原始指針和引用計數(shù)塊的指針),并同時將引用計數(shù)值加 1。這樣,多個 shared_ptr 對象可以共享相同的引用計數(shù)。
  2. 析構(gòu) std::shared_ptr:當(dāng) shared_ptr 對象析構(gòu)時,引用計數(shù)值減 1。然后檢測引用計數(shù)是否為 0。如果引用計數(shù)為 0,說明沒有其他 shared_ptr 對象指向該資源,因此需要同時刪除原始對象(通過調(diào)用自定義刪除器,如果有的話)。

4)智能指針的缺點

  1. 性能開銷,需要額外的內(nèi)存來存儲他們的控制塊,控制塊包括引用計數(shù),以及運行時的原子操作來增加或減少引用技術(shù),這可能導(dǎo)致裸指針的性能下降。
  2. 循環(huán)引用問題,如果兩個對象通過成員變量shared_ptr相互引用,并且沒有其他指針指向這兩個對象中的任何一個,那么這兩個對象的內(nèi)存將永遠不會被釋放,導(dǎo)致內(nèi)存泄露。
#include #include class B;// 前向聲明  class A { public: std::shared_ptr b_ptr; ~A() {  std::cout << "A has been destroyed."<< std::endl; } };  class B { public: std::shared_ptr a_ptr; ~B() {  std::cout << "B has been destroyed."<< std::endl; } };  int main() {  std::shared_ptr a = std::make_shared();  std::shared_ptr b = std::make_shared();  a->b_ptr = b; // A 引用 B  b->a_ptr = a; // B 引用 A  // 由于存在循環(huán)引用,A 和 B 的析構(gòu)函數(shù)將不會被調(diào)用,從而導(dǎo)致內(nèi)存泄漏  return0; } 
  1. 智能指針不一定適用于所有場景:有一些容器類,內(nèi)部實現(xiàn)依賴于裸指針,另外在考慮某些性能關(guān)鍵場景下,使用裸指針可能更合適。但絕大多數(shù)場景,用智能指針就OK。

選型建議

  1. 默認選擇unique_ptr,因為它性能最優(yōu),且語義清晰,比如局部動態(tài)對象。
  2. 當(dāng)你發(fā)現(xiàn)unique_ptr使用受限,那大概率就是有需要共享的需求,需要多個模塊或?qū)ο笮韫蚕硗毁Y源時(如全局配置、線程間共享數(shù)據(jù)),使用shared_ptr,但要注意循環(huán)引用的問題。
  3. 優(yōu)先使用make_uniquemake_shared構(gòu)造對應(yīng)的智能指針,具備異常安全性。
  4. 避免裸指針和智能指針混用,容易出現(xiàn)double free等問題。
  5. unique_ptr放心使用,并沒有額外開銷。
  6. shared_ptr 的引用計數(shù)可能引發(fā)原子操作開銷,除非對性能有非常極致的要求,否則沒必要在意這點開銷。也要注意循環(huán)引用會導(dǎo)致內(nèi)存泄漏。


本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉