目錄
- 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、 定義通常伴隨著編譯器為標識符分配內存