C++ 屬性: likely, unlikely (C++20 起)
來自 cppreference.com
允許編譯器對包含該語句的執行路徑比不包含該語句的任何替代執行路徑更可能或更不可能的情況進行最佳化。
目錄 |
[編輯] 語法
[[likely]]
|
(1) | ||||||||
[[unlikely]]
|
(2) | ||||||||
[編輯] 解釋
這些屬性可以應用於標籤和語句(除了宣告語句)。它們不能同時應用於同一個標籤或語句。
1) 應用於語句,允許編譯器最佳化,使得包含該語句的執行路徑比不包含該語句的任何替代執行路徑更有可能。
2) 應用於語句,允許編譯器最佳化,使得包含該語句的執行路徑比不包含該語句的任何替代執行路徑更不可能。
當且僅當執行路徑包含跳轉到該標籤時,才認為該路徑包含該標籤。
int f(int i) { switch (i) { case 1: [[fallthrough]]; [[likely]] case 2: return 1; } return 2; }
i == 2 被認為比 i
的任何其他值更有可能,但 [[likely]] 對 i == 1 的情況沒有影響,即使它穿過 case 2: 標籤。
[編輯] 示例
執行此程式碼
#include <chrono> #include <cmath> #include <iomanip> #include <iostream> #include <random> namespace with_attributes { constexpr double pow(double x, long long n) noexcept { if (n > 0) [[likely]] return x * pow(x, n - 1); else [[unlikely]] return 1; } constexpr long long fact(long long n) noexcept { if (n > 1) [[likely]] return n * fact(n - 1); else [[unlikely]] return 1; } constexpr double cos(double x) noexcept { constexpr long long precision{16LL}; double y{}; for (auto n{0LL}; n < precision; n += 2LL) [[likely]] y += pow(x, n) / (n & 2LL ? -fact(n) : fact(n)); return y; } } // namespace with_attributes namespace no_attributes { constexpr double pow(double x, long long n) noexcept { if (n > 0) return x * pow(x, n - 1); else return 1; } constexpr long long fact(long long n) noexcept { if (n > 1) return n * fact(n - 1); else return 1; } constexpr double cos(double x) noexcept { constexpr long long precision{16LL}; double y{}; for (auto n{0LL}; n < precision; n += 2LL) y += pow(x, n) / (n & 2LL ? -fact(n) : fact(n)); return y; } } // namespace no_attributes double gen_random() noexcept { static std::random_device rd; static std::mt19937 gen(rd()); static std::uniform_real_distribution<double> dis(-1.0, 1.0); return dis(gen); } volatile double sink{}; // ensures a side effect int main() { for (const auto x : {0.125, 0.25, 0.5, 1. / (1 << 26)}) std::cout << std::setprecision(53) << "x = " << x << '\n' << std::cos(x) << '\n' << with_attributes::cos(x) << '\n' << (std::cos(x) == with_attributes::cos(x) ? "equal" : "differ") << '\n'; auto benchmark = [](auto fun, auto rem) { const auto start = std::chrono::high_resolution_clock::now(); for (auto size{1ULL}; size != 10'000'000ULL; ++size) sink = fun(gen_random()); const std::chrono::duration<double> diff = std::chrono::high_resolution_clock::now() - start; std::cout << "Time: " << std::fixed << std::setprecision(6) << diff.count() << " sec " << rem << std::endl; }; benchmark(with_attributes::cos, "(with attributes)"); benchmark(no_attributes::cos, "(without attributes)"); benchmark([](double t) { return std::cos(t); }, "(std::cos)"); }
可能的輸出
x = 0.125 0.99219766722932900560039115589461289346218109130859375 0.99219766722932900560039115589461289346218109130859375 equal x = 0.25 0.96891242171064473343022882545483298599720001220703125 0.96891242171064473343022882545483298599720001220703125 equal x = 0.5 0.8775825618903727587394314468838274478912353515625 0.8775825618903727587394314468838274478912353515625 equal x = 1.490116119384765625e-08 0.99999999999999988897769753748434595763683319091796875 0.99999999999999988897769753748434595763683319091796875 equal Time: 0.579122 sec (with attributes) Time: 0.722553 sec (without attributes) Time: 0.425963 sec (std::cos)
[編輯] 參考
- C++23 標準 (ISO/IEC 14882:2024)
- 9.12.7 可能性屬性 [dcl.attr.likelihood]
- C++20 標準 (ISO/IEC 14882:2020)
- 9.12.6 可能性屬性 [dcl.attr.likelihood]