试图在递归函数内部捕获失败的分配:未处理的异常/堆栈溢出

Trying to catch a failed allocation inside of a recursive function: Unhandled exception/Stack overflow

本文关键字:分配 未处理 栈溢出 堆栈 异常 失败 递归函数 内部      更新时间:2023-10-16

这是我想解决的一个学校作业问题。我创建了一个单独的链表类,其中包含一个Node(即。(包含字符"item"和节点指针"next")和节点指针头的结构体。正如赋值所指定的,我需要在链表上递归地实现几个操作。我已经设法使这一切工作良好。

然而,作为作业的下一步,我被要求:"写一个测试程序来确定最长的可能链表是什么。(您将测试堆大小)。您可以很容易地做到这一点,因为append函数被定义为如果成功返回true,否则返回false。"

在课堂上,有人提到我们应该使用

之类的东西。
try{ //Allocate a new node
     // Throw an exception if it fails
}
catch(...){
     // Do something with the caught exception
}

我的生命,我不能让这个工作!我得到以下错误:

Unhandled exception at 0x7765DED4 (ntdll.dll) in Assignment.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x00352FFC).

这是我第一次处理异常,所以也许我遗漏了什么,但我已经在谷歌和我的教科书收集中拖网了几个小时,我正式被困住了。

下面是问题代码:

// RECURSIVELY appends an element to the end of the list
bool LinkedList::append(char newChar){ 
    if (head == nullptr){ // Adds a node to empty list
        head = new Node{ newChar, nullptr };
        return true;
    }
    return appendHelper(newChar, head); // Call the recursive helper function
}
// Helper function for append
bool LinkedList::appendHelper(char newChar, Node* currentNode){     
    if (currentNode->next == nullptr){ // Adds a node to the end of a list
        // HERE'S WHERE THE TROUBLE BEGINS:
        try{
            currentNode->next = new Node{ newChar, nullptr }; // From what I've read, this should throw std::bad_alloc if it fails?
        }
        catch(...){ // The "..." should catch ANY exception, right?
            return false; // Return false, so that I'll know allocation failed
        }
        return true; // Mustn't have encountered an exception; return true.
    }
    return appendHelper(newChar, currentNode->next);
}

我相当有信心,我的代码,除了异常处理,工作。Ie。使用:

添加节点
currentNode->next = new Node{ newChar, nullptr };

似乎可以正常工作。我们在课堂上的讨论给我留下的印象是,当分配失败时,我应该能够捕获异常,返回false,然后继续我的程序/实验的其余部分…

知道我在哪里做错了,或者我怎么解决这个问题吗?我开始认为我应该迭代一个计数器,并在每次调用append()函数时将其打印到屏幕上,然后在它崩溃时记录这个数字……但是这看起来不是很优雅,我也不觉得这是期望的。

必须区分两种异常:硬件异常软件异常。c++异常可以被视为软件异常,因此使用c++ try/catch语句只能捕获软件异常。软件异常的一个例子是当程序检测到为某些过程指定了无效参数时。

硬件异常要严重得多,是由CPU自己抛出的。硬件异常的例子有:除零,试图访问无效的内存地址,堆栈溢出和其他。许多这些硬件异常由操作系统本身处理(调试器也处理其中一些异常),强烈建议不要在程序中捕获这些异常。这样做可能会阻止较低级系统正确地清理留下的混乱。

回到你遇到的堆栈溢出问题,当这个硬件异常发生时,堆栈指针超过了堆栈边界。换句话说,您的程序超出了堆栈(这是过度简化,因为进程中的每个线程都获得一定数量的堆栈空间,所以可能只有线程耗尽了堆栈)。即使您要处理这个异常,您想要做什么?你的栈外,所以你的选择是非常有限的(例如,甚至定义一个局部变量,或调用一个函数可能会导致另一个异常)。

这就是为什么程序不应该处理这样的异常——在应用程序级别,你只是没有足够的智慧来正确恢复,而操作系统能够清理你的应用程序产生的混乱。

也就是说,Windows允许你捕获这样的异常…结构化异常处理可用于捕获Windows上的硬件和软件异常。但是,如果你是一个聪明的程序员,你可能不会这样做。

结构化异常处理

关于硬件异常的更多信息