您希望初始化非默认可构造成员,但需要在构造之前检查约束.
例:
(请注意,这只是一个例子.在这种特定情况下是否应该使用无符号整数是可以讨论的,但问题实际上是关于你想检查构造函数的一般情况)
你有以下课程:
class Buffer { public: Buffer() = delete; Buffer(int size) noexcept; }; .... class RenderTarget { public: .... private: int width_,height_; Buffer surface_; };
构造函数必须检查整数参数的有效性:
RenderTarget::RenderTarget(int width,int height) : width_(width),height_(height),surface_(width_*height) { if (width_<0 || height_<0) throw std::logic_error("Crizzle id boom shackalack"); }
注意Buffer没有默认构造函数,真正的构造函数是noexcept,即没有办法捕获错误.
当整数参数为负数时,已经有一个hosed surface_.在使用约束值之前进行约束检查会更好.可能吗?
解决方法
您可以使用所谓的命名构造函数(另请参阅http://www.parashift.com/c++-faq/named-ctor-idiom.html),并将构造函数设为私有:
class RenderTarget { private: RenderTarget (int w,int h) : width_(w),height_(h),buffer_(w*h) { // NOTE: Error checking completely removed. } public: static RenderTarget create(int width,int height) { // Constraint Checking if (width<0 || height<0) throw std::logic_error("Crizzle id boom shackalack"); return RenderTarget(width,height); }
如果您有多个可能不明确使用的构造函数,则命名构造函数很有用,例如:温度< - 摄氏度|华氏温度|开尔文或距离< - 米|院子里| Cubit |公里|.公里.... 否则,(个人意见)他们强加了意想不到的抽象,也分散了注意力,应该避免. 三元运算符和抛出 C允许在[expr.cond]中将一个或两个操作数中的throw-expression用于三元运算符(?: – operator):
RenderTarget(int w,int h) : width_(w<0 ? throw std::logic_error("Crizzle id boom shackalack") : w),height_(h<0 ? throw std::logic_error("Crizzle id boom shackalack") : h),surface_(w*h) {}
如果你不存储参数,你也可以在表达式中使用?:当然:
RenderTarget(int w,int h) : surface_( (w<0 ? throw std::logic_error("Crizzle id boom shackalack") : w) * (h<0 ? throw std::logic_error("Crizzle id boom shackalack") : h) ) {}
或者您将前置条件检查合并到一个操作数中:
RenderTarget(int w,int h) : surface_( (w<0||h<0) ? throw std::logic_error("Crizzle id boom shackalack") : w * h ) {}
使用带有throw-expression内联的?: – 运算符对于基本约束检查非常好,并且避免必须回退到使用默认构造函数(如果有的话),然后在构造函数体内进行“实际初始化”.
对于更复杂的场景,这可能会变得有点笨拙.
静态私人会员
当然,可以使用两全其美的优点:
private: static bool check_preconditions(int width,int height) { if (width<0 || height<0) return false; return true; } public: RenderTarget(int w,int h) : surface_( check_preconditions(w,h) ? w*h : throw std::logic_error("Crizzle id boom shackalack") ) {}
…或者您需要为预处理检查所需的任何成员编写静态函数:
private: static Buffer create_surface(int width,int height) { if (width<0 || height<0) throw std::logic_error("Crizzle id boom shackalack") return Buffer(width*height); } public: RenderTarget(int w,int h) : surface_(create_surface(w,h)) {}
这很好,因为您手头有完整的C -machinery进行约束检查,例如可以轻松添加日志记录.它可以很好地扩展,但对于简单的场景来说不那么方便.