Singleton模式析构函数C++
Singleton pattern destructor C++
我有这个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。在像这样的情况下,它们是数据源,模式中有太多的弱点需要处理。
- 例如,您使用new来分配内存。因此,在调用delete之前,实例将一直处于活动状态
- 在类的实例将被杀死的情况下调用析构函数
- 没有任何东西会杀死(使用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;
}
此调用确保指针不仅从内存中删除,而且不指向任何内容。当删除指针时,你需要确保它不再指向任何东西,否则你可能会出现内存泄漏。
- 什么时候调用组成单元对象的析构函数
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 内联映射初始化的动态atexit析构函数崩溃
- 什么时候调用析构函数
- 优先顺序:智能指针和类析构函数
- C++-明确何时以及如何调用析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 在c++中使用向量时,如何调用构造函数和析构函数
- 重载运算符new[]的行为取决于析构函数
- 我需要知道编译器如何在cpp中使用析构函数
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 析构函数调用
- 通过引用传递-为什么要调用这个析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- C++成员的析构函数顺序与shared_ptr
- C++ 防止在映射中放置()时调用析构函数
- 在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
- 调用析构函数以释放动态分配的内存
- 不命名构造函数和析构函数上的类型错误