实战:单例的析构,为什么可以析构,重复析构等注意事项

 

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;
}

 

 

 

.

posted @ 2020-10-15 15:26  一匹夫  阅读(1388)  评论(0编辑  收藏  举报