所以,基本上我有一个外部C库的简单包装代码,而且我是一个适当的异常处理新手。
事先:代码两次显示相同的问题,但也许是类版本的不同解决方案。
#include <some_c_lib>
void setup(){
//some setup code
//init function from the C library
//with C-style return code for error handling
if(!init()){
//error: program should terminate
//because error cannot be handled
}
//some setup code
}
class myclass{
//some members
public:
myclass(){
//some construction code
//create function of the C library
//with C-style return code error handling
if(!create()){
//error: program should terminate
//because error cannot be handled
}
}
~myclass(){
//desturction code
}
};
int main(){
std::ostream log("log.txt"); //logfile as an example
setup();
myclass obj;
while(everything_is_fine()){
//main loop stuff
}
}
问题是:我不知道终止程序的最佳方法是什么。
我不想在main
中发现异常。这将是一种毫无意义和丑陋的,因为无论如何都无法处理异常。即便如此,我还想拥有某种堆栈展开机制。如果我只是exit
if
块内的程序,那么日志文件就不会被正确销毁。我对吗?
如果我扔进if
但是没有在任何地方提供try-catch块,文件会关闭吗?
如何处理构造函数中发生的异常?
有没有最好的方法来处理这类问题?
我希望我的问题很清楚。
感谢您的回答,祝您有个美好的一天或晚上。
答案 0 :(得分:1)
这取决于你,你真的没有提供足够的信息。一般来说,没有绝对的“最佳” - 它取决于你的程序的需求,而不是“一刀切”的方法。
只有在小的琐碎程序中才会出现这种情况(例如,您在课堂练习中所做的事情,而不是工作场所),错误始终需要立即终止程序。现实世界的需求比模糊不清 - 取决于程序的功能,通常可以选择从错误中恢复并继续(正常或在某种降级模式下)。最好采取措施防止出现错误(例如检测错误数据,并在对坏数据进行操作并导致错误情况之前采取措施进行恢复)。
但是,通常情况下,如果构造函数中发生错误(并且它是不可避免的,并且构造函数在发生错误时无法执行任何操作等),则必须抛出异常。这基本上表示需要调用者(或调用堆栈中的某些函数)采取恢复操作。如果调用者无法恢复,则抛出异常的默认结果是程序终止 - 调用调用堆栈中本地(自动存储持续时间)创建的所有对象的析构函数。这会终止程序 - 如果有必要 - 并且在过程中进行清理,只要析构器正确清理(这是析构函数的目的)。
在您的代码中,抛出异常将(最终)将控制权返回给main()
。如果未捕获异常,程序将终止 - 但不会在log
被销毁之前终止 - 这会调用其析构函数。标准输出流类的析构函数通常会刷新流并正确关闭它。如果您需要做更多的事情(例如,在终止之前的其他恢复操作,在刷新流之后)将main()
写为函数try-block。
通常不建议在构造函数中执行“部分构造” - 例如,构造函数设置一些基础知识,但用户则必须调用另一个函数来进行“进一步”初始化。这些技术是忘记进行初始化的机会 - 这基本上意味着后续代码可以使用未正确初始化的对象。在C ++中,无论如何都很少需要这样的技术 - 可以推迟创建一个对象,直到所有信息都可用于正确初始化它(在构造函数中)。
一般来说,返回错误代码(例如,具有非void
返回类型的函数,接受指向存储状态信息的对象的指针/引用的函数)在不同情况下是适当的。没有任何东西迫使调用者检查函数的返回值。因此,如果可以安全地忽略错误条件(例如,如果您的代码忘记检查它),或者该函数仅用于检查返回代码的情况,则返回代码是合适的。没有什么能阻止您编写将返回代码(例如,用C编写的函数)转换为异常的代码。返回码的问题在于可能忘记检查它们 - 这可能意味着关键错误仍然未被检测到/未报告,并导致程序中其他代码出现故障。
答案 1 :(得分:0)
一种解决方案不是以这样的方式编写构造函数,以至于它们会抛出错误。通常的做法是使用构造函数来设置成员变量等,然后有一个方法,如bool initialize();返回一个值,该值基于类是否可以执行更复杂的初始化而没有错误。
除了bool之外,您还可以返回其他值或结构以获取更多信息性错误。
最后,您的日志文件仍可由任何类写入,并且如果您有任何错误,则应包含错误信息。