C++ 单态模式析构函数C++;

C++ 单态模式析构函数C++;,c++,singleton,valgrind,destructor,C++,Singleton,Valgrind,Destructor,我有这个单件模式,它运行正常。但是,当我使用valgrind执行程序以检查内存泄漏时,实例似乎从未被破坏 我的错在哪里 标题 类停止字{ 私人: 静态Stopwords*实例; 标准::地图迪乔纳里奥; 私人: 停止词(); 公众: ~Stopwords(); 公众: 静态停止字*getInstance(); std::map getMap(); }; .cpp Stopwords*Stopwords::instance=NULL; Stopwords::Stopwords(){ diccio

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

我的错在哪里

标题
类停止字{
私人:
静态Stopwords*实例;
标准::地图迪乔纳里奥;
私人:
停止词();
公众:
~Stopwords();
公众:
静态停止字*getInstance();
std::map getMap();
};
.cpp
Stopwords*Stopwords::instance=NULL;
Stopwords::Stopwords(){
diccionario=map();
char nombre_archivo[]=“stopwords/stopwords.txt”;
ifstream archivo;
档案室开放(名称:档案室);
字符串停止字;
while(getline(archivo,stopword,,)){
diccionario[stopword]=1;
}
archivo.close();
}
Stopwords::~Stopwords(){
删除实例;
}
Stopwords*Stopwords::getInstance(){
if(实例==NULL){
instance=newstopwords();
}
返回实例;
}
map Stopwords::getMap(){
返回迪乔纳里奥;
}
这并不相关,但在初始化过程中,我从一个文件中读取了一堆单词,并将它们保存在一个map实例中


感谢您在析构函数中执行以下操作:

Stopwords::~Stopwords() {
    delete instance;
}
我建议你补充:

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

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

问题在于,您从未手动调用析构函数或删除实例指针,即从类外部调用。所以析构函数中的删除永远不会执行,这意味着析构函数永远不会执行,这意味着删除永远不会执行,这意味着。。。你看到你在那里做了什么吗?你的析构函数正在间接地调用它自己,这不会很顺利。而且你从不从外面打电话给它,所以它根本就不会被呼叫——幸运的是

您应该更改您的单例实现,可能是Meyers单例(查找),或者最好根本不使用单例。在这种情况下,如果它们是数据源,那么该模式有太多的弱点需要处理

  • 例如,您可以使用新的内存分配内存。因此,在调用delete之前,该实例将一直处于活动状态
  • 在类的实例将被终止的情况下调用析构函数
  • 除了析构函数本身,没有任何东西会杀死(使用delete)您的实例
  • 因此,结论是您的实例从未被杀死

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

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

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

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

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

    如果析构函数实际上不是从外部调用的,则这不会有任何帮助。他还可以使用std::unique_ptr而不是原始指针。此外,更好的方法是引用
    实例,而不是将其作为指针,例如
    getInstance()中的
    返回&实例
    @odedsh这将是一种可能的解决方案,因为
    unique\u ptr
    析构函数将从外部隐式调用。每当调用getInstance时,都会创建并返回一个新实例?这不是违背了单例的目的吗?@EhsanAb不,每次调用
    getInstance
    时,它都返回相同的对象。啊,我明白了/它是静态的。没有看到关于是否使用
    static t*实例
    vs
    static t实例
    的itA说明。如果T本身较大,则前者可能更可取,因为它进行堆分配而不是静态数据分配。这会使可执行映像的大小变小,在数据段中只保留
    sizeof(T*)
    字节,而不是
    sizeof(T)
    字节。@Rodrigo防止删除复制构造函数。
    Stopwords::~Stopwords() {
        delete instance;
    }
    
    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;
    };
    
    std::map<std::string,short> getMap() const;