🦔

[C++] 戻り値を必ず使わないといけない関数はnodiscard属性を付けると良い

2023/12/08に公開

C++には属性構文という機能がある。
https://cpprefjp.github.io/lang/cpp11/attributes.html
関数等の前に属性を指定することでコンパイラに対して情報を追加で伝えることができる機能だ。

今回はこの属性の中で私が気に入っているnodiscard属性について紹介する。

戻り値の使用を自動チェックしてくれるnodiscard属性

nodiscard属性は以下のように関数の前に[[]]で付与することができるやつだ。

[[nodiscard]] int add(int a, int b)
{
  return a + b;
}

このnodiscard属性の便利な点は関数コールしている箇所で戻り値が使用されていない場合に警告を出してくれるということ。
以下のコードのように戻り値を使用していないソースに対してコンパイルするとコンパイラが警告を出力してくれる。

[[nodiscard]] int add(int a, int b)
{
  return a + b;
}

int main()
{
  add(1, 2); // 戻り値未使用
  return 0;
}

警告メッセージは以下のような感じで出力される。

.\main.cpp:15:6: warning: ignoring return value of 'int add(int, int)', declared with attribute nodiscard [-Wunused-result]
   15 |   add(1, 2);
      |   ~~~^~~~~~
.\main.cpp:8:19: note: declared here
    8 | [[nodiscard]] int add(int a, int b)
      | 

処理結果を返して呼び出し元で必ずエラーチェックすることを期待するような関数についてはこのdiscard属性を入れておくことで戻り値のチェック漏れを見つやすくなるだろう。

クラスにnodiscard属性を付けることもできる

関数だけではなくクラスに対してもnodiscard属性は付与することができる。
クラスに対して付与するとどのような動作になるかというと、付与したクラスが戻り値の型になっている場合にその戻り値が使っていないと警告が出るようになる。
以下が参考のコード。

[[nodiscard]] class Sample
{
};

Sample CreateSample()
{
  return Sample();
}

int main()
{
  CreateSample(); // 戻り値を使用していないので警告が出る
  return 0;
}

関数に付けるパターンが多いのかもしれないが、このようにクラスに付与することもできるのは覚えておきたい。ちなみに列挙型にも付けることが可能。

補足

nodiscard属性が使えるのはC++17以降。
https://cpprefjp.github.io/lang/cpp17/nodiscard.html

ちなみにnodiscardが付いているが、例外的にどうしても戻り値を使いたくない場合は以下のようにvoidキャストで戻り値を破棄すれば警告はでない。

static_cast<void>(add(1, 2));

Discussion