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

c++11&14-智能指針要點匯總

 更新時間:2020年06月03日 08:49:40   作者:晟夏的葉  
這篇文章主要介紹了c++11&14-智能指針的要點,文中代碼非常詳細,供大家學習和參考,感興趣的朋友可以了解下

學c++的人都知道,在c++里面有一個痛點,就是動態(tài)內(nèi)存的管理,就我所經(jīng)歷的一些問題來看,很多莫名其妙的問題,最后都發(fā)現(xiàn)是內(nèi)存管理不當引起的。

但像java等其他一些語言則不會有這樣的問題,為什么呢,因為它們有很好的處理內(nèi)存的方法,比如java的垃圾回收機制,現(xiàn)在,我們c++終于也有了智能指針。

1. 什么是智能指針

簡單地說,智能指針是用對象去管理一個資源指針,同時用一個計數(shù)器計算引用當前指針對象的個數(shù),當管理指針的對象增加或減少時,計數(shù)器也相應加1或減1,當最后一個指針管理對象銷毀時,計數(shù)器為1,此時在銷毀指針管理對象的同時,也對指針管理對象所管理的指針進行delete操作。

下面我們介紹兩個常用的智能指針std::shared_ptr和std::weak_ptr。

1.1 std::shared_ptr

std::shared_ptr包裝了new操作符動態(tài)分配的內(nèi)存,可以自由拷貝復制,基本上是使用最多的一個智能指針類型。

下面是一個代碼例子:

#include <memory>
#include <iostream>
class Test
{
public:
  Test()
  {
    std::cout << "Test()" << std::endl;
  }
  ~Test()
  {
    std::cout << "~Test()" << std::endl;
  }
};
int main()
{
  std::shared_ptr<Test> p1 = std::make_shared<Test>();
  std::cout << "1 ref:" << p1.use_count() << std::endl;
  {
    std::shared_ptr<Test> p2 = p1;
    std::cout << "2 ref:" << p1.use_count() << std::endl;
  }
  std::cout << "3 ref:" << p1.use_count() << std::endl;
  return 0;
}

結(jié)果如下:

Test()
1 ref:1
2 ref:2
3 ref:1
~Test()

針對代碼解讀如下:

std::make_shared里面調(diào)用了new操作符分配內(nèi)存;
第二個p1.use_count()之所以顯示為2,是因為增加了引用對象p2,而隨著大括號的結(jié)束,p2的作用域結(jié)束,所以p1的引用計數(shù)變回1,而隨著main函數(shù)的結(jié)束,p1的作用域結(jié)束,此時檢測到計數(shù)為1,那就會在銷毀p1的同時,調(diào)用p1的析構(gòu)函數(shù)delete掉之前分配的內(nèi)存空間;

1.2 std::weak_ptr

std::weak_ptr有什么特點呢?與std::shared_ptr最大的差別是在賦值的時候,不會引起智能指針計數(shù)增加。

weak_ptr被設計為與shared_ptr共同工作,可以從一個shared_ptr或者另一個weak_ptr對象構(gòu)造,獲得資源的觀測權。但weak_ptr沒有共享資源,它的構(gòu)造不會引起指針引用計數(shù)的增加。同樣,在weak_ptr析構(gòu)時也不會導致引用計數(shù)的減少,它只是一個靜靜地觀察者。weak_ptr沒有重載operator*和->,這是特意的,因為它不共享指針,不能操作資源,這是它弱的原因。如要操作資源,則必須使用一個非常重要的成員函數(shù)lock()從被觀測的shared_ptr獲得一個可用的shared_ptr對象,從而操作資源。

1.2.1 std::shared_ptr相互引用會有什么后果

代碼如下:

