プログラミング、リファクタリング、そしてすべてにおける究極の疑問: No. 33

同カテゴリーの次の記事

プログラミング、リファクタリング、そしてすべてにおける究極の疑問: No. 34

この記事は、インテル® デベロッパー・ゾーンに公開されている「The Ultimate Question of Programming, Refactoring, and Everything」の日本語参考訳です。


33. null ポインターは逆参照しない

この問題は、GIT のソースコードで見つかりました。このコードにはエラーが含まれています。PVS-Studio アナライザーは、次の診断を出力します。

V595 The ‘tree’ pointer was utilized before it was verified against nullptr. Check lines: 134, 136. (V595 ‘tree’ ポインターは nullptr に対して検証される前に使用されています。次の行を確認してください: 134、136。)

void mark_tree_uninteresting(struct tree *tree)
{
  struct object *obj = &tree->object;
  if (!tree)
    return;
  ....
}

説明

null ポインターの逆参照は、未定義の動作を引き起こすため、良くないことは明確です。その背後にある理論的な根拠については、皆さんも同意されるでしょう。

しかし、その実践については、さまざまな意見があります。特定のコードが正しく動作することを主張するプログラマーは常にいます。彼らのコードは、これまで問題なく動作してきたからです。このセクションは、そういうプログラマーの考え方を変えるためのものです。

私はあえて、さまざまな意見が出るであろう例を選択しました。tree ポインターが逆参照された後、クラスメンバーはそれを使用するだけでなく、このメンバーのアドレスを評価しています。(tree == nullptr) の場合、メンバーのアドレスは全く使用されず、関数は終了します。多くのプログラマーは、これは正しいコードであると考えます。

しかし、そうではありません。このようなコードは記述すべきではありません。例えば、null アドレスへ値を書き込んだ場合、未定義の動作が必ずプログラムのクラッシュになるとは限りません。未定義の動作は、何にでもなりえます。null に等しいポインターを逆参照するとすぐに未定義の動作になります。プログラムの動作について、ここでこれ以上議論することは意味がありません。どのような動作にもなりえるのですから。

未定義の動作の兆候の 1 つは、コンパイラーが “if (!tree) return;” ブロック全体を削除する可能性があることです。コンパイラーは、ポインターはすでに逆参照されているため、null ではないと見なし、チェックを削除できると判断します。これは、プログラムのクラッシュを引き起こす多数のシナリオの 1 つです。

詳しくは、「null ポインターの逆参照が引き起こす未定義の動作」をご覧になることを推奨します。

正しいコード

void mark_tree_uninteresting(struct tree *tree)
{
  if (!tree)
    return;
  struct object *obj = &tree->object;
  ....
}

推奨事項

すべて問題なく動作しているように見える場合であっても、未定義の動作に注意すべきです。未定義の動作はリスクが大きすぎます。前述のように、未定義の動作は、どのような形で表れるか想像することが困難です。すべてが問題なく動作するように見える場合であっても、未定義の動作を回避するようにします。

未定義の動作が何か分かっており、他のプログラマーにはできないことを自分はできると考えるプログラマーがいるかしれません。そして、すべてが問題なく動作したとしても、それは間違っています。次のセクションでは、未定義の動作の危険性について述べます。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

関連記事

  • Parallel Universe マガジンParallel Universe マガジン Parallel Universe へようこそ。 米国インテル社が四半期に一度オンラインで公開しているオンラインマガジンです。インテルの技術者によるテクノロジーの解説や、最新ツールの紹介など、並列化に関する記事を毎号掲載しています。第1号からのバックナンバーを PDF 形式で用意しました、ぜひご覧ください。 12 […]
  • 比較関数の罠比較関数の罠 この記事は、インテル® デベロッパー・ゾーンに公開されている「The Evil within the Comparison Functions」の日本語参考訳です。 この記事の PDF […]
  • 並列プログラミングにおけるロックの効率的な使用並列プログラミングにおけるロックの効率的な使用 この記事は、インテル® ソフトウェア・ネットワークに掲載されている「Using Locks Effectively in Parallel Programming […]
  • マルチスレッド開発ガイド: 4.6 インテル® Parallel Composer を利用して並列コードを開発するマルチスレッド開発ガイド: 4.6 インテル® Parallel Composer を利用して並列コードを開発する コードの並列化にはさまざまな手法があります。この記事では、インテル® Parallel Composer で利用可能な手法の概要を説明し、各手法の主な長所を比較します。インテル® Parallel Composer は Windows* 上の C/C++ を使用した開発のみを対象としていますが、これらの手法の多くは Fortran や […]
  • インテル Parallel Universe 26 号日本語版の公開インテル Parallel Universe 26 号日本語版の公開 インテル Parallel Universe マガジンの最新号が公開されました。この号では、インテル® Xeon Phi™ プロセッサー向けのコードの現代化について説明します。また、インテル® Parallel Studio XE 2017 […]