2012-11-12 26 views
3

以下定义是坏风格还是纯错误?也就是说,在初始化一个被认为不正确的值之后抛出是错误的吗?初始化不正确值错误样式后是否抛出异常?

myClass::myClass(int arg) : value(arg) 
    { 
    if (value < 0) 
     throw (myException("Negative value not allowed!")); 
    } 

看来最好使用初始化器列表上分配在体内的价值,从我的理解,如果我前扔后的值已分配不要紧。

+2

你应该更清楚地表明你(恕我直言,纠正我,如果我错了)不要问是否抛出,但如果在初始化成员后抛出,而不是在无效输入的情况下初始化它。现有的答案似乎并没有真正解决这个问题。 –

+1

一些编码准则不会允许这样做。 YMMV在那里。在这种情况下,您通常会提供一个静态构建函数,该函数返回某种状态以及指针作为输出参数。构建器将检查参数并调用将声明为私有的构造函数。我不是这个的粉丝,但它是一种方式。 :) –

+0

有趣的是,你每天都会学到新的东西。 :) – Erika

回答

4

如果value> = 0是一个类不变量,那么你真的只有一些可能性。一种方法是编写ctor以接受unsigned参数,因此仅仅是不可能的。另一个是抛出异常。

但是,如果用户传递的值不能创建有效的对象,那么抛出异常是完全可以接受的(并且通常是正确的)。构造函数的责任是创建一个有效的对象。如果它传递了一个无法创建有效对象的值,那么异常通常是正确的响应。

至于抛出异常:至少在这种情况下,它并不重要。异常将回滚当前对象的创建,因此它永远不会存在。如果首先测试该值的速度要快得多,而不是复制该值,然后在该值无效时将其摧毁,那么可能会有所不同。像int这几乎毫不相关。如果你拥有某种大树,并且只通过查看树的根节点来判断它是否有效,那么首先检查该节点可能会更好,并且只复制三个树如果它是有效的。

后者显然是一种优化,但可以是足够大和足够简单的一种,即使没有分析也可能是值得的(可以说,它只是避免了悲观化的优化)。

+2

他的问题更多地是在初始化成员之后抛出*之间的差异,或者在输入无效的情况下根本不初始化它,而不是关于是否抛出。 –

3

您正在使用构建器类型的初始化器列表,您没有获得任何性能优势,因此为什么不在构造器体内检查后对成员变量进行赋值。在你的情况下,你有一半创建非法对象,而不是一半创建的法律对象。那么为什么要给对象任何无效的状态,以便稍后被破坏。

从构造函数中抛出异常是可以的(在大多数情况下不是析构函数)。 如果你不能对他们传递的值做任何有意义的事情,即将任何负值颠倒为0,那么抛出异常似乎是要做的事情,毕竟你不能创建合法对象。

你可以使用一个unsigned int? 0至4,294,967,295。使得对调用者更加明确,值必须大于0.

+0

我已经稍微改变了一下,以便更加关注他的问题。 –

+1

“那么为什么要给对象任何无效的状态,只是在瞬间被摧毁。” 这就是我想说的,但后来我觉得初始化初始化列表中的所有值是更好的方式,然后我去了。 :) – Erika

0

除非该类在紧密循环中被多次初始化,否则额外函数的性能损失可以忽略不计。这与初始化班不适当的损失相比,这是一个非常小的代价!特别是考虑到“坏值”可能是用户输入的结果,所以产生的问题可能难以报告/排除故障

5

一种替代方案,允许使用初始化程序列表并在初始化值之前抛出,如果参数不在有效范围内:

inline int RequirePositive(int value) 
{  
    if (value < 0) throw (myException("Negative value not allowed!")); 
    return value; 
} 

class myClass { 
    myClass(int arg) : value(RequirePositive(arg)) {} 
}; 
+2

非常优雅的解决方案 – thedayofcondor

-1

我不会这样做。简单地使用使用你的班级的人会明白这是使用它的明智原因的方法。

+1

好吧,只需简单地重新翻译它并不会神奇地使它成为答案。这个问题非常简单,伴随着一个简单的*示例*。这不是从建设者抛出异常,或避免负面投入或可行的替代方案的最佳方式。它只是在初始化之前或之后抛出,不管这个例子是否具有实际价值(当然'unsigned int'是最好的想法),或者抛出异常是个好主意。并说*“忘掉你的问题”*仅仅是一个评论,仅此而已。 –

相关问题