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

问题描述 投票:14回答:3

因此,经典的简单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;
}

我在这里看到内存泄漏-'cos new没有delete。但是在C ++中没有静态析构函数,所以我们只是不在乎这种内存泄漏?

c++ design-patterns static singleton
3个回答
27
投票

内存泄漏不仅仅是分配没有可用空闲空间的分配。正是在这个时候,由于对象已不再使用,但实际上并没有被释放,因此可以回收内存。实际上,许多内存泄漏是程序中有代码来释放内存的情况,但是由于某种原因它没有被调用(例如,参考周期)。关于如何检测这类泄漏的研究很多。 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的析构函数实际上将在程序末尾触发。因此,您可以使用所需的所有清理代码来定义析构函数。

希望这会有所帮助!


3
投票

delete中没有匹配的new时为什么要避免这样的代码>

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

这里可以做什么

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


0
投票

当函数局部变量声明为“静态”时,表示它没有分配在堆栈上,并且它的值从一个调用到下一个调用一直存在。

© www.soinside.com 2019 - 2024. All rights reserved.