C++의 특성

C++ 표준은 공통 특성 집합을 정의합니다. 또한 컴파일러 공급업체가 공급업체별 네임스페이스 내에서 자체 특성을 정의할 수 있습니다. 그러나 컴파일러는 표준에 정의된 특성을 인식하기만 해야 합니다.

경우에 따라 표준 특성은 컴파일러별 __declspec 매개 변수와 겹칩니다. Microsoft C++에서는 [[deprecated]]을(를) 사용하는 대신 __declspec(deprecated) 특성을 사용할 수 있습니다. [[deprecated]] 특성은 모든 준수 컴파일러에서 인식됩니다. __declspecdllimport 등의 다른 모든 dllexport 매개변수의 경우 지금까지는 해당하는 특성이 없으므로 __declspec 구문을 계속 사용해야 합니다. 특성은 형식 시스템에 영향을 주지 않으며 프로그램의 의미를 변경하지 않습니다. 컴파일러는 인식하지 못하는 특성 값을 무시합니다.

Visual Studio 2017 버전 15.3 이상(/std:c++17 이상에서 사용 가능): 특성 목록의 범위에서 단일 using 소개자를 사용하여 모든 이름의 네임스페이스를 지정할 수 있습니다.

void g() {
    [[using rpr: kernel, target(cpu,gpu)]] // equivalent to [[ rpr::kernel, rpr::target(cpu,gpu) ]]
    do task();
}

C++ 표준 특성

C++11에서 특성은 C++ 구문(클래스, 함수, 변수 및 블록 포함)에 추가 정보를 주석으로 추가하는 표준화된 방법을 제공합니다. 특성은 공급업체에 따라 다를 수도 있고 그렇지 않을 수도 있습니다. 컴파일러는 이 정보를 사용하여 정보 메시지를 생성하거나 특성 코드를 컴파일할 때 특별한 로직을 적용할 수 있습니다. 컴파일러는 인식하지 못하는 특성은 무시하므로 이 구문을 사용하여 사용자 정의 특성을 정의할 수 없습니다. 특성은 이중 대괄호로 묶입니다.

[[deprecated]]
void Foo(int);

특성은 #pragma 지시문, __declspec()(Visual C++) 또는 __attribute__(GNU)와 같은 공급업체별 확장에 대한 표준화된 대안을 나타냅니다. 그러나 대부분의 목적에서는 여전히 공급업체별 구성을 사용해야 합니다. 현재 표준은 호환 컴파일러가 인식해야 하는 다음 특성을 지정하고 있습니다.

[[carries_dependency]]

[[carries_dependency]] 특성은 함수가 스레드 동기화에 대한 데이터 종속성 순서를 전파하도록 지정합니다. 이 특성은 하나 이상의 매개변수에 적용하여 전달된 인수가 함수 본문에 종속성을 전달하도록 지정할 수 있습니다. 이 특성을 함수 자체에 적용하여 반환값이 함수 외부의 종속성을 전달하도록 지정할 수 있습니다. 컴파일러는 이 정보를 사용하여 보다 효율적인 코드를 생성할 수 있습니다.

[[deprecated]]

Visual Studio 2015 이상:[[deprecated]] 특성은 함수가 사용되지 않도록 지정합니다. 또는 향후 버전의 라이브러리 인터페이스에는 존재하지 않을 수도 있습니다. [[deprecated]] 특성은 클래스, typedef-name, 변수, 비정적 데이터 멤버, 함수, 네임스페이스, 열거형, 열거자 또는 템플릿 특수화의 선언에 적용할 수 있습니다. 컴파일러는 클라이언트 코드가 함수 호출을 시도할 때 이 속성을 사용하여 정보 메시지를 생성할 수 있습니다. Microsoft C++ 컴파일러가 [[deprecated]] 항목 사용을 감지하면 컴파일러 경고 C4996이 발생합니다.

[[fallthrough]]

Visual Studio 2017 이상:(/std:c++17 이상에서 사용 가능) [[fallthrough]] 특성은 switch 문의 컨텍스트에서 대체 동작이 의도된 컴파일러(또는 코드를 읽는 모든 사용자)에 대한 힌트로 사용할 수 있습니다. Microsoft C++ 컴파일러는 현재 fallthrough 동작에 대해 경고하지 않으므로 이 특성은 컴파일러 동작에 영향을 주지 않습니다.

