如何将断言放置在类初始化列表之前?

Arc*_*Arc 4 c++ constructor assert design-by-contract initialization

在调用初始化列表之前是否可以断言类构造函数上的参数?

class Foo
{
    int m_lower;
    int m_upper;
    unsigned int m_delta;

  public:
    Foo(int t_lower, int t_upper) :
        assert(t_lower < t_upper),  // Assert here, before initialisation of fields.
        m_lower(t_lower),
        m_upper(t_upper),
        m_delta(t_upper - t_lower)
    {
       // Assert could be made here, but m_delta would have underflowed if t_upper < t_lower.  
    }
}
Run Code Online (Sandbox Code Playgroud)

在初始化列表之前断言的好处是可以立即提出每个字段的初始化要求,并且不必对具有相同要求的每个初始化进行多次检查。虽然 m_delta 的初始化可以在初始化方法中进行init_delta,但如果多个值具有相同的要求,t_upper > t_lower则必须将断言放置在每个值中(以防先前的断言被删除)。如果放置在构造函数本身中,则一个或多个字段的初始化可能已经失败(出现比下溢更戏剧性的情况)。

如果放置在初始化列表的顶部,则合约在检查时对用户来说是清楚的,并且会在发生任何错误(例如本例中的下溢)之前标记错误。

上述案例只是该问题的一个简化示例。我知道有更好的方法来解决上述特定问题(abs() 等)。

感谢您的帮助和建议!

Bar*_*mar 6

您可以使用逗号运算符:

  public:
    Foo(int t_lower, int t_upper) :
        m_lower((assert(t_lower < t_upper), t_lower)),
        m_upper(t_upper),
        m_delta(t_upper - t_lower)
    {
        ...
    }
Run Code Online (Sandbox Code Playgroud)

逗号运算符的操作数从左到右计算,并使用右侧的值作为结果。

请注意,初始化的顺序基于成员变量在类中声明的顺序,而不是初始化列表中的顺序。所以你应该把assert()调用放在第一个成员变量的初始化中。