# i、const 和 constexpr 的区别
提问:const 和 constexpr 有什么区别?
回答:const
和 constexpr
都用于创建常量,但它们之间有一些重要的区别。
以下是它们的区别以及如何使用它们:
- const:
const
用于创建只读的常量变量,其值在运行时不能被修改。const
变量必须在声明时初始化,并且可以在运行时计算其值。const
变量可以用于任何数据类型,包括基本数据类型、自定义类、指针等。const
变量的值在编译时或运行时(如果它是一个函数的局部变量)计算。const
变量的值不一定需要在编译时确定,但一旦初始化后就不能更改。const
变量的地址可以传递给函数,但函数不能修改该变量的值。
1 | const int myConstVar = 42; |
- constexpr:
constexpr
用于创建编译时常量,其值在编译时已经确定,不能在运行时修改。constexpr
变量必须在声明时使用常量表达式初始化,这意味着它的值必须在编译时就能确定,通常是通过常量或字面值来计算。constexpr
变量通常用于基本数据类型,如整数、浮点数等,以及由它们构成的类型。constexpr
变量的值在编译时确定,因此在运行时不存在任何计算开销。constexpr
变量通常用于模板编程、数组大小、枚举、函数的参数等需要在编译时确定值的上下文中。constexpr
变量的地址不能传递给函数,因为它们在运行时不存在。
1 | constexpr int myConstexprVar = 42; |
总结:
- 使用
const
创建只读的运行时常量,适用于各种数据类型,值在运行时确定。 - 使用
constexpr
创建编译时常量,适用于基本数据类型和由它们构成的类型,值在编译时确定。 constexpr
变量通常用于需要在编译时确定值的上下文,以提高性能和代码优化。- 选择使用哪种关键字取决于你的需求,如果可以在编译时确定值,则首选
constexpr
。
追问:为什么说 constexpr 变量在运行时不存在?
constexpr
变量在 C++ 中的一个核心概念是编译期常量。这意味着 constexpr
变量的值必须在编译时就能确定,并且这些变量的所有求值都发生在编译时,而不是运行时。因此,通常我们说 constexpr
变量在运行时不存在,这是因为它们的值和用途在编译时已经完全确定,编译器可能会将这些值内联到代码中,而不会真正分配内存存储它们。
编译时常量:
当你声明一个constexpr
变量时,编译器会在编译阶段计算它的值。与const
变量不同,constexpr
的值在编译时已经是固定的,不需要等到运行时。内存分配优化:
编译器可以对constexpr
变量进行优化,可能不会在程序的内存中为其分配特定的地址。编译器会直接使用这些变量的值,并在必要的地方进行值替换或内联,这意味着这些变量在实际运行的二进制程序中没有内存位置或指针,无法传递其地址。编译时求值:
由于constexpr
变量是在编译时求值的,因此它们的存在只是在编译器的上下文中,而不是在程序运行时的内存空间中。例如:1
constexpr int x = 42; // x 在编译时被计算为 42
在这段代码中,x
在编译时已知是42
,编译器可以在整个程序中直接使用42
,而不是存储一个x
变量的实际地址。地址限制:
由于constexpr
变量的这种编译时行为,它们的地址无法在运行时确定,因此你不能将constexpr
变量的地址传递给一个要求运行时地址的函数。例如,以下代码是不允许的:1
2constexpr int x = 42;
int *p = &x; // 错误,不能获取 `constexpr` 变量的地址这是因为
constexpr
变量没有在运行时分配地址,它的值已经完全存在于编译时上下文中。
追问:宏定义也是编译时常量吗,它和 constexpr 相比有何优劣?
回答:#define
宏定义是一种预处理指令,用于在代码中创建符号常量,但它与 constexpr
有一些重要的区别和优劣势:
#define
宏定义:
#define
定义的宏是文本替换,在编译前进行,而不是创建真正的编译时常量。这意味着它们仅仅是在代码中的文本替换,不会被编译器视为独立的常量。#define
宏没有类型,它们只是纯文本替换。这可能导致类型不一致或错误的使用。- 宏的值在编译前无法检查,因此可能会引入难以调试的错误。
- 宏定义的作用域是整个文件,它们在定义点之后的整个文件中都有效。
- 由于是文本替换,宏定义可以用于创建各种代码片段,包括函数、语句等。
constexpr 编译时常量:
constexpr
用于创建真正的编译时常量,它们在编译时已经确定。这意味着它们具有类型和值,可以进行类型检查和优化。constexpr
变量必须具有明确的类型,并且其值必须在编译时可计算。- 编译器可以在编译时检查
constexpr
变量的值,因此可以捕获错误。 constexpr
变量的作用域是常规的变量作用域,可以在需要时限制其可见性。constexpr
变量通常用于编写更安全、更可读和更可维护的代码,因为它们提供了类型检查和更好的错误检测。
总结:
#define
宏定义是文本替换,不是真正的编译时常量,可能引入类型不一致和难以调试的问题。constexpr
是用于创建编译时常量的关键字,提供了类型检查、编译时错误检测和更好的代码优化。- 推荐在 C++ 中使用
constexpr
来创建常量,以提高代码的可维护性和可读性,并避免潜在的问题。
另外,宏定义的作用域限定在单个文件内,它们不会自动影响其他文件。如果你在一个文件中定义了一个宏,其他文件需要包含这个宏的定义才能访问它。通常,宏定义会放在头文件中,然后在多个文件中包含该头文件,以确保多个文件可以共享相同的宏定义。
# i、enum 枚举
C++ 中的枚举(enum)是一种用户自定义的数据类型,用于定义命名的整数常量。枚举提供了一种更可读、更可维护的方式来表示一组相关的命名常量。例如:
1 |
|
注意,在 C++ 中,枚举类型( enum
)的值是常量,一旦定义就不能被改变。枚举提供了一种创建命名整数常量集的方式,这些常量的值是固定的,不能在运行时更改。
与宏定义 define 的区别:
枚举是具有明确定义类型的常量。枚举类型的值在编译时被检查,并且枚举类型是有限的。
枚举是由编译器处理的,可以提供更多的类型安全性和错误检查。