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

C++ 试图捕获递归函数内部失败的分配:未处理的异常/堆栈溢出,c++,list,exception,recursion,allocation,C++,List,Exception,Recursion,Allocation,这是我在学校作业中试图解决的问题。我创建了一个链表类,其中包含一个节点(即,一个包含字符“item”和节点指针“next”的结构)和一个节点指针头。按照任务的规定,我需要递归地在链表上实现几个操作。我已经设法使这一切顺利进行 然而,作为作业的下一步,我被要求:“编写一个测试程序来确定可能最长的链表是什么。(您将测试堆大小)。您可以很容易地做到这一点,因为append函数定义为如果成功则返回true,否则返回false。” 在课堂上,有人提到我们应该使用一些与 try{ //Allocate a

这是我在学校作业中试图解决的问题。我创建了一个链表类,其中包含一个节点(即,一个包含字符“item”和节点指针“next”的结构)和一个节点指针头。按照任务的规定,我需要递归地在链表上实现几个操作。我已经设法使这一切顺利进行

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

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

try{ //Allocate a new node
     // Throw an exception if it fails
}
catch(...){
     // Do something with the caught exception
}
就我的生命而言,我不能让它工作!我得到以下错误:

Assignment.exe中0x7765DED4(ntdll.dll)处未处理的异常:0xC00000FD:堆栈溢出(参数: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);
}
我很有信心,除了异常处理之外,我的代码还能正常工作。即,使用以下方法添加节点:

currentNode->next = new Node{ newChar, nullptr };
看起来很好用。我们在课堂上的讨论给我的印象是,当分配失败时,我应该能够捕获异常,返回一个false,然后继续我的剩余程序/实验


你知道我哪里出了问题,或者我该如何解决这个问题吗?我开始认为我应该迭代一个计数器,每次调用
append()
函数时将其打印到屏幕上,然后在它崩溃时记录这个数字。。。但这似乎不是很优雅,我也不认为这是预期的。

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

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

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

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

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


除非您的编译器正在优化尾部递归,否则您很可能测试的是堆栈大小而不是堆大小。可能这只是一个输入错误。。。这会显著改变问题吗?这要看情况而定。当你说“不能让它工作”时,你是什么意思?您的程序正在崩溃(堆栈溢出),还是工作正常?编写时调用
append
的复杂性将导致程序花费很长时间来耗尽堆,因为它具有指数级的时间复杂性。要在线性时间内执行此操作,需要列表跟踪最后一个节点(而不是每次都搜索),或者可以在头部插入新节点。要获得更多帮助,请更具体地说明正在发生的事情。顺便说一句,还有一个新的
的非抛出版本。哦,糟了,我想我应该在原始问题中包括这个(对不起)。我已经更新了主要问题,但自从您提出之后,我在Assignment.exe中得到:0xC00000FD:Stack overflow(参数:0x00000001,0x00352FFC)中0x7765DED4(ntdll.dll)处的未处理异常。您确定要使用递归吗?这实际上与try/catch或bad_alloc无关,而是堆栈溢出(即嵌套调用过多)。还要注意,Windows调用一个“异常”与C++调用“异常”不一样。