C++ 属性: likely, unlikely (C++20 起)

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


 
 
C++ 语言
 
 
属性
(C++23)
(C++14)
likely
(C++20)
(C++17)
(C++11)
unlikely
(C++20)
 

允许编译器为包含该语句的执行路径,比任何其他不包含该语句的执行路径,更可能或更不可能的情况进行优化。

语法

[[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{}; // 确保有副作用
 
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 Likelihood attributes [dcl.attr.likelihood]
  • C++20 标准(ISO/IEC 14882:2020):
  • 9.12.6 Likelihood attributes [dcl.attr.likelihood]