なぜ未使用の戻り値をvoidにキャストするのですか?


112
int fn();

void whatever()
{
    (void) fn();
}

未使用の戻り値をvoidにキャストする理由はありますか、それとも完全に時間の無駄だと思いますか?

ファローアップ:

まあそれはかなり包括的なようです。自己文書化コードはコメントよりも優れているため、未使用の戻り値にコメントを付けるよりも優れていると思います。個人的には、不要なノイズのため、これらの警告をオフにします。

バグが原因で脱出したら言葉を食べます...

回答:


79

Davidの答えは、この動機をかなりカバーしています。この関数が返すことを知っているが、明示的に無視していることを他の「開発者」に明示的に示します。

これは、必要なエラーコードが常に処理されるようにする方法です。

完全な静的キャスト表記の使用はここではやり過ぎのように感じるので、C ++の場合、これはおそらくCスタイルのキャストを使用することを好む唯一の場所だと思います。最後に、コーディング標準をレビューまたは記述している場合は、オーバーロードされた演算子への呼び出し(関数呼び出し表記を使用しない)もこれから免除されることを明示的に示すこともお勧めします。

class A {};
A operator+(A const &, A const &);

int main () {
  A a;
  a + a;                 // Not a problem
  (void)operator+(a,a);  // Using function call notation - so add the cast.

これは私がcスタイルのキャストも好む唯一の場所です。私のコーディング標準では、「a + a」に(void)を追加します。あまりにも(適切に括弧を付け、もちろん:p)
Johannes Schaub-litb 2009年

8
少し外れたトピックですが、なぜ「a + a;」を実行するのでしょうか。戻り値を使用せずにそのように?それは本当に私にとって副作用の乱用のようであり、コードの意図を難読化しています。
Rob K

5
さて、あなたが毎日使うものは「a = a」でしょう。これは、割り当てられたオブジェクトを返します(正常に動作するすべてのクラスの場合!:))。もう1つの例は、os << "Hello World" << std :: endlです。それぞれが「os」オブジェクトを返します。
Richard Corden

46

仕事では、それを使用して関数に戻り値があることを認めますが、開発者はそれを無視しても安全であると断言しました。質問にC ++のタグを付けたので、static_castを使用する必要があります。

static_cast<void>(fn());

コンパイラーが返す限り、戻り値をvoidにキャストしても意味がありません。


未使用の戻り値に関する警告を抑制しますか?
ポールトンブリン

いいえ、違います。@Mykola:GCC4では、戻り値を無視してはならないという警告をトリガーする属性をアタッチできます。
David Holm

2
私はg ++を使用していますが、そのようなキャストでも警告が表示されます。
klew 2009年

2
どの警告オプションを使用しますか?-Wunused-valueが私の環境で警告をトリガーしない
Mykola Golubyev 2009年

VC ++では、警告を抑制します
jalf

39

これを行う本当の理由は、lintと呼ばれるCコードで使用されるツールにさかのぼります。

コードを分析して、起こりうる問題を探し、警告と提案を出します。関数がチェックされなかった値を返したlint場合、これが偶発的である場合に警告します。lintこの警告を黙らせるには、に呼び出しをキャストします(void)


2
この方法で開始された可能性がありますが、ほとんどのツールには、このような警告を抑制する別のメカニズムが備わっています。また、これが始まった理由に関係なく、特に安全上重要なコードのドメイン内では、これは開発者の意図を「文書化」するための通常の方法になっています。
Richard Corden

5
GCCは-Wallを使用してこれについて警告を出します。
グレイフェード2009年

23

キャストvoidは、未使用の変数や未保存の戻り値または式に対するコンパイラの警告を抑制するために使用されます。

規格(2003)は§5.2.9/ 4で述べています、

任意の式を明示的に「cv void」型に変換できます。式の値は破棄されます。

だからあなたは書くことができます:

//suppressing unused variable warnings
static_cast<void>(unusedVar);
static_cast<const void>(unusedVar);
static_cast<volatile void>(unusedVar);

//suppressing return value warnings
static_cast<void>(fn());
static_cast<const void>(fn());
static_cast<volatile void>(fn());

//suppressing unsaved expressions
static_cast<void>(a + b * 10);
static_cast<const void>( x &&y || z);
static_cast<volatile void>( m | n + fn());

すべてのフォームが有効です。私は通常次のように短くします:

//suppressing  expressions
(void)(unusedVar);
(void)(fn());
(void)(x &&y || z);

それも大丈夫です。


1
ただし、コンパイラの警告が常にオフになるわけではありません。gccはvoidへのキャストに応答しないようです
Matt

@マット:GCCのどのバージョンを使用していますか?コードをideone.comまたはStacked-crooked.comに投稿できますか(後者の方が優れています)。
Nawaz 2013

1
標準の「破棄された」表現は、警告がリンターによって出されるべきではないことを意味しますか?
Ciro Santilli郝海东冠状病六四事件法轮功

2
@CiroSantilli巴撤馬文件六四事件法轮功:....それは興味深い質問です。現在のところ、その答えはわかりません。とにかく知ったら教えてください。
Nawaz

8