#include <memory>
#include <iostream>
class TestB;
class TestA
{
public:
  TestA()
  {
    std::cout << "TestA()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestB> test_ptr)
  {
    m_TestB_Ptr = test_ptr;
  }
  ~TestA()
  {
    std::cout << "~TestA()" << std::endl;
  }
private:
  std::shared_ptr<TestB> m_TestB_Ptr; //TestB的智能指針
}; 
class TestB
{
public:
  TestB()
  {
    std::cout << "TestB()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestA> test_ptr)
  {
    m_TestA_Ptr = test_ptr;
  }
  ~TestB()
  {
    std::cout << "~TestB()" << std::endl;
  }
  std::shared_ptr<TestA> m_TestA_Ptr; //TestA的智能指針
};
int main()
{
  std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
  std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
  ptr_a->ReferTestB(ptr_b);
  ptr_b->ReferTestB(ptr_a);
  return 0;
}

運行結(jié)果:

TestA()
TestB()

可以看到,上面代碼中,我們創(chuàng)建了一個TestA和一個TestB的對象,但在整個main函數(shù)都運行完后,都沒看到兩個對象被析構(gòu),這是為什么呢?

原來,智能指針ptr_a中引用了ptr_b,同樣ptr_b中也引用了ptr_a,在main函數(shù)退出前,ptr_a和ptr_b的引用計數(shù)均為2,退出main函數(shù)后,引用計數(shù)均變?yōu)?,也就是相互引用。

這等效于說:

ptr_a對ptr_b說,哎,我說ptr_b,我現(xiàn)在的條件是,你先釋放我,我才能釋放你,這是天生的,造物者決定的,改不了;
ptr_b也對ptr_a說,我的條件也是一樣,你先釋放我,我才能釋放你,怎么辦?
是吧,大家都沒錯,相互引用導致的問題就是釋放條件的沖突,最終也可能導致內(nèi)存泄漏。

1.2.2 std::weak_ptr如何解決相互引用的問題

我們在上面的代碼基礎上使用std::weak_ptr進行修改,如下:

#include <iostream>
#include <memory>
class TestB;
class TestA
{
public:
  TestA()
  {
    std::cout << "TestA()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestB> test_ptr)
  {
    m_TestB_Ptr = test_ptr;
  }
  void TestWork()
  {
    std::cout << "~TestA::TestWork()" << std::endl;
  }
  ~TestA()
  {
    std::cout << "~TestA()" << std::endl;
  }
private:
  std::weak_ptr<TestB> m_TestB_Ptr;
};
class TestB
{
public:
  TestB()
  {
    std::cout << "TestB()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestA> test_ptr)
  {
    m_TestA_Ptr = test_ptr;
  }
  void TestWork()
  {
    std::cout << "~TestB::TestWork()" << std::endl;
  }
  ~TestB()
  {
		////把std::weak_ptr類型轉(zhuǎn)換成std::shared_ptr類型
    std::shared_ptr<TestA> tmp = m_TestA_Ptr.lock();
    tmp->TestWork();
    std::cout << "2 ref a:" << tmp.use_count() << std::endl;
    std::cout << "~TestB()" << std::endl;
  }
  std::weak_ptr<TestA> m_TestA_Ptr;
};
int main()
{
  std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
  std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
  ptr_a->ReferTestB(ptr_b);
  ptr_b->ReferTestB(ptr_a);
  std::cout << "1 ref a:" << ptr_a.use_count() << std::endl;
  std::cout << "1 ref b:" << ptr_a.use_count() << std::endl;
  return 0;
}

運行結(jié)果:

TestA()
TestB()
1 ref a:1
1 ref b:1
~TestA::TestWork()
2 ref a:2
~TestB()
~TestA()

預覽
由以上代碼運行結(jié)果我們可以看到:

所有的對象最后都能正常釋放,不會存在上一個例子中的內(nèi)存沒有釋放的問題;
ptr_aptr_b在main函數(shù)中退出前,引用計數(shù)均為1,也就是說,在TestATestB中對std::weak_ptr的相互引用,不會導致計數(shù)的增加。在TestB析構(gòu)函數(shù)中,調(diào)用std::shared_ptr tmp = m_TestA_Ptr.lock(),std::weak_ptr類型轉(zhuǎn)換成std::shared_ptr類型,然后對TestA對象進行調(diào)用。

1.2.3 std::weak_ptr支持的調(diào)用

weak_ptr<T> w;	//空weak_ptr可以指向類型為T的對象
weak_ptr<T> w(shared_ptr sp);	//與sp指向相同對象的weak_ptr, T必須能轉(zhuǎn)換為sp指向的類型
w = p;	//p可以是shared_ptr或者weak_ptr,賦值后w和p共享對象
w.reset();	//weak_ptr置為空
w.use_count();	//與w共享對象的shared_ptr的計數(shù)
w.expired();	//w.use_count()為0則返回true,否則返回false
w.lock();	//w.expired()為true,返回空的shared_ptr;否則返回指向w的shared_ptr

1.3 std::unique_ptr

uniqut_ptr是一種對資源具有排他性擁有權的智能指針,即一個對象資源只能同時被一個unique_ptr指向。

1.3.1 初始化方式

使用new

T *pT = new T();
std::unique_ptr<T> up1(pT);

通過make_unique

auto pT = make_unique<T>();

通過move()函數(shù)

//up也是一個std::unique_ptr<T>指針
unique_ptr<T> up1 = std::move(up); 

1.3.2 unique_ptr不能被復制或者拷貝

unique_ptr<T> up(new T()); //ok
unique_ptr<T> up1(up); //error, can not be copy
unique_ptr<T> up2 = up; //error, can not be assigned

1.3.3 unique_ptr可以移動賦值或者移動拷貝

unique_ptr<T> pT(new T());
unique_ptr<T> pT2 = std::move(pT);	//移動賦值,此時pT被銷毀,為空
unique_ptr<T> pT3(std::move(pt2)); //移動拷貝,此時pT2被銷毀,為空

1.3.4 unique_ptr可以作為函數(shù)的返回值

unique_ptr<T> GetPtr(); //function getthe unique pointer
unique_ptr<T> pT = GetPtr(); // ok

1.3.5 使用范例

#include <iostream>
int main()
{
	std::unique_ptr<int> pInt;
	pInt.reset(new int());
	int *p = pInt.release(); //釋放所有權
	//由于unique_ptr有std::unique_ptr<T[]>的重載函數(shù),所以它可以用來管理數(shù)組資源
	std::unique_ptr<int[]> pArray(new int[3]{1,3,3}); 
}

2. 智能指針小結(jié)

可以看出,智能指針其實是std::shared_ptr和std::unique_ptr, std::shared_ptr可以有多個引用對象,但不能互相引用,而std::unique_ptr只能有一個引用,不能賦值或者拷貝,但可以移動賦值和移動拷貝,std::weak_ptr實際上是對std::shared_ptr的補充,它并不能對對象進行具體的操作。

注意:shared_ptr,weak_ptr,unique_ptr這些都是模板,并不是指針或者其他的。

以上就是c++11&14-智能指針要點匯總的詳細內(nèi)容,更多關于c++11&14 智能指針的資料請關注腳本之家其它相關文章!

相關文章

