Namespaces
Variants

C++ attribute: likely, unlikely (since C++20)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
Attributes
(C++23)
(C++11) (until C++26)
(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 : 레이블을 통해 폴스루(fall through)되더라도 마찬가지입니다.

예제

#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" : "차이점") << '\n';
    auto benchmark = [](auto fun, auto rem)
    {
        const auto start = std::chrono::high_resolution_clock::now
**변경 없음** - C++ 특정 용어와 코드 태그 내 내용은 번역하지 않음();
        for (auto size{1ULL}; size != 10'000'000ULL; ++size)
            sink = fun(gen_random());
        const std::chrono::duration
(번역 참고: HTML 태그와 속성은 번역하지 않았으며, C++ 관련 용어(std::chrono::duration)는 원문 그대로 유지했습니다)<double> diff =
            std::chrono::high_resolution_clock::now() - start;
        std::cout << "시간: " << std::fixed << std::setprecision(6) << diff.count()
                  << " 초 " << rem << std::endl; 
    };
    benchmark(with_attributes::cos, "(속성 포함)");
    benchmark(no_attributes::cos, "(속성 없음)");
    benchmark([](double t) { return std::cos(t); }, "(std::cos)");
}

가능한 출력:

x = 0.125
0.99219766722932900560039115589461289346218109130859375
0.99219766722932900560039115589461289346218109130859375
동일함
x = 0.25
0.96891242171064473343022882545483298599720001220703125
0.96891242171064473343022882545483298599720001220703125
동일함
x = 0.5
0.8775825618903727587394314468838274478912353515625
0.8775825618903727587394314468838274478912353515625
동일함
x = 1.490116119384765625e-08
0.99999999999999988897769753748434595763683319091796875
0.99999999999999988897769753748434595763683319091796875
동일함
시간: 0.579122 초 (속성 포함)
시간: 0.722553 초 (속성 없음)
시간: 0.425963 초 (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]