[[likely]]

Visual Studio 2019 버전 16.6 이상:(/std:c++20 이상에서 사용 가능) [[likely]] 특성은 특성이 지정된 레이블 또는 문의 코드 경로가 대안보다 실행될 가능성이 더 높다는 힌트를 컴파일러에 지정합니다. Microsoft 컴파일러에서 [[likely]] 특성은 블록을 내부 최적화 점수를 증가시키는 "핫 코드"로 표시합니다. 속도에 최적화할 때는 점수가 더 많이 증가하고 크기에 최적화할 때는 점수가 많이 증가하지 않습니다. 순 점수는 인라이닝, 루프 언롤링 및 벡터화 최적화 가능성에 영향을 미칩니다. [[likely]][[unlikely]]의 효과는 프로필 기반 최적화와 유사하지만 범위가 현재 번역 단위로 제한됩니다. 이 속성에 대한 블록 재정렬 최적화는 아직 구현되지 않았습니다.

[[maybe_unused]]

Visual Studio 2017 버전 15.3 이상:(/std:c++17 이상에서 사용 가능) [[maybe_unused]] 특성은 변수, 함수, 클래스, typedef, 비정적 데이터 멤버, 열거형 또는 템플릿 특수화를 의도적으로 사용하지 않을 수 있음을 지정합니다. 표시된 [[maybe_unused]] 엔터티가 사용되지 않는 경우 컴파일러는 경고하지 않습니다. 속성 없이 선언된 엔티티는 나중에 속성을 사용하여 다시 선언할 수 있으며, 그 반대의 경우도 마찬가지입니다. 엔티티는 (으)로 표시된 첫 번째 선언이 분석된 후 현재 번역 단위의 나머지 부분에 대해 [[maybe_unused]]으로 간주됩니다.

[[nodiscard]]

Visual Studio 2017 버전 15.3 이상:(/std:c++17 이상에서 사용 가능) 함수의 반환 값이 삭제되지 않도록 지정합니다. 다음 예제와 같이 경고 C4834를 발생합니다.

[[nodiscard]]
int foo(int i) { return i * i; }

int main()
{
    foo(42); //warning C4834: discarding return value of function with 'nodiscard' attribute
    return 0;
}

[[noreturn]]

[[noreturn]] 특성은 함수가 반환되지 않도록 지정합니다. 즉 항상 예외를 throw하거나 종료합니다. 컴파일러는 [[noreturn]] 엔터티에 대한 컴파일 규칙을 조정할 수 있습니다.

[[unlikely]]

Visual Studio 2019 버전 16.6 이상:(/std:c++20 이상에서 사용 가능) [[unlikely]] 특성은 특성이 지정된 레이블 또는 문의 코드 경로가 대안보다 실행 가능성이 적다는 힌트를 컴파일러에 지정합니다. Microsoft 컴파일러에서 [[unlikely]] 특성은 블록을 '콜드 코드'로 표시하여 내부 최적화 점수를 낮춥니다. 크기에 최적화할 때는 점수가 더 많이 증가하고 속도에 최적화할 때는 점수가 많이 감소하지 않습니다. 순 점수는 인라이닝, 루프 언롤링 및 벡터화 최적화 가능성에 영향을 미칩니다. 이 속성에 대한 블록 재정렬 최적화는 아직 구현되지 않았습니다.

Microsoft별 특성

[[gsl::suppress(<tag> [, justification: <narrow-string-literal>])]]

Visual Studio 2022 버전 17.14에서 도입된 이 Microsoft 특정 특성은 GSL(Guidelines Support Library) 규칙을 적용하는 검사기의 경고를 표시하지 않습니다. 문, 블록 또는 선언에 특성을 적용할 수 있습니다. C++에서만 사용할 수 있습니다. C 코드의 경우 대신 사용합니다 #pragma warning(suppress) .

