试图在递归函数内捕获失败的分配:未处理的 exception/Stack 溢出

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

这是我在学校作业中试图解决的问题。我创建了一个包含节点(即包含字符 "item" 和节点指针 "next" 的结构)和节点指针头的单个链表 class。根据作业的规定,我需要递归地对链表执行多个操作。我已经设法让所有这些工作正常。

然而,作为作业的下一步,我被要求:"write a test program to determine what the longest possible linked list is. (You will be testing the heap size). You can do this easily since the append function is defined to return true if successful and false otherwise."

在 class 中提到我们应该使用类似于

的东西
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).

这是我第一次处理异常,所以也许我遗漏了一些东西,但我一直在拖网 google 和我收集的教科书几个小时,我正式陷入困境。

这里是有问题的代码:

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

似乎工作正常。我们在 class 中进行的讨论给我的印象是,我应该能够在分配失败时捕获异常,return 为 false,然后继续我 program/experiement 的其余部分。 ..

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

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

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

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

这就是程序不应处理此类异常的原因 - 在应用程序级别,您只是没有足够的智慧来正确恢复,而 OS 能够清理您的应用程序产生的混乱。

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

Structured Exception Handling

More on hardware exceptions