다음을 통해 공유


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>])]]

<tag> 표시하지 않을 규칙의 이름을 지정하는 문자열입니다. 선택적 justification 필드를 사용하면 경고가 비활성화되거나 표시되지 않는 이유를 설명할 수 있습니다. 이 값은 옵션이 지정되면 SARIF 출력에 /analyze:log:includesuppressed 표시됩니다. 해당 값은 UTF-8로 인코딩된 좁은 문자열 리터럴입니다. 이 [[gsl::suppress]] 특성은 Visual Studio 2022 버전 17.14 이상 버전에서 사용할 수 있습니다.

Microsoft별 [[gsl::suppress]] 특성은 코드에서 GSL(Guidelines Support Library) 규칙을 적용하는 검사기의 경고를 표시하지 않는 데 사용됩니다. 예를 들어 다음 코드 조각을 고려하세요.

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 특성을 사용하면 원치 않을 때 경고를 쉽게 끌 수 있습니다.

[[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::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- 컴파일러 옵션을 사용합니다.