<tag> 표시하지 않을 규칙의 이름을 지정하는 문자열입니다. 선택적 justification 필드를 사용하면 경고가 비활성화되거나 표시되지 않는 이유를 설명할 수 있습니다. 이 값은 옵션을 지정하면 SARIF(정적 분석 결과 교환 형식) 출력에 /analyze:log:includesuppressed 표시됩니다. 해당 값은 UTF-8로 인코딩된 좁은 문자열 리터럴입니다. SARIF 파일을 생성하려면 컴파일러 옵션을 사용합니다 /analyze:log:format:sarif .

예제:

int main()
{
    int arr[10]; // GSL warning C26494 will be fired
    int* p = arr; // GSL warning C26485 will be fired
    [[gsl::suppress("bounds.1", justification: "This attribute suppresses Bounds rule #1")]]
    {
        int* q = p + 1; // GSL warning C26481 suppressed
        p = q--; // GSL warning C26481 suppressed
    }
}

이 예제에서는 다음과 같은 경고를 발생합니다.

  • C26494(형식 규칙 5: 항상 개체를 초기화합니다.)
  • C26485(경계 규칙 3: 포인터 감쇠에 대한 배열 없음)
  • C26481(경계 규칙 1: 포인터 산술 연산을 사용하지 말 것. 대신 범위를 사용)

처음 두 경고는 CppCoreCheck 코드 분석 도구를 설치하고 활성화하여 이 코드를 컴파일할 때 발생합니다. 그러나 세 번째 경고는 특성 때문에 실행되지 않습니다. 특정 규칙 번호를 포함하지 않고 [[gsl::suppress("bounds")]]을(를) 작성하여 전체 경계 프로필을 표시하지 않을 수 있습니다. C++ 핵심 가이드라인은 더 좋고 안전한 코드를 작성하는 데 도움이 되도록 설계되었습니다. suppress 특성을 사용하면 원치 않을 때 경고를 쉽게 끌 수 있습니다.

다음 중에서 #pragma warning 선택 [[gsl::suppress]]

[[gsl::suppress]] 경고 #pragma warning(suppress) 억제를 세밀하게 제어할 수 있습니다.

  • [[gsl::suppress]] Microsoft C++ Code Analysis 내보낸 경고만 표시하지 않습니다. 범위 또는 특정 선언에 적용할 수 있는 C++ 핵심 지침 검사와 함께 사용합니다.
  • #pragma warning(suppress) 는 컴파일러 경고에 사용할 수 있습니다. 코드의 구조를 크게 변경하지 않고 특정 코드 블록에서 경고를 표시하지 않는 경우에 유용합니다.

가능하면 [[gsl::suppress]] 사용하여 Microsoft C++ Code Analysis 경고를 표시하지 않습니다.

[[msvc::disable(feature:APX)]]

MSVC 빌드 도구 버전 14.51(Visual Studio 버전 18.6.0)에 도입된 [[msvc::disable(feature:APX)]] 특성은 특정 함수에 대한 Intel APX(Advanced Performance Extensions) 명령 생성을 사용하지 않도록 설정하는 x64 전용 Microsoft 특정 특성입니다. 함수 선언 또는 정의에 적용하면 컴파일러 옵션을 통해 /feature:APX APX가 전역적으로 사용하도록 설정된 경우에도 컴파일러가 해당 함수 본문에 APX 명령을 내보내지 못하게 합니다. 동일한 변환 단위의 다른 함수는 유사하게 특성이 지정되지 않는 한 APX 명령을 계속 사용합니다. 인라인 함수를 호출하는 함수 [[msvc::disable(feature:APX)]] 인 경우 인라인 코드도 APX 명령 없이 컴파일됩니다.

예시

// The following shows how to disable APX instructions for specific functions,
// even when APX is enabled globally with /feature:APX
​int test(int argc)
{
    auto lambda = 
        []
        [[msvc::disable(feature:APX)]]
        (int argc)
        {
            return argc + 42;
        };
    return lambda(argc);
}

[[msvc::disable(feature:APX)]]
int test2(int x)
{
    return x + 42;
}

[[msvc::enable(feature:APX)]]

