Updated:

5 minute read

개요

  • 타입, 객체, 코드 등에 대한 구현/정의 속성을 설명
  • 문법
    • C++11
      • [[ attribute-list ]]
    • C++17
      • [[ using attribute-namespace : attribute-list ]]
  • 표준 속성
    • [[noreturn]]
      • C++11
      • 함수가 return 하지 않음을 지정
      • 함수가 반환되는 경우 동작이 정의되지 않음
      • 함수 선언에서 함수 이름에만 적용 가능
      • throw 사용하여 함수를 빠져나가야 함
    • [[carries_dependency]]
      • C++11
      • indicates that dependency chain in release-consume std::memory_order propagates in and out of the function
    • [[deprecated]] / [[deprecated(“reason”)]]
      • C++14
      • 사용은 허용되지만 권장되지 않음
      • 사용 시 컴파일 경고 발생
      • class/struct/union
        • class [[deprecated]] C;
      • typedef/using
        • [[deprecated]] typedef C* PC;
        • using PC [[deprecated]] = C*;
      • variable
        • [[deprecated]] int i;
      • non-static 데이터 멤버
        • class T { [[deprecated]] int i; };
      • 함수
        • [[deprecated]] void f();
      • namespace
        • namespace [[deprecated]] NS { int i; }
      • enum
        • enum [[deprecated]] E {};
        • enum { A [[deprecated]], B [[deprecated]] = 42 };
          • C++17
      • 템플릿
        • template <> class [[deprecated]] C<int> {};
    • [[fallthrough]]
      • C++17
      • switch문에서 특정 라벨에 break가 없는게 의도적임을 지정
      • 컴파일 경고가 발생하지 않음
    • [[nodiscard]] / [[nodiscard(“reason”)]]
      • [[nodiscard]]
        • C++17
      • [[nodiscard(“reason”)]]
        • C++20
      • 함수의 반환 값을 사용하지 않으면 컴파일 경고 발생
        • 해당 속성으로 선언된 함수
        • 해당 속성으로 선언된 enum, class 등을 반환하는 함수
    • [[maybe_unused]]
      • C++17
      • 사용하지 않는 변수 등에 대한 경고를 억제
    • [[likely]] / [[unlikely]]
      • C++20
      • 컴파일러가 적절한 최적화를 하도록 분기문에 실행 빈도를 지정
    • [[no_unique_address]]
      • C++20
      • non-static 데이터 멤버가 다른 non-static 데이터 멤버와 구별되는 주소를 가질 필요가 없음을 지정
    • [[assume]]
      • C++23
      • 표현식이 항상 true로 평가되도록 지정


