当我尝试LeakySingleton
通过静态函数调用在堆上构造一个对象create_instance()
,然后尝试通过delete
操作显式删除它时,我对为什么析构函数会无限次调用自己感到困惑。
据我了解,考虑到下面的源代码清单,leaky_singleton
里面的变量main()
指向由create_instance()
. 因此,我们通过函数LeakySingleton
间接在堆上分配了一个对象。create_instance
现在,如果我在 上显式调用 delete 运算符或 delete 函数leaky_singleton
,那么它首先调用析构函数并检查它是否满足instance != nullptr
条件,然后删除instance
指向的对象应该被删除。如果这个对象LeakySingleton::instance
被删除,那么 dtor 就没有理由再次调用自己,或者我在这里遗漏了什么?
使用和不使用 valgrind 调用它会导致分段错误(由于堆栈溢出导致的无效内存访问):
Segmentation fault (core dumped)
使用调试器单步执行会导致无休止的析构函数调用(堆栈溢出的罪魁祸首)。
来自 cplusplus.com(http://www.cplusplus.com/forum/general/40044/):
如果你删除你的对象,它会尝试删除自己,这将导致它尝试删除自己,这将导致它删除自己,这将...
delete
当我简单地使用运算符/函数来释放LeakySingleton
静态类成员变量指向的堆对象时,为什么它会尝试删除自己LeakySingleton::instance
?堆分配的资源由指向对象的LeakySingleton::instance
指针变量指向LeakySingleton
。那么为什么显式delete
函数调用不会删除或释放分配的堆对象,而是无休止地递归呢?我在这里想念什么?
(我目前对 dtor 和 ctor 的理解:new
函数/运算符为堆上的对象分配内存并调用构造函数,delete
函数调用析构函数,在我的情况下还调用delete
内部的运算符/函数。)
来源:
主.cpp:
class Singleton final
{
public:
static Singleton & create_instance(int);
~Singleton() = default;
private:
int x;
Singleton(int);
Singleton(Singleton &) = delete;
Singleton(Singleton &&) = delete;
Singleton & operator=(Singleton &) = delete;
Singleton & operator=(Singleton &&) = delete;
};
Singleton::Singleton(int t_x) : x{t_x}
{}
Singleton & Singleton::create_instance(int t_x)
{
static Singleton instance{t_x};
return instance;
}
// Potential endless dtor calls inside:
class LeakySingleton final
{
public:
static LeakySingleton * create_instance(int);
~LeakySingleton();
private:
int x;
static LeakySingleton * instance;
LeakySingleton(int);
LeakySingleton(LeakySingleton &) = delete;
LeakySingleton(LeakySingleton &&) = delete;
LeakySingleton & operator=(LeakySingleton &) = delete;
LeakySingleton & operator=(LeakySingleton &&) = delete;
};
LeakySingleton * LeakySingleton::instance = nullptr;
LeakySingleton::LeakySingleton(int t_x) : x{t_x}
{}
LeakySingleton::~LeakySingleton()
{
if (instance != nullptr)
{
delete instance;
instance = nullptr;
}
}
LeakySingleton * LeakySingleton::create_instance(int t_x)
{
if (instance == nullptr)
{
instance = new LeakySingleton{t_x};
}
return instance;
}
int main()
{
// The correct implementation with no issues:
{
Singleton & singleton = Singleton::create_instance(42);
}
// The faulty implementation causing the dtor to recurse endlessly and resulting in a segfault:
{
LeakySingleton * leaky_singleton = LeakySingleton::create_instance(42);
delete leaky_singleton;
}
return 0;
}
生成文件:
CC = g++
CFLAGS = -g -Wall -Wextra -pedantic -std=c++11
SRC = main.cpp
TARGET = app
RM = rm -rf
.PHONY: all clean
all: $(TARGET)
clean:
$(RM) $(TARGET)
$(TARGET): $(SRC)
$(CC) $(CFLAGS) $^ -o $@