Skip to content

[[nodiscard]]の使い方と活用場面(C++17以降)

問題の本質

C++17で導入された[[nodiscard]]属性について、特に「なぜクラスのconstメソッドにこの属性を付ける必要があるのか」「コンパイラが戻り値を無視するとは具体的にどういう状況か」という疑問が生じます。例として以下のコードを考えます:

cpp
class Test {
public:
    [[nodiscard]] int f(int a, int b) const {
        return a + b;
    }
};

一般的な誤解として「呼び出し側が戻り値を処理する限り問題ないのでは?」と思うかもしれません。しかしこの属性が防ぐのは、プログラマが意図せず戻り値を無視してしまうバグです。具体的には:

cpp
Test obj;
obj.f(10, 20); // 警告発生!戻り値を無視している

解決策:[[nodiscard]]の適切な使い方

[[nodiscard]]は主に以下の3つのケースで効果を発揮します:

1. 計算結果だけが意味を持つ関数(副作用のない関数)

cpp
[[nodiscard]] double calculateArea(double radius) {
    return 3.14 * radius * radius;
}

// 使用例
calculateArea(5.0); // 警告: 計算結果を無視している

2. 新しいオブジェクトを返すメソッド(元のオブジェクトを変更しない)

cpp
class DateTime {
public:
    [[nodiscard]] DateTime addDays(int days) const;
};

// 誤った使用例
DateTime dt;
dt.addDays(1); // 警告: 新しいDateTimeオブジェクトを無視!

3. エラーコードやリソースハンドルを返す関数

cpp
[[nodiscard]] FileHandle openFile(const std::string& path) {
    // ファイルオープン処理
}

// 危険な例
openFile("data.txt"); // 警告: ファイルハンドルを無視→リソースリークの可能性

実際の警告例

コンパイラは[[nodiscard]]関数の戻り値無視を検出すると警告を出します:

cpp
class List {
public:
    [[nodiscard]] List reverse() const;
};

List myList{1, 2, 3};
myList.reverse();  // 警告: nodiscard属性付き関数の戻り値を破棄
std::cout << myList; // 元のリストが表示される(逆順ではない)

正しい使い方

cpp
List reversed = myList.reverse(); // 戻り値を受け取る
std::cout << reversed; // 逆順リストが表示される

なぜメンバ関数に必要か?

IDE(CLionなど)がconstメソッドに[[nodiscard]]を提案する理由:

  • 意図が明確化
    関数が状態変更ではなく「結果を返すだけ」であることを示す
  • バグ予防
    オブジェクトの状態が変更されないため、無視はほぼ確実に誤り
  • 自己文書化
    コードを見ただけで「戻り値を処理すべき」と分かる

適用すべきではないケース

すべての関数に付けるべきではありません:

cpp
// 副作用が目的の関数(戻り値の無視が許容される例)
void saveToDatabase(); // 戻り値ないので不要
void getVersion();     // バージョン出力だけが目的

注意点

  • static_cast<void>で明示的に無視した場合は警告が抑制されます
cpp
(void)calculateArea(10.0); // 警告なし(意図的な無視を示す)
  • C++20以降ではエラーメッセージのカスタマイズ機能も追加されています

ベストプラクティス

  1. リソース管理関数には必須で適用
  2. 状態変更せず結果を返すメンバ関数に積極適用
  3. コンストラクタにも適用可能(C++20以降)
  4. 警告が煩わしい場合は「無視」ではなく「設計の見直し」を

[[nodiscard]]は現代C++における重要なコードセーフティ機能です。適切な場面で活用することで、戻り値の誤った扱いによるバグをコンパイル時に防止でき、意図が明確な自己文書化コードの作成に貢献します。