不,抛出异常是在对象构造期间发出错误信号的最佳方式。 (由于没有返回值,所以除了构造一个无头对象之外没有其他方法,这在 C++ 中是不好的风格。)
来自 Bjarne Stroustrup 本人:http://www.stroustrup.com/bs_faq2.html#ctor-exceptions http://www.stroustrup.com/bs_faq2.html#ctor-exceptions
(如果您正在一个不允许异常的项目中工作,那么您必须使构造函数万无一失,并将任何可能失败的逻辑移至有可能返回错误的工厂函数中。)
回复:“但是我的析构函数没有被调用”
的确。
在 C++ 中,对象的生命周期从构造函数运行完成时开始。当析构函数被调用时它就结束了。如果 ctor 抛出异常,则不会调用 dtor。
(但是任何成员变量对象的 dtors,其 ctors 之前已经运行完成this冉博士,被称为。)
您应该查阅标准,或者good教科书了解更多细节,尤其是。与涉及继承时发生的情况有关。根据一般经验,析构函数的调用顺序与构造函数的顺序相反。
你关于为什么在你的特定代码中没有调用“~B”的问题,这是因为你没有在 main.c 中捕获异常。如果您更改代码以便 main 捕获异常,则将调用“~B()”。但是,当抛出没有捕获的异常时,实现可以自由地终止程序,而无需调用析构函数或销毁静态初始化的对象。
C++11 标准中的参考(强调我的):
15.5.1 std::terminate() 函数[终止除外]
1在某些情况下,必须放弃异常处理,而采用不太微妙的错误处理技术。
...
2在这种情况下,调用 std::terminate() (18.8.3)。在没有找到匹配处理程序的情况下,在调用 std::terminate() 之前是否展开堆栈是实现定义的。
顺便说一句,一般来说,对于 gcc 和 clang,~B
无论如何,在您的示例程序中都会被调用,而使用 MSVC 时,~B
不会被调用。异常处理很复杂,标准允许编译器编写者可以试验并选择他们认为在这方面最好的实现,但他们不能选择给出未定义的行为。
如果即使在这种情况下调用析构函数对于您的程序来说确实很重要,那么您应该确保捕获异常main
这样您的代码将是可移植的(在所有符合标准的编译器上工作相同)。例如:
int main() {
try {
A a;
} catch (...) {}
}
这样,像 MSVC 这样的编译器将有义务调用的析构函数B
退出前。