實戰:單例的析構,為什么可以析構,重復析構等注意事項


 

1.為什么可以析構?

我對單例模式的理解:

在單例類對象的生命周期內,只有一個單例類的對象,所以我可以讓單例類對象生,也可以讓它死,只要保證單例類對象生的時候,只有一個對象就行。

讓單例類對象死,就得需要接口,即在外部調用delete。

 

2.單例的析構-實驗, 以及注意事項

注意事項: 不要重復調用析構函數,那樣會導致程序奔潰

代碼:

singleton_delete.cpp

#include <iostream>
#include "singleton_delete.hpp"
#include <unistd.h>
using namespace std;

key_inputdev* key_inputdev::pkey_inputdev_instance = NULL;

key_inputdev::key_inputdev() {    
    cout << "key_inputdev() Created !!" << endl;
}

key_inputdev::~key_inputdev() { 
    cout << "~key_inputdev() Gone !!" << endl;
    //delete pkey_inputdev_instance;  
   // 實測,main函數內deletedelete單例指針以后,這里析構函數內就不需要再次delete了。
   //     在main函數內delete單例指針后就已經釋放了該類對象的內存。
    pkey_inputdev_instance = NULL;
}

key_inputdev* key_inputdev::pkey_inputdev_construct_instance(){
    //boost::unique_lock<boost::mutex> lock(mutex_singleton);
    if(pkey_inputdev_instance == NULL)  {

        std::cout << "Go To Create the key_inputdev " <<  std::endl;
        pkey_inputdev_instance = new key_inputdev;
    }
    return pkey_inputdev_instance;
}
int main(){

  while(1){
   key_inputdev*  pobj = key_inputdev::pkey_inputdev_construct_instance();
   delete pobj;

   sleep(1);
   cout << endl << endl;

  }
  return 0;
}

singleton_delete.hpp

#ifndef singleton_delete_hpp
#define singleton_delete_hpp

class key_inputdev{
     
   key_inputdev(); 
public:
    ~key_inputdev();
    static key_inputdev* pkey_inputdev_construct_instance();

    static key_inputdev* pkey_inputdev_instance;
};

#endif

makefile

.PHONY : do

do:
    g++ *.cpp *.hpp -o ab
    #mips-linux-gnu-g++  *.cpp  *.hpp  -o  ab

下面是代碼截圖:

 為什么不能在單例類的析構函數內再次調用delete單例類指針? 

 知識點,需要深刻理解delete的含義: delete提供兩個功能=》1,根據后面跟的地址值來釋放內存     2,調用析構函數。

因為那樣會造成反復調用單例類的析構函數,形成套娃現象,導致程序奔潰。

 

在搞不清楚一些內存是否已經釋放的情況下,有這樣一個檢測內存泄漏的小技巧: 

再次嘗試delete那片內存,如果程序運行奔潰,說明已經是二次重復釋放了,如果程序正常運行,說明之前的內存並未釋放。

 

3.增補實驗

 在有些情況下我們需要在析構函數內部去釋放內存,這是很基本的常識:

 析構函數的函數體的職責是去釋放類對象構造時以及工作過程中申請到的系統資源,因為此時類對象的生命周期結束了,所占資源要歸還給操作系統!

 下面貼一個例子作為補充。

#include <iostream>

class myclass{
    int* pri;
public:
    myclass(){
    pri = new int(100);
    }
    ~myclass(){
    delete pri;
    }

    int* GetP(){ // 不合理的接口
    return pri;
    }
};

int main(){
  myclass* pobj = new myclass;
#if 0  
  delete pobj; // 代碼運行無段錯誤,且pobj對象的內存空間和pri所指向的內存,均被釋放。
#endif

#if 0
  int* p = pobj->GetP();
  delete p;   // 代碼運行無段錯誤,pri所指向的內存被釋放。
#endif

#if 1
  int* p = pobj->GetP();
  delete p; // 代碼運行出現段錯誤,delete p和 delete pobj發生了沖突,導致pri的內存被重復釋放。
  delete pobj;
#endif

  return 0;
}

 

 

 

.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM