如何防止初始化列表中的错误值?
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?!...
}
};
主要有以下三种方式:
使用逗号运算符链接验证:
a(int c) : b(validate(c), c) {}
请记住,初始化程序严格按声明顺序深度优先执行,忽略虚拟继承。
使用三元运算符:
a(int c) : b(validate(c) ? c : throw 0) {}
如果真的是一次性的,这需要最少的 folderol。
使用转换和验证 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,但它仍然是可能的。
当您编写构造函数时,您有机会在超出范围或主体中其他不需要的情况下测试参数的值。
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?!...
}
};
主要有以下三种方式:
使用逗号运算符链接验证:
a(int c) : b(validate(c), c) {}
请记住,初始化程序严格按声明顺序深度优先执行,忽略虚拟继承。
使用三元运算符:
a(int c) : b(validate(c) ? c : throw 0) {}
如果真的是一次性的,这需要最少的 folderol。
使用转换和验证 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,但它仍然是可能的。