Singleton模式析构函数C++

Singleton pattern destructor C++

本文关键字:C++ 析构函数 模式 Singleton      更新时间:2023-10-16

我有这个singleton模式,它运行正常。但当我用valgrind执行程序以检查内存泄漏时,实例似乎从未被破坏。

我的错误在哪里?

收割台

class Stopwords {   
    private:
        static Stopwords* instance;
        std::map<std::string,short> diccionario;
    private: 
    Stopwords();
    public:
        ~Stopwords();
    public:
    static Stopwords* getInstance();
    std::map<std::string,short> getMap();
};

.cpp

Stopwords* Stopwords::instance = NULL;
Stopwords::Stopwords() {
    diccionario = map<string,short>();
    char nombre_archivo[] = "stopwords/stopwords.txt";
    ifstream archivo;
    archivo.open(nombre_archivo);
    string stopword;
    while(getline(archivo,stopword,',')) {
    diccionario[stopword] = 1;
    }
    archivo.close();
}
Stopwords::~Stopwords() {
    delete instance;
}

Stopwords* Stopwords::getInstance() {
    if (instance == NULL) {
       instance = new Stopwords ();
    }
    return instance;
}
map<string,short> Stopwords::getMap(){
    return diccionario;
}

这并不相关,但在初始化过程中,我从文件中读取了一堆单词,并将它们保存在映射实例中。

感谢

Stopwords::~Stopwords() {
    delete instance;
}

这是类实例的析构函数。你可能打算在程序结束时调用这个函数,就好像它是一种"静态"析构函数,但事实并非如此

因此,您的Stopwwords实例的析构函数会启动StopwWords实例的销毁;这里有一个无限循环,你永远不会进入。如果你真的进入了这个循环,那么程序可能会崩溃。

有一种更简单的方法可以实现singleton:与其将实例保留为手动分配的静态类成员,不如将其保留为静态函数变量。C++将为您管理创建和销毁它。

class Stopwords {   
public:
    static Stopwords &getInstance() {
        static Stopwords instance;
        return instance;
    }
    ~Stopwords();
    std::map<std::string,short> getMap();
private:
    Stopwords();
    std::map<std::string,short> diccionario;
};

此外,您应该将不需要修改类的成员函数标记为const:

std::map<std::string,short> getMap() const;

问题是,您永远不会手动调用实例指针上的析构函数或delete,即从类外调用。因此,析构函数内部的delete永远不会被执行,这意味着析构函数永远不会执行,意味着delete永远不会执行。。。你看到你在那里做了什么吗?您的析构函数正在间接调用自己,这将不太顺利。而且你从来不会从外面叫它,所以它根本不会被人叫——幸运的是。

您应该更改您的singleton实现,也许是Meyers singleton(查找它),甚至最好根本不使用singleton。在像这样的情况下,它们是数据源,模式中有太多的弱点需要处理。

  1. 例如,您使用new来分配内存。因此,在调用delete之前,实例将一直处于活动状态
  2. 在类的实例将被杀死的情况下调用析构函数
  3. 没有任何东西会杀死(使用delete)您的实例,只有析构函数本身

所以结论是你的实例永远不会被杀死。

通常,当您使用singleton时,您不想在程序完成之前杀死它。你为什么需要这个?

如果不这样做,最好使用static关键字来明确它在程序完成之前是活动的。

static Singleton& getInstance()
{
     static Singleton s;
     return s;
}

您可以在C++中实现singleton,方法是在实例getter中使实例成为函数static std::unique_ptr,而不是类静态变量。这确保了在程序完成时调用析构函数,并允许您创建一个以多态方式访问的实例,例如通过指向抽象基类的指针。

在析构函数中,您可以执行:

Stopwords::~Stopwords() {
    delete instance;
}

我建议您添加:

Stopwords::~Stopwords() {
    delete instance;
    instance = 0;
}

此调用确保指针不仅从内存中删除,而且不指向任何内容。当删除指针时,你需要确保它不再指向任何东西,否则你可能会出现内存泄漏。