C++ 属性: assume (C++23 起)

出自cppreference.com
< cpp‎ | language‎ | attributes


 
 
C++ 語言
 
 
屬性
assume
(C++23)
(C++11)(C++26 前)
(C++14)
(C++20)
(C++17)
(C++11)
(C++20)
 

指示可以假設給定的表達式在給定位置總是求值為 true,以允許編譯器根據給定的信息進行優化。

目錄

[編輯] 語法

[[assume( 表達式 )]]
表達式 - (無括弧的逗號表達式以外的)任意表達式

[編輯] 解釋

[[assume]] 只能被應用到空語句,如 [[assume(x > 0)]];。該語句被稱為一條假設 。

表達式 會按語境轉換到 bool,但不會求值(依然會潛在求值)。

  • 如果轉換後的表達式 在假設出現的位置求值為 true,那麼假設不會有任何效果。
  • 否則對假設求值具有運行時未定義行為

[編輯] 註解

因為假設在不成立時會導致運行時未定義行為,所以必須小心使用它們。它們不用來提供函數的前提條件文檔或者診斷是否違反前條件。另外,不要未經檢驗就假設編譯器實際會使用任何特定的假設。

一種正確用法是連續使用斷言和假設:

assert(x > 0);     // 在 NDEBUG 没有定义时检查条件,如果条件不成立则触发断言
[[assume(x > 0)]]; // 在 NDEBUG 定义时提供优化机会

[編輯] 示例

#include <cmath>
 
void f(int& x, int y)
{
    void g(int);
    void h();
 
    [[assume(x > 0)]]; // 编译器可以假设 x 是正数
 
    g(x / 2); // 可以生成更高效的代码
 
    x = 3;
    int z = x;
 
    [[assume((h(), x == z))]]; // 编译器可以假设在调用 h 后 x 的值保持相同
                               // 该假设本身不会调用 h
 
    h();
    g(x); // 编译器可以用 g(3); 替换该语句
 
    h();
    g(x); // 编译器不能用 g(3); 替换该语句
          // 假设只在它出现的地方适用
 
    z = std::abs(y);
 
    [[assume((g(z), true))]]; // 编译器可以假设 g(z) 会返回
 
    g(z); // 根据上面和下面的假设,编译器可以用 g(10); 替换该语句
 
    [[assume(y == -10)]]; // 这里 y != -10 的情况下行为未定义
 
    [[assume((x - 1) * 3 == 12)]];
 
    g(x); // 编译器可以用 g(5); 替换该语句
}

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 出版時的行為 正確行為
CWG 2924 C++11 違背假設會導致未定義行為 會導致運行時未定義行為

[編輯] 引用

  • C++23 標準(ISO/IEC 14882:2024):
  • 9.12.3 Assumption attribute [dcl.attr.assume]

[編輯] 參閱

 (C++23)
標記執行的不可抵達點
(函數) [編輯]
contract_assert 語句 (C++26) 在執行中驗證一項內部條件[編輯]

[編輯] 外部鏈接

1.  Clang 語言擴展文檔:__builtin_assume
2.  Clang 屬性參考文檔:assume
3.  MSVC 文檔:__assume 內建函數。
4.  GCC 文檔:__attribute__((assume(...)))