예제

  • [[noreturn]]
    • 코드
         #include <iostream>
              
         using namespace std;
              
         [[noreturn]] void func1() { throw "throw"; };
              
         void func2 [[noreturn]] () { throw "throw"; };
              
         int main() {
         	try {
         		func1();
         	} catch (...) {
         		cout << "~~~ func1()" << endl;
         	}
              
         	try {
         		func2();
         	} catch (...) {
         		cout << "~~~ func2()" << endl;
         	}
              
         	return 0;
         }
      
    • 실행 결과
         ~~~ func1()
         ~~~ func2()
      
  • [[deprecated]] / [[deprecated(“reason”)]]
    • 코드
         #include <iostream>
         #include <string>
              
         using namespace std;
              
         class [[deprecated]] Test1 {
         	public:
         		void Print() { cout << "Test1::Print()" << endl; }
         };
              
         class Test2 {
         	public:
         		[[deprecated]] int i;
         		[[deprecated]] void Print() { cout << "Test2::Print()" << endl; }
         };
              
         template <typename T> class Test3 {};
         template <> class [[deprecated]] Test3<int> {};
              
         [[deprecated]] int I = 0;
              
         int main() {
         	cout << I << endl;
              
         	Test1().Print();
              
         	Test2().i;
         	Test2().Print();
              
         	[[deprecated]] int i = 0;
         	cout << i << endl;
              
         	Test3<string>();
         	Test3<int>();
              
         	return 0;
         }
      
    • 실행 결과
         main.cpp: In function ‘int main()’:
         main.cpp:23:17: warning: ‘I’ is deprecated [-Wdeprecated-declarations]
            23 |         cout << I << endl;
               |                 ^
         main.cpp:20:20: note: declared here
            20 | [[deprecated]] int I = 0;
               |                    ^
         main.cpp:25:15: warning: ‘Test1’ is deprecated [-Wdeprecated-declarations]
            25 |         Test1().Print();
               |               ^
         main.cpp:6:22: note: declared here
             6 | class [[deprecated]] Test1 {
               |                      ^~~~~
         main.cpp:27:17: warning: ‘Test2::i’ is deprecated [-Wdeprecated-declarations]
            27 |         Test2().i;
               |                 ^
         main.cpp:13:36: note: declared here
            13 |                 [[deprecated]] int i;
               |                                    ^
         main.cpp:27:17: warning: ‘Test2::i’ is deprecated [-Wdeprecated-declarations]
            27 |         Test2().i;
               |                 ^
         main.cpp:13:36: note: declared here
            13 |                 [[deprecated]] int i;
               |                                    ^
         main.cpp:27:17: warning: ‘Test2::i’ is deprecated [-Wdeprecated-declarations]
            27 |         Test2().i;
               |                 ^
         main.cpp:13:36: note: declared here
            13 |                 [[deprecated]] int i;
               |                                    ^
         main.cpp:28:22: warning: ‘void Test2::Print()’ is deprecated [-Wdeprecated-declarations]
            28 |         Test2().Print();
               |         ~~~~~~~~~~~~~^~
         main.cpp:14:37: note: declared here
            14 |                 [[deprecated]] void Print() { cout << "Test2::Print()" << endl; }
               |                                     ^~~~~
         main.cpp:31:17: warning: ‘i’ is deprecated [-Wdeprecated-declarations]
            31 |         cout << i << endl;
               |                 ^
         main.cpp:30:28: note: declared here
            30 |         [[deprecated]] int i = 0;
               |                            ^
         main.cpp:34:20: warning: ‘Test3’ is deprecated [-Wdeprecated-declarations]
            34 |         Test3<int>();
               |                    ^
         main.cpp:18:34: note: declared here
            18 | template <> class [[deprecated]] Test3<int> {};
               |                                  ^~~~~~~~~~
         0
         Test1::Print()
         Test2::Print()
         0
      
  • [[fallthrough]]
    • 코드
         #include <iostream>
              
         using namespace std;
              
         int main() {
         	int i = 0;
              
         	switch (i) {
         	case 0:
         		cout << 0 << endl;
         		[[fallthrough]];
         	case 1:
         		cout << 1 << endl;
         		break;
         	}
              
         	return 0;
         }
      
    • 실행 결과
         0
         1
      
  • [[nodiscard]] / [[nodiscard(“reason”)]]
    • 코드
         class [[nodiscard]] Test {};
         Test func1() { return Test(); }
              
         [[nodiscard("reason")]] int func2() { return 1; };
              
         int main() {
         	func1();
              
         	func2();
              
         	return 0;
         }
      
    • 실행 결과
         main.cpp: In function ‘int main()’:
         main.cpp:7:14: warning: ignoring returned value of type ‘Test’, declared with attribute ‘nodiscard’ [-Wunused-result]
             7 |         func1();
               |         ~~~~~^~
         main.cpp:2:6: note: in call to ‘Test func1()’, declared here
             2 | Test func1() { return Test(); }
               |      ^~~~~
         main.cpp:1:21: note: ‘Test’ declared here
             1 | class [[nodiscard]] Test {};
               |                     ^~~~
         main.cpp:9:14: warning: ignoring return value of ‘int func2()’, declared with attribute ‘nodiscard’: ‘reason’ [-Wunused-result]
             9 |         func2();
               |         ~~~~~^~
         main.cpp:4:29: note: declared here
             4 | [[nodiscard("reason")]] int func2() { return 1; };
               |                             ^~~~~
      
  • [[maybe_unused]]
    • 코드
         [[maybe_unused]] void func([[maybe_unused]] int x, int y) {}
              
         int main() {
         	int i = 0;
         	[[maybe_unused]] double d = 0.0;
              
         	return 0;
         }
      
    • 실행 결과
         main.cpp: In function ‘int main()’:
         main.cpp:4:13: warning: unused variable ‘i’ [-Wunused-variable]
             4 |         int i = 0;
               |             ^
      
  • [[likely]] / [[unlikely]]
    • 코드
         #include <algorithm>
         #include <chrono>
         #include <iostream>
              
         using namespace std;
              
         constexpr long long fact_with_attributes(long long n) noexcept {
         	if (n > 1) [[likely]] {
         		return n * fact_with_attributes(n - 1);
         	} else [[unlikely]] {
         		return 1;
         	}
         }
              
         constexpr long long fact_no_attributes(long long n) noexcept {
         	if (n > 1) {
         		return n * fact_no_attributes(n - 1);
         	} else {
         		return 1;
         	}
         }
              
         int main() {
         	auto run = [](auto func) {
         		const auto start = chrono::high_resolution_clock::now();
              
         		for (int i = 0; i < 2000000; i++) {
         			for (int j = 0; j <= 20; j++) {
         				func(j);
         			}
         		}
              
         		const auto end = chrono::high_resolution_clock::now();
              
         		const chrono::duration<double> result = end - start;
         		cout << result.count() << endl;
         	};
              
         	run(fact_with_attributes);
         	run(fact_no_attributes);
              
         	return 0;
         }
      
    • 실행 결과
         1.68545
         1.7237
      
  • [[no_unique_address]]
    • 코드
         #include <iostream>
              
         using namespace std;
              
         class Test {};
              
         class Test1 {
         	private:
         		int i;
         		Test t;
              
         	public:
         		void Print() {
         			cout << &this->i << endl;
         			cout << &this->t << endl;
         		}
         };
              
         class Test2 {
         	private:
         		int i;
         		[[no_unique_address]] Test t;
              
         	public:
         		void Print() {
         			cout << &this->i << endl;
         			cout << &this->t << endl;
         		}
         };
              
         int main() {
         	cout << sizeof(int) << endl;
         	cout << sizeof(Test) << endl;
         	cout << sizeof(Test1) << endl;
         	cout << sizeof(Test2) << endl;
              
         	cout << "------" << endl;
              
         	Test1().Print();
              
         	cout << "------" << endl;
              
         	Test2().Print();
              
         	return 0;
         }
      
    • 실행 결과
         4
         1
         8
         4
         ------
         0x7ffd4e7a40b4
         0x7ffd4e7a40b8
         ------
         0x7ffd4e7a40bc
         0x7ffd4e7a40bc