目录
- 1、常量表达式和constexpr关键字
- 2、断言与C++11的静态断言
- 1.1. assert : C语言的宏(Macro),运行时检测。
- 1.2. assert()依赖于NDEBUG 宏
- 1.3. assert 帮助调试解决逻辑bug (部分替代“断点/单步调试”)
- 2.1static_assert (C++11的静态断言 )
- 2.2. 作用:编译时断言检查
- 2.3. static_assert的用途
- 3. 1When to use assertions (何时使用断言)
- 3、声明与定义
- 1. What is "Declare/Declaration" (什么是声明)
- 2. What is "define/definition" (什么是定义)
- 3. Differences between a declaration and a definition (定义与声明的区别)
1、常量表达式和constexpr关键字
常量表达式是编译期间就能计算其结果的表达式。
const修饰的对象既可能是编译期常量,也可能是运行期常量。
constexpr说明符声明可在编译时计算函数或变量的值
constexpr int max(int a , int b) { // c++11 引入 constexprif (a > b) return a; // c++14才允许constexpr函数中有分支循环等else return b;
}
int main() {int m = 1;const int rcm = m++; // rcm是运行期常量const int cm = 4; // 编译期常量,等价于: constexpr int cm = 4;int a1[ max(m , rcm)]; // 错误:m & rcm 不是编译期常量std::array<char , max(cm , 5)> a2; // OK: cm 和 5 是编译期常量
}
const用来告知程序员const指向的内容不可被修改,主要目的是为了避免写出bug。
constexpr在所有编译期常量的地方做限定。使得constexpr修饰的语句在编译期即可计算得到值。让编译期优化代码性能。
constexpr修饰的函数,要满足什么条件才能成为编译期常量表达式?
constexpr 函数的返回值必须在编译时就能被确定。
2、断言与C++11的静态断言
断言是一条检测假设成立与否的语句。
断言assert是一个宏,而非一个函数。
static_assert 是一个关键字,而非一个函数。
1.1. assert : C语言的宏(Macro),运行时检测。
用法:包含头文件 以调试模式编译程序
//assert( bool_expr ); // bool_expr 为假则中断程序
std::array a{ 1, 2, 3 }; //C++17 类型参数推导
for (size_t i = 0; i <= a.size(); i++) {assert(i < 3); //断言:i必须小于3,否则失败std::cout << a[ i ];std::cout << (i == a.size() ? "" : " ");
1.2. assert()依赖于NDEBUG 宏
NDEBUG这个宏是C/C++标准规定的,所有编译器都有对它的支持。
(1) 调试(Debug)模式编译时,编译器不会定义NDEBUG,所以assert()宏起作用。
(2) 发行(Release)模式编译时,编译器自动定义宏NDEBUG,使assert不起作用
如果要强制使得assert()生效或者使得assert()不生效,只要手动 #define NDEBUG 或者 #undef NDEBUG即可。
1.3. assert 帮助调试解决逻辑bug (部分替代“断点/单步调试”)
#undef NDEBUG // 强制以debug模式使用<cassert>
int main() {int i;std::cout << "Enter an int: ";std::cin >> i;assert((i > 0) && "i must be positive"); return 0;
}
上面示例的第6行代码中,若assert中断了程序则表明程序出bug了!程序员要重编代码解决这个bug,而不是把assert()放在那里当成正常程序的一部分
assert断言中所用的表达式可以不是是编译期常量表达式。
2.1static_assert (C++11的静态断言 )
2.1. static_assert ( bool_constexpr, message)
其中两个参数解释如下:
(1) bool_constexpr: 编译期常量表达式,可转换为bool 类型
(2) message: 字符串字面量 ,是断言失败时显示的警告信息。自C++17起,message是可选的
2.2. 作用:编译时断言检查
// 下面的语句能够确保该程序在32位的平台上编译进行。
// 如果该程序在64位平台上编译,就会报错 (例子来自MSDN)
static_assert(sizeof(void *) == 4, "64-bit code generation is not supported.");
2.3. static_assert的用途
常用在模版编程中 ,对写库的作者用处大
在static_assert的第一个参数 bool_constexpr 中不能有变量表达式
3. 1When to use assertions (何时使用断言)
这里我们指的是assert,运行期的断言。
若某些状况是你预期中的,那么用错误处理;若某些状况永不该发生,用断言)
int n{ 1 } , m{ 0 };
std::cin >> n;
assert((n != 0) && "Divisor cannot be zero!"); // 不合适
int q = m / n;
int n{ 1 } , m{ 0 };
do { // 这是修补bug的代码std::cin >> n; // 断言失败后,要解决这个bug
} while (n == 0); // 在这里编写修复bug的代码
assert((n != 0) && "Divisor cannot be zero!");
int q = m / n;
下面的例子说明了在编译期,静态断言就已经执行了,因为array<int,nums>的nums在编译期就应该知道它的值。
3、声明与定义
1. What is “Declare/Declaration” (什么是声明)
“声明”是引入标识符并描述其类型,无论是类型,对象还是函数。编译器需要该“声明”,以便识别在它处使用该标识符。
extern int bar;extern int g(int, int);double f(int, double); // extern can be omitted for function declarationsclass foo; // no extern allowed for type declarations
2. What is “define/definition” (什么是定义)
“定义”实例化/实现这个标识符。链接器需要“定义”,以便将对标识符的引用链接到标识符所表示的实体。
int bar;int g(int lhs, int rhs) {return lhs*rhs;}double f(int i, double d) {return i+d;}class foo {};
3. Differences between a declaration and a definition (定义与声明的区别)
1、定义有时可取代声明,反之则不行
2、标识符可被声明多次,但只能定义一次
3、 定义通常伴随着编译器为标识符分配内存