为什么析构函数会不断地自我调用(导致堆栈溢出)?

问题描述 投票:3回答:4

我困惑于为什么析构函数会无休止地自我调用,当我尝试通过静态函数调用LeakySingleton在堆上构造一个对象时说create_instance(),然后尝试通过[ C0]操作。

据我所知,考虑下面的源代码清单,delete中的变量leaky_singleton指向main()返回的堆分配资源。因此,我们已通过create_instance()函数在堆上间接分配了一个对象LeakySingleton。现在,如果我显式调用create_instance上的delete运算符或delete函数,则它将首先调用析构函数,并检查其是否满足leaky_singleton条件,然后删除instance != nullptr指向的对象应为已删除。如果此对象instance被删除,则dtor没有理由再次调用自身,或者我在这里丢失了什么吗?

使用和不使用valgrind调用都会导致分段错误(由于堆栈溢出而导致无效的内存访问):

LeakySingleton::instance

逐步调试,导致无休止的析构函数调用(堆栈溢出的元凶)。>>

从cplusplus.com(Segmentation fault (core dumped)):

如果删除对象,它将尝试删除自身,这将使它尝试删除自身,这将导致它删除本身,这将...

为什么当我简单地使用http://www.cplusplus.com/forum/general/40044/运算符/函数来释放静态类成员变量delete指向的堆对象LeakySingleton时,为什么试图删除自身?堆分配的资源由指向LeakySingleton::instance对象的LeakySingleton::instance指针变量指向。那么,为什么显式LeakySingleton函数调用不删除或取消分配已分配的堆对象,而是无限递归?我在这里想念什么?

(我目前对dtor和ctor的理解:delete函数/操作符为堆上的对象分配内存并调用构造函数,new函数调用析构函数,在我的情况下还调用delete运算符/函数内部。)

来源:

main.cpp

delete

Makefile

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

我对为什么析构函数调用自己无休止的次数感到困惑,当我尝试通过静态函数调用create_instance()然后在堆上构造对象时说LeakySingleton,然后...

c++ design-patterns singleton destructor self-destruction
4个回答
1
投票

您有一个令人讨厌的循环,在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 $@ 中,您有:


1
投票

在C ++中,instance = nullptr; 将调用类析构函数。


0
投票

在析构函数中删除实例,启动析构函数调用。


0
投票

首先,由于class LeakySingleton final { public: static LeakySingleton& create_instance(int); static void destroy_instance(); ~LeakySinglton() = default; private: static LeakySingleton *instance; ... }; void LeakySingleton::destroy_instance() { if (instance != nullptr) { delete instance; instance = nullptr; } } 不能直接创建,也不能直接销毁:

© www.soinside.com 2019 - 2024. All rights reserved.