Coding Memo
[[nodiscard]] 리턴 값 무시 방지 속성 (C++17 ~) 본문
"반드시 이 함수는 리턴값을 무시하면 안된다!"
"이 함수의 리턴값을 무시하면 사용 의미가 없다!"
위 경우에 리턴값을 무시하지 않도록 컴파일 시 경고를 줄 수 있는 기능이 C++17부터생겼다.
`[[nodiscard]]`
[[nodicard]]를 함수나 타입 앞에 붙이게 되면, 이 함수나 타입을 사용하고 리턴 값을 무시했을 때, 경고를 줄 수 있다.
다음과 같은 특징이 있다.
1. 함수 뿐만 아니라, 타입에도 적용 가능
2. C++20 부터는 경고 메시지 (진단 메시지)를 직접 추가할 수 있음반드시 이 함수는 리턴값을 무시하면 안된다!"
"이 함수의 리턴값을 무시하면 사용 의미가 없다!"
위 경우에 리턴값을 무시하지 않도록 컴파일 시 경고를 줄 수 있는 기능이 C++17부터생겼다.
함수나 타입 앞에 아래 속성을 추가하면 된다.
[[nodiscard]]
[[nodicard]]를 함수나 타입 앞에 붙이게 되면, 이 함수나 타입을 사용하고 리턴 값을 무시했을 때, 경고를 줄 수 있다.
다음과 같은 특징이 있다.
1. 함수 뿐만 아니라, 타입에도 적용 가능
2. C++20 부터는 경고 메시지 (진단 메시지)를 직접 추가할 수 있음
이 [[nodicard]] 속성을 어떤 경우에 사용하면 좋을지 생각해보자.
먼저, 클래스 내의 멤버변수나, 외부 참조에 대한 값을 변경 시키지 않는 함수 (e.g. const 함수)는 반환값을 사용하지 않다면 의미가 없으므로 사용처에 알맞을 것이다. (pure-function)
조금 더 깊히 생각한다면, 어떤 메모리를 로드하거나, 상태를 반환 또는 특정 기능을 하는 핸들을 반환하는 함수나 타입에서도 사용 할 수 있을 것이다. 윈도우 함수를 생각하면 간단하다. HRESULT를 반환하는 함수를 실행 시키고, 결과 값을 확인하지 않는다면, 실행이 제대로 되었는지 알 수가 없고, 결과 값도 사용할 수 없을 것이다. 마찬가지로, IOCP와 관련된 핸들을 가져오는 함수도, 핸들을 가져오지않는다면, 함수를 실행시킨 의미가 없을 것이다.
Note: MSVC에서는 `__DISCARD` 라는 매크로 키워드를 제공하기도 한다. (실제로 [[nodiscard]] 가 정의되어 있다.)
Notes2: Pure Function이란, 함수 실행 시, 외부에 영향을 주지 않는 함수를 말한다.
1. [[nodiscard]] 함수에 적용
양쪽에 괄호가 2개씩인 것에 유의하자.
다음은 간단한 예시이다.
[[nodiscard]]
static int sum( const int a, const int b )
{
return a + b;
}
이렇게 하면, sum을 사용했을 때, return 값을 사용하지 않는다면 경고(C4834)가 나타난다.
nodiscard.cpp(11,8): warning C4834: discarding return value of function with [[nodiscard]] attribute |
만약, C++20 이상에서 진단메시지를 추가한다면...
[[nodiscard("Check the return value!")]]
static int sum( const int a, const int b )
{
return a + b;
}
nodiscard.cpp(11,8): warning C4858: discarding return value: Check the return value! |
경고 메시지가 지정한대로 나타난다!
2. [[nodiscard]] 타입에 적용
실제로 사용되고 있거나, 사용될 수 있는 좋은 예시라고 생각한다.
struct [[nodiscard]] Result
{
// 0: success
// > 0 : failed with reason
int result = 0;
std::string reason;
};
Result LoadTexture( const std::wstring& path, void*& ptr )
{
Result ret;
// ...
return ret;
}
void LoadAll()
{
void* pTexture = nullptr;
LoadTexture( L"../test.png", pTexture ); // warning C4834
// ...
}
Result라는 구조체 타입에 [[nodiscard]]를 사용한 코드이다.
LoadTexture를 호출한 이후에 반환값(Result)를 무시하고 있는 LoadAll 내부에서 컴파일 경고가 나타나게 된다.
실제로, LoadTexture를 하고, 이 함수가 성공했는지 실패 했는지 알아야, pTexture라는 변수를 사용할 수 있을 것이다.
(만약 실패 했다면, pTexture의 값은 nullptr 그대로이다. 즉, 성공여부를 확인하지 않은 상태에서 pTexture를 사용한다면 nullptr 참조가 일어나는 큰 문제가 발생할 것이다.)
따라서, 위와 같은 실수 및 문제를 방지하기 위해서 [[nodiscard]]를 사용하는 것이다.
아래와 같이 좀 더 좋은코드로 바꿀 수 있다.
void LoadAll()
{
void* pTexture = nullptr;
auto result = LoadTexture( L"../test.png", pTexture );
if( result.result != 0 )
{
std::cout << "Failed to load texture: " << result.reason << std::endl;
return;
}
// Do something with pTexture
// ...
}
리턴 값이 중요한 함수나 타입에는 [[nodiscard]] 속성을 붙여서 실수나, 문제를 방지하자!
별거 아닌 것 같아보이지만, 은근 유용하게 이용될 수도 있다.
추가적인 정보는 아래 문서를 참고해도 될 것 같다.
https://en.cppreference.com/w/cpp/language/attributes/nodiscard
C++ attribute: nodiscard (since C++17) - cppreference.com
If a function declared nodiscard or a function returning an enumeration or class declared nodiscard by value is called from a discarded-value expression other than a cast to void, the compiler is encouraged to issue a warning. [edit] Syntax [[nodiscard]] (
en.cppreference.com
'Language > C++' 카테고리의 다른 글
Factory 패턴 (팩토리 패턴) (0) | 2024.11.28 |
---|---|
브릿지 패턴 (Bridge Pattern) + Pimpl (0) | 2024.11.26 |
[LNK2005] already defined in ~~.obj / inline 함수 (0) | 2024.10.28 |
템플릿 특수화, constexpr if 그리고 concept (3) | 2024.10.16 |
[C++20] concepts - requires (0) | 2024.10.02 |