如何在C++构造函数初始化列表中抛出异常?
在构造函数初始化列表中抛出异常是否符合C++标准?
当构造函数的参数超出范围时,我们希望抛出异常。在构造函数体内实现这一点很简单:
class A { int x; enum { MAX = 10 }; public: A(int x_) { if (x_ > MAX) throw 1; x = x_; } };
但如果想用初始化列表直接初始化成员x,该怎么实现参数校验并抛出异常呢?
你发现GCC、MSVC和Clang都接受下面这种写法:
class A { int x; enum { MAX = 10 }; public: A(int x_) : x(x_ <= MAX ? x_ : throw 1) {} // 注:你代码里的`_x`是笔误,应该是`x_` };
这种在初始化列表的直接初始化语句中抛出异常的写法完全符合C++标准。
为什么符合标准?
C标准允许在成员初始化器中使用任意合法表达式,而throw表达式本身就是C中的合法表达式(它属于“抛出表达式”,类型为void,但在三元运算符中,当其中一个分支是throw时,整个表达式的类型由另一个有效分支决定)。
当在成员初始化过程中抛出异常时,构造函数会立即终止:已经完成初始化的成员会按照初始化的逆序被销毁,随后异常会被传播到构造函数的调用处——这和在构造函数体内抛出异常的行为完全一致。
更易读的替代写法
虽然三元运算符的写法可行,但对于更复杂的校验逻辑,使用辅助函数会更清晰:
class A { int x; enum { MAX = 10 }; static int validate_x(int x_) { if (x_ > MAX) { throw 1; // 实际项目中建议抛出std::invalid_argument这类标准异常 } return x_; } public: A(int x_) : x(validate_x(x_)) {} };
这种方式不仅可读性更好,还能将校验逻辑复用,也方便添加更复杂的检查条件。
内容的提问来源于stack exchange,提问作者albert
相关产品推荐
相关产品推荐

