以下定义是不好的风格还是完全错误的?也就是说,在初始化一个被认为不正确的值之后抛出是错误的吗?
myClass::myClass(int arg) : value(arg)
{
if (value < 0)
throw (myException("Negative value not allowed!"));
}
似乎最好使用初始化器列表而不是在正文中分配值,据我所知,如果我在分配值之后或之前抛出并不重要。
以下定义是不好的风格还是完全错误的?也就是说,在初始化一个被认为不正确的值之后抛出是错误的吗?
myClass::myClass(int arg) : value(arg)
{
if (value < 0)
throw (myException("Negative value not allowed!"));
}
似乎最好使用初始化器列表而不是在正文中分配值,据我所知,如果我在分配值之后或之前抛出并不重要。
如果参数不在有效范围内,则允许使用初始化器列表并在初始化值之前抛出的替代方法:
inline int RequirePositive(int value)
{
if (value < 0) throw (myException("Negative value not allowed!"));
return value;
}
class myClass {
myClass(int arg) : value(RequirePositive(arg)) {}
};
如果value
>= 0 是类不变量,那么您实际上只有几种可能性。一种是编写 ctor 来接受unsigned
参数,因此值 <0 根本不可能。另一种是抛出异常。
但是,是的,如果用户传递了一个您无法从中创建有效对象的值,那么抛出异常是完全可以接受的(而且通常是正确的做法)。构造函数的职责是创建一个有效的对象。如果它传递了一个无法从中创建有效对象的值,那么异常通常是正确的响应。
至于何时抛出异常:至少在这种情况下,这并不重要。该异常将回滚当前对象的创建,因此它永远不会存在。如果首先测试值要快得多,而不是复制值然后在它无效时销毁它,它可能会有所作为。这样的事情int
几乎无关紧要。例如,如果您有一棵大树,并且可以通过仅查看树的根节点来判断它是否有效,那么最好先检查该节点,然后只复制三个如果它是有效的。
后者显然是一种优化,但它可以是一个足够大和足够简单的优化,即使没有分析也可能是值得的(可以说,它只是避免悲观化而不是优化)。
您正在为内置类型使用初始化列表,您没有获得任何性能优势,所以为什么不在构造函数体内检查后对成员变量进行赋值。在您的情况下,您创建了一半的非法对象而不是创建了一半的合法对象。那么为什么要给对象任何无效状态,只是为了稍后被销毁。
从构造函数抛出异常是可以的(在大多数情况下,析构函数不是这样)。如果您不能对它们传入的值做任何有意义的事情,即将任何负值变为 0,那么抛出异常似乎是应该做的事情,毕竟您无法创建合法对象。
您可以使用无符号整数吗?0 到 4,294,967,295。使调用者更明确地知道该值必须大于 0。
除非该类在紧密循环中多次初始化,否则额外功能的性能损失可以忽略不计。与未正确初始化的类所能造成的损害相比,这是一个非常小的代价!特别是考虑到“坏值”可能是用户输入的结果,因此产生的问题可能难以报告/故障排除
我不会这样做。只需使用使用您的课程的人会理解这是使用它的合理原因的方法。