valgrind & 单例模式的自动释放(多线程)

发布于:2024-10-09 ⋅ 阅读:(35) ⋅ 点赞:(0)

单例模式,其中对象是由_pInstance指针来保存的,而在使用单例设计模式的过程中,也难免会遇到内存泄漏的问题。那么是否有一个方法,可以让对象自动释放,而不需要程序员自己手动去释放呢? ——嵌套类

5.1、内存泄漏的检测工具valgrind
安装
sudo apt install valgrind
使用

[外链图片转存中…(img-Onqi9PtX-1728058419413)]

5.2、单例模式自动释放的四种方法 & 多线程
1、友元类

[外链图片转存中…(img-yl7twkoI-1728058419413)]

[外链图片转存中…(img-epIiJsLR-1728058419414)]

#include <iostream>

using std::cout;
using std::endl;

class Singleton
{
    friend class AutoRelease;
public:
    static Singleton *getInstance()
    {
        if(nullptr == _pInstance)
        {
            _pInstance = new Singleton();
        }

        return _pInstance;
    }

    static void destroy()
    {
        if(_pInstance)
        {
            delete _pInstance;
            _pInstance =nullptr;
        }
    }

private:
    Singleton()
    {
        cout << "Singleton()" << endl;
    }

    ~Singleton()
    {
        cout << "~Singleton()" << endl;
    }
private:
    static Singleton *_pInstance;
};
Singleton *Singleton::_pInstance = nullptr;

class AutoRelease
{
public:
    AutoRelease()
    {
        cout << "AutoRelease()" << endl;
    }

    ~AutoRelease()
    {
        cout << "~AutoRelease()" << endl;
        if(Singleton::_pInstance)
        {
            delete Singleton::_pInstance;
            Singleton::_pInstance =nullptr;
        }

    }
};
int main(int argc, char **argv)
{
    Singleton *ps1 = Singleton::getInstance();
    AutoRelease ar;//栈对象

    /* ps1->destroy(); */
    return 0;
}


2、内部类 + 静态数据成员

