正确删除单身人士

时间:2013-11-20 20:39:03

标签: 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.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'后,我调用

    • theInstance = 0;
    • instanceMutex.release();

    但是如果删除实例甚至可能的话?这不是班里的记忆吗?

5 个答案:

答案 0 :(得分:13)

如果它是一个单例 - 它被定义为只有一个实例 - 如果你删除它 - 这会下降到0

所以看来你不应该支持删除

答案 1 :(得分: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();
}

您可能希望实现某种引用计数系统(如使用shared_ptr)并以类似方式初始化它,但要注意确保在初始化完成之前未设置其实例指针。

如果你喜欢冒险,你也可以试试:

if (theInstance == 0)
{
    instanceMutex.acquire();
    if (theInstance == 0)
    {
        MyClass * volatile ptr = new MyClass();
        __FuglyCompilerSpecificFenceHintThatMightNotActuallyDoAnything();
        theInstance = ptr;  // <- Much hilarity may ensue if this write is not atomic.
    }
    instanceMutex.release();
}

这可能会解决它,也可能不会。在第二种情况下,它取决于编译器处理volatile的方式,并且天气或非指针大小的写入是原子的。

答案 2 :(得分:0)

我更喜欢用以下方式在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&);
};

您也可以使用锁定机制,以防止来自多个线程的并发实例化(当然需要静态互斥锁!)。但是删除留给了(OS特定的)过程上下文 通常,您不需要关心单例类的删除,以及如何释放它们获取的资源,因为当进程终止时,操作系统都会处理这些资源。 无论如何可能有用例,当你想让你的单例类在程序崩溃情况下有一些备份点。大多数C ++ crt实现都支持调用静态分配的实例的析构函数,但是你应该注意不要为任何这些析构函数设置顺序依赖。

答案 3 :(得分:0)

在我们从一些外部公司继承的一个项目中,我看到有人因删除单身人员而导致整个噩梦般的错误。也许在极少数情况下删除单例并不会对整个应用程序产生任何副作用,因为您可以确定在使用中没有此单例的实例,但通常情况下,它是一个很好的例子糟糕的设计。有人可以从你的榜样中学习,这将是一个糟糕的 - 甚至是有害的 - 教训。如果您需要在应用程序退出时清理单例中的某些内容,请使用模式ith返回对单例的引用,如示例所示:

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

答案 4 :(得分:-3)

getInstance和delteInstance应该是静态的,因此它们只能与类的静态成员一起使用。静态成员不会被实例破坏。

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