[解決済み] 強化されたGCC 6オプティマイザは、なぜ実用的なC++コードを壊すのですか?
質問
GCC 6 には新しいオプティマイザ機能があります
: を想定しています。
this
は常にnullでないことを前提に最適化されます。
値域伝搬は、C++メンバ関数のthisポインタが非Nullであると仮定するようになりました。これにより、以下のような一般的なNullポインタチェックが不要になります。 が、一部の不適合なコードベース (Qt-5, Chromium, KDevelop など) を破壊してしまいます。 . 一時的な回避策として、 -fno-delete-null-pointer-checks を使用することができます。誤ったコードは、-fsanitize=undefinedを使用することで識別できます。
この変更文書では、頻繁に使用されるコードの驚くほど多くを壊してしまうため、危険であることを明確に指摘しています。
なぜこの新しい仮定が実用的なC++のコードを壊してしまうのでしょうか?
不注意なプログラマや無知なプログラマがこの特定の未定義の動作に依存している特定のパターンがあるのでしょうか?私は、誰かが
if (this == NULL)
というのは、あまりに不自然だからです。
解決方法は?
そもそも、なぜ善意の人が小切手を書くのかという疑問があるのでしょう。
最も一般的なケースは、自然に発生する再帰呼び出しの一部であるクラスがある場合でしょう。
持っていたとしたら
struct Node
{
Node* left;
Node* right;
};
をC言語で書くと、こうなります。
void traverse_in_order(Node* n) {
if(!n) return;
traverse_in_order(n->left);
process(n);
traverse_in_order(n->right);
}
C++では、これをメンバ関数にするのがいい感じです。
void Node::traverse_in_order() {
// <--- What check should be put here?
left->traverse_in_order();
process();
right->traverse_in_order();
}
C++の初期(標準化以前)には、メンバ関数は構文上の砂糖であることが強調されており、そのような関数では
this
パラメータは暗黙の了解です。コードはC++で書かれ、同等のC言語に変換され、コンパイルされた。と比較する明示的な例さえありました。
this
をNULLにすることは意味があり、オリジナルのCfrontコンパイラもこれを利用していた。ですから、C言語のバックグラウンドからすると、チェックの対象は明らかなのです。
if(this == nullptr) return;
注:Bjarne Stroustrupは、以下のルールについて言及しています。
this
は何年も前から変更されています。
こちら
そして、これは長年にわたって多くのコンパイラで動作していました。標準化が進むと、これは変わりました。さらに最近になって、コンパイラは、メンバ関数を呼び出す際に
this
ビーイング
nullptr
は未定義の動作であり、つまりこの条件は常に
false
また、コンパイラはこれを自由に省略することができます。
つまり、このツリーの探索を行うには、どちらかが必要です。
-
を呼び出す前に、すべてのチェックを行います。
traverse_in_order
void Node::traverse_in_order() { if(left) left->traverse_in_order(); process(); if(right) right->traverse_in_order(); }
これは、すべての呼び出し先で、NULLルートがあるかどうかもチェックすることを意味します。
-
メンバー関数を使用しない
これは、古いC言語のコードを(おそらくスタティックメソッドとして)書いて、オブジェクトをパラメータとして明示的に呼び出すことを意味します。
Node::traverse_in_order(node);
ではなくnode->traverse_in_order();
を呼び出し先で使用します。 -
この例を規格に準拠した形で修正する最も簡単な/最も新しい方法は、実際にセンチネルノードではなく
nullptr
.// static class, or global variable Node sentinel; void Node::traverse_in_order() { if(this == &sentinel) return; ... }
最初の2つの選択肢はどちらもそれほど魅力的とは思えません。コードはそれで済むかもしれませんが、彼らは悪いコードを書くために
this == nullptr
適切な修正方法を使わず
そうやって進化してきたコードベースには
this == nullptr
のチェックを入れています。
関連
-
[解決済み】C++コンパイルタイムエラー:数値定数の前に期待される識別子
-
[解決済み] explicit キーワードの意味は?
-
[解決済み] なぜGCCはa*a*a*a*aを(a*a*a)*(a*a*a)に最適化しないのでしょうか?
-
[解決済み] なぜテンプレートはヘッダーファイルでしか実装できないのですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] 0.1fを0にすると、なぜ10倍もパフォーマンスが落ちるのですか?
-
[解決済み] Cプリプロセッサはなぜ "linux "という単語を定数 "1 "と解釈するのですか?
-
[解決済み] g++とgccの違いは何ですか?
-
[解決済み] Collatz予想の検証を行うC++のコードは、なぜ手書きのアセンブリよりも高速に動作するのでしょうか?
-
[解決済み] なぜGCCは、速度の代わりにサイズに最適化すると、15-20%速いコードを生成するのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】構造体のベクター初期化について
-
[解決済み】識別子 "string "は未定義?
-
[解決済み】Cygwin Make bash コマンドが見つかりません。
-
[解決済み】C++プログラムでのコンソールの一時停止
-
[解決済み】「std::operator」で「operator<<」にマッチするものがない。
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み】なぜ、サイズ8の初期化されていない値を使用するのでしょうか?
-
[解決済み】std::cin.getline( ) vs. std::cin
-
[解決済み】'std::cout'への未定義の参照