防御式编程是防御式设计的一种形式,旨在确保软件在意料之外的情况下仍能继续正常运行。防御式编程实践
防御式编程是一种从以下方面改进软件和源代码的方法:
- 总体质量——减少软件缺陷和问题的数量。
- 让源代码易于理解——源代码应当可读、可理解,从而能够通过代码审计。
- 让软件在面对意外输入或用户操作时仍表现出可预测的行为。
在 C++ 中采用防御式编程方法的惯用做法是使用 assert 机制:
void test( int *p ) {
assert( p != 0 );
if (p == 0)
return;
// use p.
}断言是在开发期间使用的代码——通常是一个例程或宏——让程序在运行时进行自我检查。当断言为真时,意味着一切按预期运行;当它为假时,意味着检测到了代码中的意外错误。
断言在大型复杂程序和高可靠性程序中尤为有用。它们能帮助程序员更快地发现不匹配的接口假设、修改代码时悄悄引入的错误等等。
断言通常接受两个参数:一个描述应当成立的假设的布尔表达式,以及假设不成立时要显示的消息。
新的 C++ 标准为防御式编程提供了哪些机制?
C++11 与 static_assert
C++11 引入了使用新关键字 static_assert 在编译期测试断言的新方式。这一特性非常适合为模板参数添加约束,正如下面的 Folly 源代码中的模板类所示:

C++17 与 [[nodiscard]] 属性
声明为[[nodiscard]]的函数,其返回值不应被调用者忽略。如果您希望确保调用者检查返回值,这会很有用:您可以强制落实函数的代码契约,使调用者不会跳过返回值。
例如,如果 do_something 函数的返回值未被使用,编译器将发出警告。
[[nodiscard]] error do_something (thing&);
do_something(my_thing); // Warning: ignored return valueC++20 与契约
这是新标准在防御式编程方面的一项重大改进:它将为契约式设计提供众多设施与特性。
您可以在此处查看该提案。
让我们先看看契约特性提案中使用的术语:
1. A 前置条件 is a predicate that should hold upon entry into a function. It expresses a function's expectation on its arguments and/or the state of objects that may be used by the function. Preconditions are expressed by expectsattributes (7.6.10).
2. A 后置条件 is a predicate that should hold upon exit from a function. It expresses the conditions that a function should ensure for the return value and/or the state of objects that may be used by the function. Postconditions are expressed by ensures attributes (7.6.11).
3. An 断言 is a predicate that should hold at its point in a function body. It expresses the conditions, on objects that accessible at its point in a body, that must be satisfied. Assertions are expressed by assert attributes (7.6.12).
4. Preconditions, postoconditions, and assertions are collectively called 契约. A contract shall have no observable effect in a correct program (a program where all contracts would be satisified, if they were evaluated).
5. Contract attributes are followed by a 条件表达式, which is a potentially evaluated expression (3.2).
下面是这一新特性的使用示例:
void push(int x, queue & q) [[expects: !q.full()]] [[ensures: !q.empty()]] { //... [[assert: q.is_valid()]]; //... }C++20 标准将带来防御式编程实践者一直期待已久的特性,让契约式设计不再依赖外部库或框架。
