从构造函数初始化程序引发异常 [英] Throw exception from constructor initializer
问题描述
从构造函数初始值设定项引发异常的最佳方法是什么?
What is the best way to throw exception from the constructor initializer?
例如:
class C {
T0 t0; // can be either valid or invalid, but does not throw directly
T1 t1; // heavy object, do not construct if t0 is invalid, by throwing before
C(int n)
: t0(n), // throw exception if t0(n) is not valid
t1() {}
};
我想也许可以做包装纸,例如 t0(throw_if_invalid(n))
。
I thought maybe making wrapper, e.g. t0(throw_if_invalid(n))
.
如何处理此类情况?
推荐答案
我认为有多种解决方法。据我了解, n
只能接受特定范围的数字。为此,您甚至可能阻止构造函数运行:
There are multiple ways of going about this, I think. From what I understand, n
can only take on a specific range of numbers. For that, you might prevent the constructor from even being run:
template <typename T, T Min, T Max>
class ranged_type_c
{
public:
typedef T value_type;
ranged_type_c(const value_type& pX) :
mX(pX)
{
check_value();
}
const value_type& get(void) const
{
return mX;
}
operator const value_type&(void) const
{
return get();
}
// non-const overloads would probably require a proxy
// of some sort, to ensure values remain valid
private:
void check_value(void)
{
if (mX < Min || mX > Max)
throw std::range_error("ranged value out of range");
}
value_type mX;
};
可能会更加充实,但这就是想法。现在您可以确定范围:
Could be more fleshed out, but that's the idea. Now you can clamp the range:
struct foo_c
{
foo_c(ranged_value_c<int, 0, 100> i) :
x(i)
{}
int x;
};
如果传递的值不为0-100,则将抛出上述错误。
If you pass a value that does not lie from 0-100, the above would throw.
在运行时,我认为您的最初想法是最好的:
At runtime, I think your original idea was best:
template <typename T>
const T& check_range(const T& pX, const T& pMin, const T& pMax)
{
if (pX < pMin || pX > pMax)
throw std::range_error("ranged value out of range");
return pValue;
}
struct foo
{
foo(int i) :
x(check_range(i, 0, 100))
{}
int x;
}
就是这样。与上面相同,但是0和100可以由对某个函数的调用来代替,该函数返回有效的最小值和最大值。
And that's it. Same as above, but 0 and 100 can be replaced with a call to some function that returns the valid minimum and maximum.
如果您最终使用了对函数的调用要获得有效范围(建议,将杂波降到最低并提高组织水平),我会添加重载:
If you do end up using a function call to get valid ranges (recommended, to keep clutter to a minimum and organization higher), I'd add an overload:
template <typename T>
const T& check_range(const T& pX, const std::pair<T, T>& pRange)
{
return check_range(pX, pRange.first, pRange.second); // unpack
}
要允许这样的事情:
std::pair<int, int> get_range(void)
{
// replace with some calculation
return std::make_pair(0, 100);
}
struct foo
{
foo(int i) :
x(check_range(i, get_range()))
{}
int x;
}
如果我要选择的话,即使范围是编译时。即使优化程度不高,编译器仍会生成相同的代码,而且比类版本少笨拙且可读性更强。
If I were to choose, I'd pick the runtime methods even if the range was compile-time. Even with low optimization the compiler will generate the same code, and it's much less clumsy and arguably cleaner to read than the class version.
这篇关于从构造函数初始化程序引发异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!