c ++ 17以降[[maybe_unused]]voidキャストの代わりに使用できる属性があります。


1
nodiscard興味深いかもしれないC ++ 17も追加しました:stackoverflow.com/a/61675726/895245また、私はあなたが[[maybe_unused]]思われる呼び出しに直接適用することはできません、呼び出しの戻りを受け入れるダミー変数にのみ適用できますか?それが正しければ、少し不安定です。
Ciro Santilli郝海东冠状病六四事件法轮功

4

voidにキャストしてもコストはかかりません。コンパイラーがそれをどのように扱うかについての情報にすぎません。


1
コードを記述し、その後コードを読んで理解し(そして無視する)時間が自由であれば、「費用はかかりません」。IMO、書く(void)ことは私に時間とエネルギーを費やし、著者が表現がどのように機能するか知っていたのか疑問に思います。
wallyk

4

プログラムの機能上、voidへのキャストは意味がありません。また、Davidの回答で示唆されているように、コードを読んでいる人に何かを知らせるためにそれを使用しないでください。自分の意図について何かを伝えたい場合は、コメントを使用することをお勧めします。このようなキャストを追加すると、奇妙に見えるだけで、考えられる理由についての質問が発生します。ただ私の意見...


2
これは、戻り値を気にする必要がないこと、処理することを忘れていないことを他のユーザーに明示的に知らせる既知のパターンです。
Spidey 2014年

For the functionality of you program casting to void is meaningless自己文書化とコンパイル時の警告の数については、実際にそうではありません。コードがそれ自体を説明するとき、you should not use it to signal something to the person that is reading the code [...] it is better to use a comment.最高のコメントはコメントなしです。そして、繰り返しになりますが、その過程で有効な警告コンパイラを満足させます。
underscore_d

「このようなキャストを追加すると、奇妙に見えるだけで、考えられる理由についての質問が発生します」。私はこれらの1つを発見し、それが私がこれを読んでいる理由です。私の訓練されていない脳への神秘的なスタック虐待のようでした。
mynameisnafe 2017

1

また、コードがMISTA(または他の)標準に準拠していることを確認する場合、LDRAなどの自動ツールでは、戻り値を(void)に明示的にキャストしない限り、戻り値を返さずに戻り値型を持つ関数を呼び出すことはできません。


0

C ++ 17 [[nodiscard]]

C ++ 17は、「戻り値無視ビジネス」を属性で標準化しました。

したがって、準拠した実装が常にnodiscard指定された場合にのみ警告し、それ以外の場合は警告しないことを願っています。

例:

main.cpp

[[nodiscard]] int f() {
    return 1;
}

int main() {
    f();
}

コンパイル:

g++ -std=c++17 -ggdb3 -O0 -Wall -Wextra -pedantic -o main.out main.cpp

結果:

main.cpp: In function int main()’:
main.cpp:6:6: warning: ignoring return value of int f()’, declared with attribute nodiscard [-Wunused-result]
    6 |     f();
      |     ~^~
main.cpp:1:19: note: declared here
    1 | [[nodiscard]] int f() {
      | 

以下はすべて警告を回避します。

(void)f();
[[maybe_unused]] int i = f();

私は通話でmaybe_unused直接使用することができませんでしたf()

[[maybe_unused]] f();

与える:

main.cpp: In function int main()’:
main.cpp:6:5: warning: attributes at the beginning of statement are ignored [-Wattributes]
    6 |     [[maybe_unused]] f();
      |     ^~~~~~~~~~~~~~~~

(void)鋳造作業は必須ではありませんが、標準で「奨励」されています。どのように私は意図的に[[nodiscard]]の戻り値を破棄することができますか?

また、警告メッセージからわかるように、警告の「解決策」の1つは次のように追加すること-Wno-unused-resultです。

g++ -std=c++17 -ggdb3 -O0 -Wall -Wextra -pedantic -Wno-unused-result -o main.out main.cpp

もちろん、このようにグローバルに警告を無視することはお勧めしません。

C ++ 20では、https//en.cppreference.com/w/cpp/language/attributes/nodiscardで説明nodiscardされ[[nodiscard("reason")]]ているように、理由をに追加することもできます

GCC warn_unused_result属性

の標準化の前[[nodiscard]]、およびCが最終的に属性の標準化を決定する前に、GCCはとまったく同じ機能を実装しましたwarn_unused_result

int f() __attribute__ ((warn_unused_result));

int f() {
    return 1;
}

int main() {
    f();
}

それは与える:

main.cpp: In function int main()’:
main.cpp:8:6: warning: ignoring return value of int f()’, declared with attribute warn_unused_result [-Wunused-result]
    8 |     f();
      |     ~^~

ANSI Cにはこのための標準がないため、ANSI CはどのC標準ライブラリ関数が属性を持っているかどうかを指定せず、したがって実装はでマークする必要があるかどうかについて独自の決定を行っていますwarn_unuesd_result。そのため、一般に、(void)キャストを使用して標準ライブラリ関数の呼び出しの戻りを無視し、実装での警告を完全に回避する必要があります。

GCC 9.2.1、Ubuntu 19.10でテスト済み。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.