MSVC 빌드 도구 버전 14.51(Visual Studio 버전 18.6.0)에서 도입 <된 특성은 특정 함수에 대한 Intel APX(Advanced Performance Extensions) 명령 생성을 가능하게 하는 x64 전용 Microsoft 특정 특성입니다. 함수 선언 또는 정의에 적용하면 APX가 전역적으로 사용하도록 설정되지 않은 경우에도 컴파일러가 해당 함수 본문에 APX 명령을 내보낸다. 이렇게 하면 전체 변환 단위를 요구하지 /arch:APX 않고 APX 기능에 대한 함수별 옵트인을 제공합니다. 함수 [[msvc::enable(feature:APX)]] 에 인라인된 호출이 있는 경우 인라인 코드도 APX 명령으로 컴파일됩니다.

[[msvc::enable(feature:APX)]] 예제

// The following shows how to enable APX instructions for specific functions,
// even when APX isn't enabled globally with /feature:APX

​int test(int argc)
{
    auto lambda = 
        []
        [[msvc::enable(feature:APX)]]
        (int argc)
        {
            return argc + 42;
        };
    return lambda(argc);
}

[[msvc::enable(feature:APX), msvc::noinline]]
int test2(int x)
{
    return x + 42;
}

[[msvc::flatten]]

Microsoft 특정 특성 [[msvc::flatten]][[msvc::forceinline_calls]] 유사하며 동일한 위치에서 동일한 방식으로 사용할 수 있습니다. 차이점은 [[msvc::flatten]]은(는) 호출이 남지 않을 때까지 재귀적으로 적용되는 범위의 모든 호출을 [[msvc::forceinline_calls]]한다는 것입니다. 이는 결과적으로 함수의 코드 크기 증가 또는 컴파일러의 처리량에 영향을 미칠 수 있으며, 이를 수동으로 관리해야 합니다.

[[msvc::forceinline]]

함수 선언 앞에 배치할 때 Microsoft 전용 특성 [[msvc::forceinline]]은(는) __forceinline과(와) 동일한 의미를 갖습니다.

[[msvc::forceinline_calls]]

Microsoft별 특성 [[msvc::forceinline_calls]]은(는) 문 또는 블록 위 또는 그 앞에 배치할 수 있습니다. 인라인 추론이 해당 문 또는 블록의 모든 호출을 [[msvc::forceinline]](으)로 시도합니다.

void f() {
    [[msvc::forceinline_calls]]
    {
        foo();
        bar();
    }
    ...
    [[msvc::forceinline_calls]]
    bar();
    
    foo();
}

foo에 대한 첫 번째 호출과 bar에 대한 두 번째 호출은 __forceinline(으)로 선언된 것처럼 취급됩니다. foo에 대한 두 번째 호출은 __forceinline(으)로 취급되지 않습니다.

[[msvc::intrinsic]]

[[msvc::intrinsic]] 특성에는 적용되는 함수에 대한 세 가지 제약 조건이 있습니다.

  • 함수는 재귀적일 수 없으며, 본문에는 매개변수 유형에서 반환 유형까지 static_cast이(가) 포함된 반환문만 있어야 합니다.
  • 이 함수는 하나의 매개변수만 사용할 수 있습니다.
  • /permissive- 컴파일러 옵션이 필요합니다. (/std:c++20 이상 옵션은 기본적으로 /permissive-을(를) 의미합니다.)

Microsoft별 특성 [[msvc::intrinsic]]은(는) 매개 변수 형식에서 반환 형식으로 명명된 캐스트 역할을 하는 메타 함수를 인라인으로 컴파일러에 지시합니다. 함수 정의에 특성이 있으면 컴파일러는 해당 함수에 대한 모든 호출을 간단한 형변환으로 대체합니다. [[msvc::intrinsic]] 특성은 Visual Studio 2022 버전 17.5 미리 보기 2 이상 버전에서 사용할 수 있습니다. 이 특성은 뒤에 오는 특정 함수에만 적용됩니다.

예시

이 샘플 코드에서 [[msvc::intrinsic]] 함수에 적용된 my_move 특성은 컴파일러가 함수에 대한 호출을 본문의 인라인 정적 캐스트로 대체합니다.

