C++ 正确删除单例

C++ 正确删除单例,c++,mutex,C++,Mutex,我有以下代码: MyClass.h: static MyMutex instanceMutex; static MyClass* getInstance(); static void deleteInstance(); MyClass.c: MyMutex MyClass::instanceMutex; MyClass* MyClass::getInstance() { if (theInstance == 0) { instanceMutex.acqu

我有以下代码:

MyClass.h:

static MyMutex instanceMutex;
static MyClass* getInstance();
static void deleteInstance();
MyClass.c:

MyMutex MyClass::instanceMutex;

MyClass* MyClass::getInstance()
{   
    if (theInstance == 0)
    {
        instanceMutex.acquire();
        if (theInstance == 0)
        {
            theInstance  = new MyClass();
        }
        instanceMutex.release();
    }
    return theInstance;
}

void MyClass::deleteInstance()
{   
    if (theInstance != 0)
    {
        instanceMutex.acquire();
        if (theInstance != 0)
        {
           theInstance->finalize();
           delete theInstance; 
           theInstance = 0;
        }
        instanceMutex.release();
    }
    return;
}
关于这一点,我有两个问题:

  • 上述代码正确且安全吗
  • 在MyClass::deleteInstance()中调用“delete theInstance”后,我将调用

    • 持续时间=0
    • instanceMutex.release()
    但是如果实例被删除了,那怎么可能呢?这堂课的记忆不是消失了吗


getInstance和delteInstance应该是静态的,因此它们只能处理类的静态成员。静态成员不会随实例一起销毁


如果代码是多线程的,则代码不安全。无法确保在某些运行上下文中没有指向实例的指针。

如果它是单实例-定义为只有一个实例-如果删除它-则该值降至0

因此,您似乎根本不应该支持删除,这是一个问题:

if (theInstance == 0)  // <- Some other thread might see a non-null theInstance 
{                      // before the constructor below returns

    instanceMutex.acquire();
    if (theInstance == 0)
    {
        theInstance  = new MyClass();  // <- This might set theInstance to something 
                                       // before the constructor returns.
    }
    instanceMutex.release();
}

这可能会解决问题,也可能不会。在第二种情况下,这取决于编译器如何处理<代码> Value,以及天气或指针大小写都是原子的。

< P>我喜欢用C++实现单体:
class Singleton
{
public:
    static Singleton& instance()
    {
        static Singleton theInstance;
        return theInstance;
    }

    ~Singleton()
    {
        // Free resources that live outside the processes life cycle here,
        // if these won't automatically be released when the occupying process 
        // dies (is killed)!
        // Examples you don't have to care of usually are:
        // - freeing virtual memory
        // - freeing file descriptors (of any kind, plain fd, socket fd, whatever)
        // - destroying child processes or threads
    }

private:
    Singleton()
    {
    }

    // Forbid copies and assignment
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
};
您还可以使用锁定机制,以防止来自多个线程的并发实例化(当然需要静态互斥)。但此处的删除由(特定于操作系统的)进程上下文决定。
通常,您不需要关心单例类的删除,以及它们获取的资源是如何释放的,因为当进程死亡时,这些都由操作系统处理。

无论如何,当您想让您的单例类在程序崩溃情况下有一些备份点时,可能会有一些用例。大多数C++ CRT实现支持静态分配实例的调用析构函数,但是您应该注意不要对这些析构函数中的任何析构函数有排序依赖关系。

< P>在我们从某个外部公司继承的一个项目中,我看到了由删除单个元素引起的整个噩梦类错误。也许在您罕见的情况下,删除单例对整个应用程序没有任何副作用,因为您可以确定没有使用此单例的实例,但是,一般来说,这是一个糟糕设计的极好例子。有人会从你的例子中学习,这将是一个糟糕甚至有害的教训。如果在应用程序退出时需要清理单例中的某些内容,请使用返回单例引用的模式,如示例所示:

#include <iostream>

using namespace std;

class singleton {
    private:
        singleton() {
            cout << "construktor\n";
        }
        ~singleton() {
            cout << "destructor\n";
        }
    public:
        static singleton &getInstance() {
            static singleton instance;
            cout << "instance\n";
            return instance;
        }
        void fun() {
            cout << "fun\n";
        }
};


int main() {
    cout << "one\n";
    singleton &s = singleton::getInstance();
    cout << "two\n";
    s.fun();
    return 0;
}
#包括
使用名称空间std;
单件阶级{
私人:
singleton(){

不能同时双重检查锁定和单例!哦,天哪。你打算在多线程环境中使用此单例吗?如果不,为什么要锁定?如果是,为什么要删除单例?顺便说一句,为什么在程序执行期间需要删除单例?finalize()取消线程它们应该是静态的。这就是模式的实现方式。为什么不使用C++11呢?不,没有同步机制,这个变体不能保证线程安全。除了实例之外,你还需要一个静态互斥体来确保线程安全。@g-makulik erm,你是对的。我正在从answer中删除此信息,而不是从co中删除使用潜在读者。
#include <iostream>

using namespace std;

class singleton {
    private:
        singleton() {
            cout << "construktor\n";
        }
        ~singleton() {
            cout << "destructor\n";
        }
    public:
        static singleton &getInstance() {
            static singleton instance;
            cout << "instance\n";
            return instance;
        }
        void fun() {
            cout << "fun\n";
        }
};


int main() {
    cout << "one\n";
    singleton &s = singleton::getInstance();
    cout << "two\n";
    s.fun();
    return 0;
}