kmi*_*las 7 c++ constructor exception-handling try-catch c++11
当构造函数抛出异常时,如何防止创建对象?
在下面的示例中,我创建了一个Month()类,其int month_
属性的合法值在1到12的范围内.I实例化12月,或者 dec
,使用整数值13.抛出异常,因为它应该是,但仍然创建了该对象.然后调用析构函数.
如何在抛出异常时中止创建类实例?
OUTPUT
-- Month() constructor called for value: 2
-- Month() constructor called for value: 6
-- Month() constructor called for value: 13
EXCEPTION: Month out of range
2
6
13
-- ~Month() destructor called.
-- ~Month() destructor called.
-- ~Month() destructor called.
Press any key to exit
Run Code Online (Sandbox Code Playgroud)
最小,完整和可验证的例子
#include <iostream>
#include <string>
class Month {
public:
Month(int month) {
std::cout << "-- Month() constructor called for value: " << month << std::endl;
try {
// if ((month < 0) || month > 12) throw 100; Good eye, Nat!
if ((month < 1) || month > 12) throw 100;
} catch(int e) {
if (e == 100) std::cout << "EXCEPTION: Month out of range" << std::endl;
}
month_ = month;
}
~Month() {
std::cout << "-- ~Month() destructor called." << std::endl;
}
int getMonth()const { return month_; }
private:
int month_;
};
int makeMonths() {
Month feb(2), jun(6), dec(13);
std::cout << feb.getMonth() << std::endl;
std::cout << jun.getMonth() << std::endl;
std::cout << dec.getMonth() << std::endl;
return 0;
}
int main() {
makeMonths();
std::cout << "Press any key to exit"; std::cin.get();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Rak*_*111 15
如何在抛出异常时中止创建类实例?
好吧,你在构造函数中抛出一个异常.但有一个问题:不要抓住它!
如果你抓住它,就会发生异常从未发生过.你抓住了它,所以它不再上调调用堆栈了.所以创建了对象,因为就任何人而言,构造函数都没有抛出异常.
如果你catch
从构造函数中删除子句,你可能会得到类似的东西:
-- Month() constructor called for value: 2
-- Month() constructor called for value: 6
-- Month() constructor called for value: 13
terminate called after throwing an instance of 'int'
[1] 28844 abort (core dumped) ./main
Run Code Online (Sandbox Code Playgroud)
这里,构造函数引发了一个异常,这次它在构造函数之外的调用堆栈上升,因为没有人在构造函数中捕获它.然后它会进入makeMonths
,它也没有被捕获,然后到达main
,它也没有被捕获,因此程序异常终止.
Sof*_*re2 10
默认情况下,在构造函数中抛出异常应该可以防止析构函数被调用.但是,您正在捕获异常并处理它.
您可以在catch中抛出一个新异常,然后可以在此范围之外看到,以便不调用析构函数.
小智 5
如何在抛出异常时中止类实例的创建?
你只是(重新)抛出异常,而不是捕捉它,我建议抛出一个std::invalid_argument
或std::out_of_range
异常:
class Month {
public:
Month(int month) {
std::cout << "-- Month() constructor called for value: " << month << std::endl;
if ((month < 0) || month > 12)
throw std::invalid_argument("month");
// or throw std::out_of_range("month");
else
month_ = month;
}
~Month() {
std::cout << "-- ~Month() destructor called." << std::endl;
}
int getMonth()const { return month_; }
private:
int month_;
};
Run Code Online (Sandbox Code Playgroud)
您创建的实例Month
将被堆栈展开机制正确丢弃。永远不会创建实例,因此根本不会调用析构函数。
请参阅现场示例。
为了使异常更具信息性,您可以使用以下内容:
if ((month < 0) || month > 12) {
throw std::out_of_range("'month' parameter must be in the range of 1-12.");
}
Run Code Online (Sandbox Code Playgroud)
此外,如果您不喜欢在构造函数的主体中初始化成员变量(就像我经常做的那样)
您可以为有效性检查代码引入一个lambda 表达式:
auto month_check = [](int month) {
if ((month < 0) || month > 12) {
throw std::out_of_range("'month' parameter must be in the range of 1-12.");
}
return month;
};
class Month {
public:
Month(int month) : month_(month_check(month)) {
std::cout << "-- Month() constructor called for value: " << month << std::endl;
}
~Month() {
std::cout << "-- ~Month() destructor called." << std::endl;
}
int getMonth()const { return month_; }
private:
int month_;
};
Run Code Online (Sandbox Code Playgroud)