[外链图片转存中…(img-oCRKHufV-1728058419414)]

  • 若_ar定义为类成员,则会死锁:
    • new Singleton(),导致_ar在创建的单例堆对象内部,无法使其自动创建&析构(析构自身前,进行delete _pInstance
    • 应将_ar定义为static
    • [外链图片转存中…(img-8lWGqW65-1728058419414)]
#include <iostream>

using std::cout;
using std::endl;

// 2、内部类 + 静态数据成员

class Singleton
{
public:
    static Singleton *getInstance()
    {
        if (_pInstance == nullptr)
        {
            _pInstance = new Singleton(); // 构造函数
            // _ar;
        }

        return _pInstance;
    }

    static void destroy()
    {
        if (_pInstance)
        {
            delete _pInstance;
            _pInstance = nullptr;
        }
    }

private:
    class AutoRelease
    {
    public:
        AutoRelease()
        {
            cout << "AutoRelease()" << endl;
        }

        ~AutoRelease()
        {
            cout << "~AutoRelease()" << endl;
            if (_pInstance)
            {
                delete _pInstance;
                _pInstance = nullptr;
            }
        }
    };

private:
    Singleton()
    {
        cout << "Singleton()" << endl;
    }

    ~Singleton()
    {
        cout << "~Singleton()" << endl;
    }

private:
    static Singleton *_pInstance; // 前向声明;定义为static,位于全局静态区(不属于本类!)
    static AutoRelease _ar; // 前向声明;对象数据成员, _ar不能存在堆上,否则死锁;定义为static,位于全局静态区(不属于本类!)
};

Singleton *Singleton::_pInstance = nullptr; // 静态对象必须在类外进行正式声明!
Singleton::AutoRelease Singleton::_ar; // 静态对象必须在类外进行正式声明!

int main(int argc, char **argv)
{
    Singleton *ps1 = Singleton::getInstance();
    /* Singleton::AutoRelease ar;//栈对象 */

    /* ps1->destroy(); */
    return 0;
}

/*
AutoRelease()
Singleton()
~AutoRelease()
~Singleton()

*/
采用模板
  • Singleton.h
#ifndef __WD_TEMPLATE_SINGLETON_H__
#define __WD_TEMPLATE_SINGLETON_H__

#include <iostream>
using std::cout;
using std::endl;
#if 0
class Singleton
{
public:
    static Point *getInstance(int ix, int iy)
    {
		if(nullptr == _pInstance) 
        {
			_pInstance = new Point(ix, iy);
			_ar;//为了在模板参数推导时创建ar对象
		}
		return _pInstance;

    }
};
#endif
template <class T>
class Singleton
{
public:
	template <class... Args>
	static T *getInstance(Args... args)
	{
		if (nullptr == _pInstance)
		{
			_pInstance = new T(args...);
			_ar; // 为了在模板参数推导时创建ar对象
		}
		return _pInstance;
	}

private:
	class AutoRelease
	{
	public:
		AutoRelease()
		{
			cout << "AutoRelease()" << endl;
		}

		~AutoRelease()
		{
			cout << "~AutoRelease()" << endl;
			if (_pInstance)
			{
				delete _pInstance;
				_pInstance = nullptr;
			}
		}
	};

private:
	Singleton()
	{
		cout << "Singleton()" << endl;
		/* _ar; */
	}

	~Singleton()
	{
		cout << "~Singleton()" << endl;
	}

private:
	static T *_pInstance;// 前向声明;定义为static,位于全局静态区(不属于本类!)
	static AutoRelease _ar;// 前向声明;对象数据成员, _ar不能存在堆上,否则死锁;定义为static,位于全局静态区(不属于本类!)
};

template <class T>
T *Singleton<T>::_pInstance = nullptr; // 静态对象必须在类外进行正式声明!

template <class T>
typename Singleton<T>::AutoRelease Singleton<T>::_ar;  // 静态对象必须在类外进行正式声明! // typename表名是一个类型

#endif

  • Test.cpp

    • #include "Singleton.h"
      
      #include <iostream>
      using std::cout;
      using std::endl;
      
      
      class Point
      {
      public:
      	Point(int ix = 0, int iy = 0)
      	: _ix(ix)
      	, _iy(iy)
      	{	
              cout << "Point(int = 0,int = 0)" << endl;	
          }
      
      	void print() const
      	{
      		cout << "(" << _ix
      			 << "," << _iy
      			 << ")" << endl;
      	}
      
      	~Point()
      	{
      		cout << "~Point()" << endl;
      	}
      
      private:
      	int _ix;
      	int _iy;
      };
       
      int main()
      {
      	Point *pt1 = Singleton<Point>::getInstance(1, 2);
      	Point *pt2 = Singleton<Point>::getInstance(3, 4);
      	pt1->print();
      	pt2->print();
      
      	cout << "p1 = " << pt1 << endl
      		 << "p2 = " << pt2 << endl;
      
      	return 0;
      }
      
      
3、饿汉模式 + atexit
atexit

[外链图片转存中…(img-M9pmTrsb-1728058419415)]

#include <stdlib.h>
#include <iostream>

using std::cout;
using std::endl;

void func()
{
    cout << "void func()" << endl;
}

void test()
{
    atexit(func); // atexit: 进程正常结束时候,注册的func会被执行,注册几次就会执行几次
    atexit(func);
    atexit(func);
    atexit(func);
    atexit(func);
}

int main(int argc, char **argv)
{
    cout << "start test..." << endl;
    test();
    cout << "finish test..." << endl;

    return 0;
}

/*
start test...
finish test...
void func()
void func()
void func()
void func()
void func()

*/
饿汉模式 + atexit

[外链图片转存中…(img-tBQqgF0g-1728058419415)]

[外链图片转存中…(img-ruQk952y-1728058419415)]

#include <stdlib.h>
#include <iostream>

using std::cout;
using std::endl;

// 3、atexit + 饿汉模式

class Singleton
{
public:
    static Singleton *getInstance()
    {
        // 在多线程情况下,是不安全的
        if (_pInstance == nullptr)
        {
            _pInstance = new Singleton(); // 构造函数
            atexit(destroy);              // 使用atexit:注册函数destroy一次, 当进程正常结束后,会调用一次注册的函数destroy
        } else {
            cout << "_pInstance != nullptr" << endl;
        }

        return _pInstance;
    }

    static void destroy()
    {
        if (_pInstance)
        {
            delete _pInstance;
            _pInstance = nullptr;
        }
    }

private:
    Singleton()
    {
        cout << "Singleton()" << endl;
    }

    ~Singleton()
    {
        cout << "~Singleton()" << endl;
    }

private:
    static Singleton *_pInstance;
};

/* Singleton *Singleton::_pInstance = nullptr; //饱(懒)汉模式, 问题:多线程下,单例模式失效;*/
Singleton *Singleton::_pInstance = getInstance(); // 饿汉模式,可解决多线程不安全问题

void *func1(void *arg)
{
    Singleton::getInstance();
}

void *func2(void *arg)
{
    Singleton::getInstance();
}

void *func3(void *arg)
{
    Singleton::getInstance();
}
int main(int argc, char **argv)
{
    Singleton *ps1 = Singleton::getInstance();

    // 饱(懒)汉模式下,多线程不安全;-- 解决:使用饿汉模式
    // pthread_t th1, th2, th3;
    // pthread_create(&th1, nullptr, func1, nullptr);
    // pthread_create(&th2, nullptr, func2, nullptr);
    // pthread_create(&th3, nullptr, func3, nullptr);

    return 0;
}

4、多线程场景:pthread_once + atexit

[外链图片转存中…(img-MvIJXvC9-1728058419415)]

#include <pthread.h>
#include <stdlib.h>
#include <iostream>

using std::cout;
using std::endl;

//4、atexit + pthread_once
//有平台问题,只能在Linux下使用

class Singleton
{
public:
    static Singleton *getInstance()
    {
        //当第一个参数是某个固定值的时候,可以保证第一个参数只会被
        //调用一次  call_once
        pthread_once(&_once, init);

        return _pInstance;
    }

    static void init()
    {
        _pInstance = new Singleton();//构造函数
        atexit(destroy);
    }

    static void destroy()
    {
        if(_pInstance)
        {
            delete _pInstance;
            _pInstance = nullptr;
        }
    }


private:
    Singleton()
    {
        cout << "Singleton()" << endl;
    }

    ~Singleton()
    {
        cout << "~Singleton()" << endl;
    }
private:
    static Singleton *_pInstance;
    static pthread_once_t _once;
};

Singleton *Singleton::_pInstance = nullptr; //饱(懒)汉模式
/* Singleton *Singleton::_pInstance = getInstance();//饿汉模式 */
pthread_once_t Singleton::_once = PTHREAD_ONCE_INIT;

int main(int argc, char **argv)
{
    Singleton *ps1 = Singleton::getInstance();

    return 0;
}