template <typename T>
[[msvc::intrinsic]] T&& my_move(T&& t) { return static_cast<T&&>(t); }

void f() {
    int i = 0;
    i = my_move(i);
}

[[msvc::musttail]]

[[msvc::musttail]]에 도입된 이 특성은 비상 호출 최적화를 적용하는 실험적 x64 전용 Microsoft 전용 특성입니다. 정규화 반환 문에 적용하면 컴파일러가 호출을 비상 호출로 내보내도록 지시합니다. 컴파일러가 비상 호출을 내보낼 수 없으면 컴파일 오류가 발생합니다. 이 특성은 [[msvc::musttail]] 함수를 인라인하는 대신 비상 호출을 적용합니다.

[[msvc::musttail]] 요구 사항:

  • 호출자와 호출 수신자는 일치하는 반환 형식이 있어야 합니다.
  • 호출 규칙은 호환되어야 합니다.
  • 비상 호출은 호출 함수의 최종 작업이어야 합니다.
  • 호출 수신자는 호출 함수보다 더 많은 스택 공간을 사용할 수 없습니다.
  • 4개 이상의 정수 매개 변수가 전달되는 경우 호출 함수는 다른 인수에 충분한 스택 공간을 할당해야 합니다.
  • /O2 /O2 /GL 또는 최적화 수준으로 컴파일합니다.

예시

비상 호출은 함수 호출이 반환하기 전에 수행된 마지막 작업일 때 가능한 컴파일러 최적화입니다. 함수를 호출하는 새 스택 프레임을 만드는 대신 현재 함수의 스택 프레임이 재사용됩니다. 이렇게 하면 스택 사용량이 줄어들고 특히 재귀 시나리오에서 성능이 향상됩니다.

다음 코드에서 적용된 [[msvc::musttail]] 특성으로 return increment(x) 인해 컨트롤이 직접 으로 전송됩니다 increment. 문에 도달하면 increment 해당 결과가 호출자에게 return x+1;직접 제공됩니다. 즉incrementIfPositive,main 이렇게 하면 인라인 increment 으로 또는 호출 incrementIfPositiveincrement 한 후 incrementIfPositive 로 돌아가기 전에 다시 찾게 됩니다incrementIfPositivemain. 비상 호출 최적화는 완료 후 incrementIfPositive 제어를 다시 얻을 필요가 increment 없습니다. 이는 스택 사용량을 줄이는 성능 최적화이며, 특히 재귀 시나리오에서 유용합니다.

// compile with /O2
#include <iostream>

int increment(int x)
{
    return x + 1;
}

int incrementIfPositive(int x)
{
    if (x > 0)
    {
        [[msvc::musttail]]
        return increment(x);
	}
    return -1;
}

int main()
{
    int result = incrementIfPositive(42);
    if (result < 0)
    {
        return -1;
    }

    std::cout << result; // outputs 43
    return 0;
}

[[msvc::noinline]]

함수 선언 앞에 배치할 때 Microsoft 전용 특성 [[msvc::noinline]]은(는) __declspec(noinline)과(와) 동일한 의미를 갖습니다.

[[msvc::noinline_calls]]

Microsoft별 특성 [[msvc::noinline_calls]][[msvc::forceinline_calls]]과(와) 사용법이 동일합니다. 문이나 블록 앞에 배치할 수 있습니다. 해당 블록의 모든 호출을 강제 인라이닝하는 대신 해당 블록이 적용되는 범위에 대한 인라이닝을 해제하는 효과가 있습니다.

[[msvc::no_tls_guard]]

Microsoft별 [[msvc::no_tls_guard]] 특성은 DLL의 스레드 지역 변수에 대한 첫 번째 액세스에서 초기화에 대한 검사를 사용하지 않도록 설정합니다. 검사는 기본적으로 Visual Studio 2019 버전 16.5 이상을 사용하여 빌드된 코드에서 사용하도록 설정됩니다. 이 특성은 뒤에 오는 특정 변수에만 적용됩니다. 전역적으로 검사를 사용하지 않도록 설정하려면 /Zc:tlsGuards- 컴파일러 옵션을 사용합니다.