如何防止初始化列表中的错误值?

How to prevent wrong values in an initializer list?

当您编写构造函数时,您有机会在超出范围或主体中其他不需要的情况下测试参数的值。

class a
{
  int b;
public:
  a(int c)
  {
    if(c < MIN_ALLOWED || c > MAX_ALLOWED)
    {
      // Take some measure
    }
    else
    {
      b = c;
    }
  }
};

但是当你处理 const 成员时,它们应该通过初始化列表来初始化,那么,在这种情况下,如何防止不需要的值?

class a
{
  const int b;
public:
  a(int c) : b(c)
  {
    // How to control "c" value?!...
  }
};

可以将变量的校验和修改委托给一个函数。

class a {
 public:
  a(int c) : b(ValidateAndTransformInputParameter(c)) {}
 private:
  const int b;
  int ValidateAndTransformInputParameter(int d) const {
    if (d < 100) {
      d = 100;
    }
    return d;
  }
};

创建函数:

class a {
    int const b;

public:
    a(int const c)
        : b { initializeB(c) }
    {
    }

private:
    static int initializeB(int const c)
    {
        if (c < MIN_ALLOWED || c > MAX_ALLOWED) {
            // Take some mesure
            return -1; // example
        }
        return c;
    }
};
class a
{
    const int b;
public:
    a(int c) : b((c < MIN_ALLOWED || c > MAX_ALLOWED) ? throw std::logic_error("bad") : c)
    {
        // How to control "c" value?!...                                                                        
    }
};

主要有以下三种方式:

  1. 使用逗号运算符链接验证:

    a(int c) : b(validate(c), c) {}
    

    请记住,初始化程序严格按声明顺序深度优先执行,忽略虚拟继承。

  2. 使用三元运算符:

    a(int c) : b(validate(c) ? c : throw 0) {}
    

    如果真的是一次性的,这需要最少的 folderol。

  3. 使用转换和验证 class 或函数:

    a(int c) : b(process(c)) {}
    

可选地,它们可以与 ctor-chaining 结合使用,尤其是当多个结果来自处理输入时:

private:
    struct process {
        ...
    };
    a(process x) : b(x.b), c(x.c), d(x.d) {}
public:
a(int c) : a(process(c)) {}

以上所有答案都很好并且有效...但为了避免我们忘记,您还可以这样做:

class a
{
    public:
        a(int c) : b([=]() -> int {
            if (c < MIN_ALLOWED || c > MAX_ALLOWED)
                throw std::logic_error("b");
            return c;
        }()) {}
    private:
        int b;

};

虽然在我看来它看起来很糟糕,在初始化列表中有一个 lambda,但它仍然是可能的。