Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 속성(Attribute) 완벽 가이드 – 개념, 문법, 주요 속성 총정리


C++ 속성(Attribute)이란?

C++의 속성(Attribute)은 동일한 코드가 서로 다른 컴파일러에서 실행되더라도 일관된 동작을 보장하기 위해 표준화된 현대적인 기능입니다. 속성은 컴파일러에 추가 정보를 전달하여 조건(제약) 강제, 코드 최적화, 필요 시 특정 코드 생성 등을 수행하도록 돕습니다.

즉, 속성은 컴파일러를 위한 일종의 '정보 매뉴얼'로서, 코드 성능 향상에 필요한 규칙을 적용하는 역할을 합니다. 속성은 C++11에서 처음 도입되었으며, 이후 언어의 중요한 구성 요소로 자리 잡았습니다. 또한 표준이 개정될 때마다 지속적으로 보완되어 점점 더 강력해지고 있습니다.

속성 정의 문법

C++ 버전에 따라 속성을 정의하는 문법이 조금씩 다릅니다.

C++11

[[attribute-list]]

C++17

[[using attribute-namespace : attribute-list]]

C++20

[[contract-attribute-token contract-level-identifier : expression]]

속성은 변수, 함수, 클래스 등 다양한 대상에 적용할 수 있습니다. 그럼 이제 C++에서 사용할 수 있는 표준 속성들을 하나씩 살펴보겠습니다.

C++11에서 도입된 속성

noreturn

함수가 호출자에게 제어 흐름을 반환하지 않음을 컴파일러에 알립니다.

문법

[[noreturn]]

예제

[[noreturn]] void f();

이렇게 선언된 함수는 void조차 반환하지 않습니다. 무한 루프나 오류 발생처럼 실행 흐름이 호출부로 돌아오지 않는 상황에서 컴파일러가 경고를 출력할 수 있어, 잠재적인 버그를 조기에 발견하는 데 유용합니다.

carries_dependency

release-consume 메모리 순서에서 발생하는 의존 관계를 정의하여, 컴파일러가 불필요한 메모리 소모 명령을 건너뛰고 최적화할 수 있도록 합니다. 주로 함수 선언이나 매개변수에 의존성을 표시할 때 사용됩니다.

문법

[[carries_dependency]]

deprecated

코드 내에서 더 이상 사용이 권장되지 않는 엔티티를 표시합니다. 해당 엔티티의 사용 자체는 허용되지만, 권장되지는 않습니다.

문법

[[deprecated]]
[[deprecated("사유")]]

괄호 안의 문자열은 폐기 사유와 함께 대안을 안내하는 데 사용되며, 컴파일러 경고 메시지에 포함됩니다. 폐기 처리할 수 있는 엔티티로는 클래스, 구조체, 공용체(union), typedef 이름, 정적 멤버, 함수, 네임스페이스, 열거형 등이 있습니다.

C++17에서 도입된 속성

fallthrough

switch문에서 한 case의 실행이 다음 case로 의도적으로 이어짐(fallthrough)을 컴파일러에 알려, 불필요한 경고가 발생하지 않도록 합니다. 당연히 switch문 안에서만 사용할 수 있습니다.

문법

[[fallthrough]]

nodiscard

함수의 반환값이 버려지는(discard) 것을 방지하기 위한 속성입니다. 반환값을 사용하지 않고 호출하면 컴파일러가 경고를 발생시킵니다.

문법

[[nodiscard]]
[[nodiscard("사유")] // C++20에서 추가

괄호 안의 문자열은 결과를 버리면 안 되는 이유를 설명하며, C++20부터 사용할 수 있습니다.

maybe_unused

사용되지 않는 엔티티로 인해 발생하는 경고를 억제하거나 제거하도록 컴파일러에 지시합니다.

문법

[[maybe_unused]]

클래스, 구조체, 공용체, typedef 이름, 정적 멤버, 함수, 변수, 열거형 등에 선언할 수 있습니다.

C++20에서 도입된 속성

likely, unlikely

분기문에서 어느 경로가 실행될 가능성이 더 높은지(likely), 혹은 더 낮은지(unlikely)를 컴파일러에 알려 분기 예측 최적화에 활용하게 합니다. 주로 레이블(label)이나 문(statement)처럼 프로그램의 실행 흐름을 바꾸는 요소에 적용됩니다.

문법

[[likely]]
[[unlikely]]

no_unique_address

데이터 멤버가 반드시 고유한 주소를 가질 필요가 없음을 나타냅니다. 주로 비정적(non-static) 데이터 멤버에 적용되며, 별도의 메모리 할당이 불필요함을 의미합니다. 컴파일러가 메모리 위치를 배정할 때 일반 멤버를 우선하므로, 빈 클래스 타입 멤버로 인한 공간 낭비를 줄이는 데 유용합니다.

문법

[[no_unique_address]]

expects (계약 조건)

함수가 실행되기 위해 인수가 반드시 만족해야 하는 사전 조건을 명시합니다.

문법

[[expects : condition]]

condition은 함수가 실행되기 위해 충족되어야 하는 조건을 정의합니다.

optimize_for_synchronized

해당 함수의 정의가 synchronized 문(트랜잭셔널 메모리 확장)에서 호출될 때 최적화되어야 함을 나타냅니다. 이 속성이 붙은 함수는 synchronized 블록의 직렬화를 피하도록 구현됩니다.

문법

[[optimize_for_synchronized]]

속성을 사용하는 이유

지금까지 C++11부터 C++20까지 소개된 속성들을 살펴보았습니다. 그렇다면 프로그래밍에서 속성은 어떤 문제를 해결해 줄까요?

  • 코드에 제약 조건 추가 – 많은 경우 속성은 코드에 의미를 부여하고 유효성을 높여, 불필요한 수고를 덜어줍니다.

  • 컴파일러에 추가 최적화 정보 제공 – fallthrough, likely, maybe_unused 같은 속성은 컴파일러가 특정 최적화를 수행하는 데 필요한 정보를 제공합니다.

  • 경고 및 오류 회피 – 때로 프로그래머의 로직이 C++의 엄격한 규칙과 충돌할 수 있습니다. 이럴 때 속성을 활용하면 발생할 경고를 회피하거나 억제할 수 있습니다.