断言
简介
在程序设计中,断言(assertion)是一种放在程序中的一阶逻辑(如一个结果为真或是假的逻辑判断式),目的是为了标示与验证程序开发者预期的结果-当程序运行到断言的位置时,对应的断言应该为真。若断言不为真时,程序会中止运行,并给出错误消息。
C++断言包含运行期检查断言、静态断言
- 运行期检查的断言
在程序运行时,可以用断言检查程序开发时的假设,确认这些假设是否成立。
存在先天的缺点:可能有改变存储器数据或是线程时序的风险,因此需小心的处理断言,确认断言在程序中没有其他的副作用。 - 静态断言(c++11以上,static_assert)
只在编译期间检查的断言称为静态断言,静态断言必需配合清楚的注解说明。
介绍static_assert
程序结构中的断言有助于在不使用第三方程式库的情形下,应用测试驱动开发的开发方式。
示例
运行时期检查的断言
- 头文件:
所需引用头文件 | 基本用法 |
---|---|
assert.h(C语法)、cassert(C++) | assert(bool_constexpr) |
assert.h与cassert : 简而言之,#include<assert.h>是c语言引用库的写法,C++为了兼容C语言也可以这么写,但是可能缺少C++库的某些特性(比如c99中中的assert.h没有static_assert宏,C++14的cassert中包含);编写C++代码时,最好还是选择#include 的写法。
规则 | 详细 |
---|---|
规则一 | 断言必须使用宏定义,禁止直接调用系统提供的assert() |
规则二 | 运行时可能会导致的错误,严禁使用断言 |
规则三 | 严禁在断言内改变运行环境 |
规则四 | 不要将多条语句放在同一个断言中(无法知道到底是哪个条件出错) |
规则二详细说明:
环境等外界因素导致的错误,不能使用断言进行判断;断言属于契约式设计中的前置条件,任何断言失败,一定标识着某处代码的错误,需要更改代码,类比编译错误;
如果代码书写完全正确,但因外界环境或者用户操作仍然可能发生的事件,都不适合用断言;请使用条件判断或异常进行处理。
错误示例:
FILE *fp = fopen(path,"r");
ASSERT(fp != NULL); //文件有可能打开失败
断言使用示例:
包含头文件assert_self.h、main.cpp
/**********************************************************************
>File Name: assert_self.h
>Author: sunrise
>Mail: [email protected]
>Created Time: Fri 08 Mar 2019 04:52:55 AM EST
*************************************************************/
#include<iostream>
#include<cassert>
using namespace std;
#ifndef ASSERT_SELF_H
#define ASSERT_SELF_H
#ifdef DEBUG // 定义宏变量,来控制程序是否打开断言
#define ASSERT(f) assert(f)
#else
#define ASSERT(f) ((void)0)
#endif
#endif
/**********************************************************************
>File Name: main.cpp
>Author: sunrise
>Mail: [email protected]
>Created Time: Fri 08 Mar 2019 04:56:03 AM EST
*************************************************************/
#include<iostream>
#include "assert_self.h"
using namespace std;
int main()
{
int i = 1;
ASSERT(i > 2);
cout << "success !!!" << endl;
return 0;
}
通过宏在编译阶段进行控制(规则一):
打开ASSERT宏:
编译命令(使用-D 定义宏):
g++ main.cpp assert_self.h --std=c++11 -D DEBUG -o assert
执行结果,断言生效:
assert: main.cpp:15: int main(): Assertion `i > 2’ failed.
Aborted (core dumped)
关闭ASSERT宏,正常编译即可
编译命令:
g++ main.cpp assert_self.h --std=c++11 -o assert
执行结果:
success !!!
静态断言
C11 (程序标准版本)及C++11可以用static_assert支持静态断言。
示例:
/**********************************************************************
>File Name: test.cpp
>Author: sunrise
>Mail: [email protected]
>Created Time: Fri 08 Mar 2019 03:15:51 AM EST
*************************************************************/
#include<iostream>
using namespace std;
#include <type_traits>
template <class T>
void swap1(T& a, T& b)
{
static_assert(std::is_copy_constructible<T>::value,"Swap requires copying");
static_assert(std::is_nothrow_copy_constructible<T>::value
&& std::is_nothrow_copy_assignable<T>::value,
"Swap requires nothrow copy/assign");
auto c = b;
b = a;
a = c;
}
template <class T>
struct data_structure
{
static_assert(std::is_default_constructible<T>::value,
"Data Structure requires default-constructible elements");
};
struct no_copy
{
no_copy ( const no_copy& ) = delete;
no_copy () = default;
};
struct no_default
{
no_default () = delete;
};
int main()
{
const int i = 2;
static_assert(i > 3,"i should large than 3");
int a, b;
swap1(a, b);
no_copy nc_a, nc_b;
//swap1(nc_a, nc_b); // 1
data_structure<int> ds_ok;
data_structure<no_default> ds_error; // 2
return 0;
}
备注:std::is_copy_constructible::value这些函数是库函数,判断函数构造函数
编译命令:
g++ test.cpp --std=c++11 -o test
执行结果:
test.cpp: In function ‘int main()’:
test.cpp:47:5: error: static assertion failed: i should large than 3
static_assert(i > 3,"i should large than 3");
^
test.cpp: In instantiation of ‘struct data_structure<no_default>’:
test.cpp:55:32: required from here
test.cpp:29:5: error: static assertion failed: Data Structure requires default-constructible elements
static_assert(std::is_default_constructible<T>::value,
^