从构造函数初始化程序引发异常 [英] Throw exception from constructor initializer

查看:109
本文介绍了从构造函数初始化程序引发异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从构造函数初始值设定项引发异常的最佳方法是什么?

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