C++错误处理不绕过堆栈展开过程

anhgbhbe  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(125)

我希望在由许多源文件和头文件组成的代码中有干净的错误处理。我更喜欢使用传统的C风格的状态码(调用函数,在成功时返回1,然后检查返回值是否为1),如果状态码不是1,那么我想调用一个错误函数,如下所示。通过这种方式,我避免了在我的程序中到处都是垃圾的try-catch,它允许我描述代码中可能发生的实际错误。我在下面的例子中遇到的问题是,我需要清理内存(假设打开了数据库之类的东西),并且必须在程序退出之前关闭内存,以避免进一步的问题。为了实现这一点,我想利用RAII,这意味着类的析构函数应该在堆栈展开过程开始时被调用。然而,很明显,在下面的例子中,析构函数从未被调用,因为cout没有发生。我知道这可以通过使用try-catch来捕获所有错误来避免,否则堆栈倒带是“实现定义的”(哪个实现?这是我的代码吗?但是我真的想避免经常把所有东西都放到try-catch中,因为这样会大大影响可读性。
以下是我的问题:是否可以只调整函数throw_error(),以便在一切停止之前调用析构函数(我想进行正常的堆栈展开)?如果不可能,为什么?这似乎是一个每个人都应该遇到的简单问题,所以我很惊讶没有找到像safe_throw这样的东西,而不是throw将首先调用所有析构函数。我知道这里有很多关于RAII的问题,但是阅读这些问题并没有帮助我解决我的问题。
谢谢你的帮助下面是我的示例代码:

#include <iostream>

using namespace std;

void throw_error(const string& error_description){
    throw runtime_error(error_description); // i would like to have a different function that does the same thing except that the stack unwind happens
    
}

class DatabaseExample{
public: 

    // constructor
    DatabaseExample(){
        testarray = new int[32]; // can lead to memory leak if not deleted manually (class is called DatabaseExample because I plan to open a database connection and the leak would be not closing the database connection properly, this is just a simplified example)
    }
    
    // destructor, which sadly is never called because exit() or throw avoids the stack unwind which would call the destructor :(
    ~DatabaseExample(){
        cout << "Destructor of the class has been called.. Or has it?" << endl;
        delete[] testarray;
    }
    
private:
    int* testarray;
};

int main(){
    DatabaseExample testobject = DatabaseExample();
    
    int a = 2;  // simplified example
    if (a != 1){    // openssl library returns 1 on success
        throw_error("My custom error that occured because...");
    }
    

    return 0;   // imagine having 0 chosen as a status value convention from a successful program when from a boolean perspective 0 means FALSE.. Everything worked as expected and the program succeeded in everything it was supposed to do and yet it is supposed to return false
}
voj3qocg

voj3qocg1#

您描述的异常的缺点让我认为您并不真正知道如何正确使用它们。实际上,在一个使用异常来传递错误的程序中,当你想从一个错误中恢复时,你只需要很少的try-catch。
未捕获异常的行为取决于谁的实现的问题:编译器实现。
您可以通过在main中放置一个try-catch并简单地log + exit来解决当前问题。所有异常都将冒泡到此时,此时将发生堆栈展开。如果你使用多个线程,你必须在你启动的每个线程的入口点执行此操作。
我的2美分:如果您这样做了,您还不如去掉错误代码,而只是在第一时间正确地使用异常。现在,您通过将错误代码转换为异常来混合这两种方法。

相关问题