int fn();
void whatever()
{
(void) fn();
}
未使用の戻り値を void にキャストする理由はありますか、それとも完全に時間の無駄だと思うのは正しいですか?
ファローアップ:
それはかなり包括的なようです。自己文書化コードはコメントよりも優れているため、未使用の戻り値にコメントするよりも優れていると思います。個人的には、不要なノイズなので、これらの警告をオフにします。
そのせいで虫が逃げたら言葉を食う…
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++ のタグを付けたので、static_castを使用する必要があります。
static_cast<void>(fn());
コンパイラが戻り値を void にキャストする限り、ほとんど意味がありません。
これを行う本当の理由は、 lintと呼ばれるCコードで使用されるツールにまでさかのぼります。
コードを分析して、考えられる問題を探し、警告と提案を発行します。関数が値を返し、それがチェックされなかっlint
た場合、これが偶発的な場合に備えて警告します。この警告を黙らせるlint
には、に呼び出しをキャストします(void)
。
へのキャストvoid
は、未使用の変数および保存されていない戻り値または式に対するコンパイラの警告を抑制するために使用されます。
Standard(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);
それも大丈夫です。
c++17 以降、キャスト[[maybe_unused]]
の代わりに使用できる属性があります。void
あなたの機能にとって、voidへのキャストは無意味です。また、Davidの回答で示唆されているように、コードを読んでいる人に何かを知らせるためにそれを使用するべきではないと主張します。自分の意図について何かを伝えたい場合は、コメントを使用することをお勧めします。このようなキャストを追加すると、奇妙に見えるだけで、考えられる理由について疑問が生じます。ただ私の意見...
void へのキャストはコストがかかりません。コンパイラがそれをどのように扱うかについての情報です。
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
as に理由を追加することもできます。[[nodiscard("reason")]]
GCCwarn_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 でテスト済み。