静态字段的析构函数。单身实现

时间:2012-04-01 20:43:38

标签: c++ design-patterns static singleton

因此,经典的简单Singleton实现如下:

class Singleton
{
private:
    static Singleton* singleton;
    Singleton() {}
public:
    static Singleton* getInstance();        
};

CPP-文件

Singleton* Singleton::singleton = 0;

Singleton* Singleton::getInstance()
{
    if (!singleton)
    {
        singleton = new Singleton;
    }

    return singleton;
}

我在这里看到了内存泄漏 - '因为 new 没有删除。但是在C ++中没有静态析构函数,所以我们只是不关心这个内存泄漏?

3 个答案:

答案 0 :(得分:26)

内存泄漏不仅仅是一个没有匹配空闲的分配。当你拥有可以回收的内存时,因为该对象不再被使用,但实际上并没有被释放。实际上,许多内存泄漏都是程序中有代码释放内存的情况,但无论出于何种原因它都不会被调用(例如,引用循环)。事实上,有很多关于如何检测这些泄漏的研究; this paper 就是这种工具的一个很好的例子。

在单身人士的情况下,我们没有泄漏,因为整个计划中存在单身人士。它的生命周期永远不会结束,所以没有回收的内存不是问题。

也就是说,上面的代码并不是大多数人实现单例的方式。规范的C ++实现将是这样的:

class Singleton
{
private:
    /* No instantiation. */
    Singleton() {}

    /* Explicitly disallow copying. */ 
    Singleton(const Singleton&) = delete;
    Singleton& operator= (const Singleton&) = delete;

    /* In C++03, the above would be written as
     *
     *    Singleton(const Singleton&);
     *    Singleton& operator= (const Singleton&);
     * 
     * and you'd just leave the methods unimplemented.
     */
public:
    static Singleton& getInstance();        
};

.cpp文件:

Singleton& Singleton::getInstance() {
    /* Have a static local variable representing the unique instance.  Since
     * it's static, there is only one instance of this variable.  It's also only
     * initialized when getInstance is called.
     */
    static Singleton theInstance;
    return theInstance;
}

现在根本没有动态分配 - 内存由编译器分配,可能驻留在代码或数据段中而不是堆中。另请注意,您必须明确禁止复制,否则您最终可能会遇到单个克隆的许多克隆。

这样做的另一个好处是C ++保证在程序退出时(假设程序正常终止),theInstance的析构函数确实会在程序结束时触发。因此,您可以使用所需的所有清理代码定义析构函数。

希望这有帮助!

答案 1 :(得分:3)

delete

没有匹配的new时,为什么要避免使用此类代码?

虽然没有实际的内存泄漏(在大多数现代操作系统中),但更糟糕的是你的Singleton析构函数不会被调用。如果你获得了一些资源,他们可能泄漏。

这里可以做什么

使用智能指针存储实例,考虑std::unique_ptr(使用C ++ 11)或boost::auto_ptr

答案 2 :(得分:0)

当声明函数的本地变量" static"时,表示它没有在堆栈上分配 - 并且它的值从一次调用持续到下一次。