C++ - Attribute ([[noreturn]], [[nodiscard]] 등)
C++ 에선 컴파일러에게 함수의 성질을 알려주어 최적화를 수행하거나 경고를 제거하는 등의 작업을 도울 수 있다.
이 기능이 Attribute이다.
Attribute는 종류가 여러가지가 있으므로 하나씩 알아보자.
[[noreturn]]
[[noreturn]] 은 이름 그대로, 반환하지 않는다는 의미이다. 함수가 반환된다는 것은 return 을 만나 함수가 종료되고, 다음 동작이 수행되는 것을 의미한다. [[noreturn]] 이란, 해당 함수가 절대 반환되지 않고 다음 동작이 수행되지 않음을 의미한다.
예를 들어, 아래의 코드를 보자.
int main()
{
std::exit(0);
int A = 0;
return 0;
}
std::exit 함수가 실행되면 프로그램은 그대로 종료된다. 다른 일반적인 함수가 호출되었다면 int A = 0; 과 return 0; 의 구문까지 모두 수행되어야 하지만, std::exit() 함수는 그 즉시 프로그램을 종료하는 역할이기 때문에 다음 코드가 수행되지 않는다. 이러한 경우를 함수가 반환하지 않는 경우라고 할 수 있다.
이 때, [[noreturn]] 키워드를 통해, 컴파일러에게 해당 함수는 반환하지 않는다는 것을 알려줄 수 있다. 컴파일러가 이를 알게 되면, 절대 수행될 수 없는 코드(noreturn 함수 이후에 수행되는 코드)를 판별할 수 있게 되고, 이를 제거하여 컴파일하게 된다. 코드 용량이 조금이나마 절약되는 효과가 있을 것이다.
또한, 컴파일러는 noreturn 이후에 수행되는 구문에 컴파일러 경고를 띄워주는데, 프로그래머는 이를 확인하여 의도에 맞게 코드를 수정할 수 있게 된다. (noreturn 이전에 실행되어야 하는 구문이 noreturn 이후에 실행되고 있는 등의 설계 오류를 수정 가능)
[[noreturn]] void Exit()
{
throw std::exception();
}
이렇게 함수 앞에 붙여 속성을 명시할 수 있게 된다. throw 키워드를 통해 예외를 던지는 경우에도 예외를 catch한 후에 프로세스가 종료되므로 [[noreturn]] 키워드를 사용하여 의미를 명시할 수 있다.
이렇게 [[noreturn]] 키워드가 사용된 함수 이후에 작성된 구문은 도달할 수 없다는 경고를 보여주게 된다.
[[deprecated]]
이 attribute는 더이상 함수가 사용되지 않음을 프로그래머에게 알려주기 위해 사용한다.
예를 들어, 내가 만든 라이브러리를 배포한다고 해보자. 이전 버전에선 특정 함수를 사용했었으나, 라이브러리의 버전이
높아지면서 해당 함수를 더이상 사용하지 않는 경우에는 이를 라이브러리 사용자에게 알려줄 필요가 있게 된다. 이 때, [[deprecated]] 를 사용하여 알려줄 수 있다.
사용되지 않는다는 에러가 발생하는 것을 확인할 수 있다.
아래와 같이 사용하면 그 사유를 함께 알려줄 수도 있다.
사유도 함께 명시되는 것을 확인할 수 있다.
[[fallthrough]]
switch 문을 사용할 때, 우리는 아래와 같이 사용한다.
int main()
{
int A = 0;
switch(A)
{
case 0:
A += 0;
break;
case 1:
A += 1;
break;
default:
A += 2;
break;
}
return 0;
}
A의 값에 따라 서로 다른 분기로 들어가고, break를 만나면 switch문을 탈출하여 다음 코드를 수행하게 된다.
하지만 break가 없는 상황이라면?
int main()
{
int A = 0;
switch(A)
{
case 0:
A += 0;
case 1:
A += 1;
default:
A += 2;
break;
}
return 0;
}
이런 경우엔, A의 값에 따라 처음 들어간 분기를 시작으로 break를 만날 때까지 모든 코드를 수행하게 된다.
일반적으로는 이런 경우 컴파일 경고가 발생하게 된다. 하지만, 의도적으로 코드를 이렇게 작성하였다면 해당 경고가 필요 없게 된다. 그런 경우 [[fallthrough]]를 사용하여 경고를 제거할 수 있다.
int main()
{
int A = 0;
switch(A)
{
case 0:
A += 0;
[[fallthrough]];
case 1:
A += 1;
[[fallthrough]];
default:
A += 2;
break;
}
return 0;
}
이렇게 의도된 코드임을 명시하여 경고를 제거할 수 있다.
[[nodiscard]]
해당 함수의 반환값이 낭비되는 경우 경고를 방출해주는 attribute이다.
아래의 코드를 보자.
int Function()
{
int A = 0;
return A;
}
int main()
{
Function();
return 0;
}
위의 코드에서 Function은 A를 반환하고 있지만, 반환값을 전혀 사용하고 있지 않다. 의도된 경우엔 상관이 없지만, getter처럼 애초부터 반환 값을 사용하는 것이 호출 목적인 경우 반환값을 반드시 사용하라고 경고하는 것이 좋다.
이 때, 아래와 같이 사용할 수 있다.
함수 앞에 nodiscard 속성을 명시하였고, 컴파일 경고가 발생함을 확인할 수 있다.
이 4가지 말고도 추가적인 attribute가 있지만, 이는 추후 추가적으로 작성해보도록 하겠다!