Singleton模式析构函数C ++

时间:2013-11-20 14:13:55

标签: c++ singleton valgrind destructor

我有这个单例模式,运行正常。但是当我用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;
}

这没关系,但在初始化时,我从文件中读取了一堆单词,然后将它们保存在地图实例中。

由于

5 个答案:

答案 0 :(得分:15)

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

这是类的实例的析构函数。您可能希望在程序结束时调用此函数,就好像它是一种“静态”析构函数,但这不是它。

因此,对于Stopwords实例的析构函数会启动对Stopwords实例的破坏;你在这里有一个无限循环,你永远不会进入。如果你进入这个循环,那么程序可能会崩溃。

有一种更简单的方法可以做单例:不要将实例保持为手动分配的静态类成员,而只需将其保存为静态函数变量。 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;

答案 1 :(得分:11)

问题是你永远不会手动调用析构函数或删除实例指针,即从类外部调用。因此析构函数中的删除将永远不会被执行,这意味着析构函数永远不会被执行,这意味着删除永远不会被执行,这意味着......你看到你在那里做了什么?你的析构函数间接地称自己为自己不顺利。而且你永远不会从外面打电话,所以它永远不会被召唤 - 幸运的是。

你应该改变你的单身实现,也许是Meyers单身(查找),甚至更好不要使用单身。在像这样的情况下,如果它们是数据源,那么处理模式的弱点就太多了。

答案 2 :(得分:1)

  1. 您可以使用new分配内存。因此,在调用delete之前,实例将处于活动状态。
  2. 在一个类的实例将要被杀死的情况下调用析构函数。
  3. 没有任何东西可以杀死(使用删除)你的实例,但是析构函数本身。
  4. 所以结论是你的实例永远不会被杀死。

    通常,当你使用单身时,你不必在程序结束前杀死它。你为什么需要这个?

    如果你不这样做,你最好使用static关键字明确说明它在程序完成之前一直存在。

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

答案 3 :(得分:-1)

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

答案 4 :(得分:-6)

在您的析构函数中,您可以:

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

我建议你补充一下:

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

此调用确保指针不仅从内存中删除,而且指向任何内容。删除指针时,您需要确保它不再指向任何内容,否则您可能会发生内存泄漏。