  • C++中靜態(tài)庫與動態(tài)庫的使用示例

    C++中靜態(tài)庫與動態(tài)庫的使用示例

    在C/C++中使用庫的技術,庫主要分為兩種類型:靜態(tài)庫和動態(tài)庫,本文主要介紹了C++中靜態(tài)庫與動態(tài)庫的使用示例,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • C++智能指針模板應用詳細介紹

    C++智能指針模板應用詳細介紹

    從比較簡單的層面來看,智能指針是RAII(Resource Acquisition Is Initialization,資源獲取即初始化)機制對普通指針進行的一層封裝。這樣使得智能指針的行為動作像一個指針,本質(zhì)上卻是一個對象,這樣可以方便管理一個對象的生命周期
    2022-08-08
  • 如何尋找數(shù)組中的第二大數(shù)

    如何尋找數(shù)組中的第二大數(shù)

    本篇文章是對如何尋找數(shù)組中的第二大數(shù)進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • 簡要對比C語言中的setgid()函數(shù)和setregid()函數(shù)

    簡要對比C語言中的setgid()函數(shù)和setregid()函數(shù)

    這篇文章主要介紹了C語言中的setgid()函數(shù)和setregid()函數(shù)的簡要對比,是C語言入門學習中的基礎知識,需要的朋友可以參考下
    2015-08-08
  • 深入淺析STL vector用法

    深入淺析STL vector用法

    這篇文章給大家介紹 stl vector用法,主要知識點在如何恰當?shù)氖褂盟鼈兊某蓡T函數(shù),涉及到條件函數(shù)和函數(shù)指針在迭代算法中的使用,對stl vector用法感興趣的朋友可以參考下本文
    2015-10-10
  • 關于C語言和命令行之間的交互問題

    關于C語言和命令行之間的交互問題

    這篇文章主要介紹了C語言和命令行之間的交互,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-07-07
  • 復數(shù)乘法中的結(jié)構(gòu)體賦值實現(xiàn)代碼

    復數(shù)乘法中的結(jié)構(gòu)體賦值實現(xiàn)代碼

    復數(shù)乘法中的結(jié)構(gòu)體賦值實現(xiàn)代碼。需要的朋友可以過來參考下,希望對大家有所幫助
    2013-10-10
  • C語言中進程間通訊的方式詳解

    C語言中進程間通訊的方式詳解

    這篇文章主要為大家詳細介紹了C語言中幾種進程間通訊的方式,文中的示例代碼講解詳細,?對我們學習或工作有一定的借鑒價值,需要的可以參考一下
    2022-08-08
  • C++指針與數(shù)組:指針詳解

    C++指針與數(shù)組:指針詳解

    本文從初學者的角度,深入淺出地講解C++中的指針、數(shù)組指針,對最常混淆的引用傳遞、值傳遞和指針傳遞做了區(qū)處,需要的朋友可以參考下
    2021-09-09
  • OpenCV利用對比度亮度變換實現(xiàn)水印去除

    OpenCV利用對比度亮度變換實現(xiàn)水印去除

    OpenCV中去除水印最常用的方法是inpaint,通過圖像修復的方法來去除水印。本文將介紹另一種方法:利用對比度亮度變換去除水印,需要的朋友可以參考一下
    2021-11-11

最新評論