189

NULL単純に書くことによって存在しないことへのポインターをチェックするのは安全ですか、それともif(pointer)使用する必要がありますif(pointer != NULL)か?

4

14 に答える 14

46

はい、できます。

  • null ポインターは暗黙的に false に変換されます
  • null 以外のポインターは true に変換されます。

これは C++ 標準変換の一部であり、ブール変換句に分類されます。

§ 4.12 ブール変換

算術、スコープなし列挙、ポインター、またはメンバー型へのポインターの prvalue は、bool 型の prvalue に変換できます。ゼロ値、NULL ポインター値、または NULL メンバー ポインター値は false に変換されます。その他の値は true に変換されます。std::nullptr_t 型の prvalue は bool 型の prvalue に変換できます。結果の値は false です。

于 2013-07-21T12:05:51.520 に答える
2

null ポインターの関連する使用例は次のとおりです。

  • 存在しないか、まだリンクされていない、より深いツリー ノードのようなものへのリダイレクト。これは、常に専用のクラスに緊密にカプセル化する必要があるため、読みやすさや簡潔さはここではそれほど問題ではありません。
  • 動的キャスト。基本クラスのポインターを特定の派生クラスのポインターにキャストする (回避する必要がありますが、場合によっては必要になることがあります) ことは常に成功しますが、派生クラスが一致しない場合は null ポインターになります。これを確認する1つの方法は、

    Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
    if(derived_ptr != nullptr) { ... }
    

    (または、できればauto derived_ptr = ...)。これは、安全保護ifブロックのスコープ外に (おそらく無効、つまり null) 派生ポインターを残すため、悪いことです。C++ ではブール変換可能な変数を-conditionifに導入できるため、これは必要ありません。

    if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }
    

    これは短くてスコープセーフであるだけでなく、その意図もより明確です。別のif条件でnullをチェックすると、読者は「わかりましたderived_ptr。ここでnullであってはなりません...まあ、なぜだろうヌルですか?」一方、1行のバージョンでは、「に安全にキャストできる場合は、それを...に使用してください」と非常に明白に述べてbase_ptrDerived*ます。

    ポインターを返す他の失敗の可能性のある操作でも同じことが機能しますが、IMO では一般的にこれを避ける必要がboost::optionalあります。ポインターではなく、失敗する可能性のある操作の結果の「コンテナー」などを使用することをお勧めします。

したがって、null ポインターの主な使用例を常に暗黙的キャスト スタイルのバリエーションで記述する必要がある場合は、一貫性の理由から、常にif(ptr)このスタイルを使用することをお勧めします。つまり、 over を推奨しif(ptr!=nullptr)ます。


残念ながら宣伝で締めくくる必要があります。構文は、実際には、このような問題に対する実際の解決策であるパターン マッチングif(auto bla = ...)の、やや面倒な近似にすぎません。最初に何らかのアクション (ポインターのキャストなど) を強制してから、失敗する可能性があると考えるのはなぜですか?つまり、ばかげていると思いませんか? 食材があり、スープを作りたいとします。たまたま柔らかい野菜の場合は、ジュースを抽出するタスクをアシスタントに渡します。あなたは最初にそれを見ません。ポテトを持っているときは、アシスタントにそれを渡しますが、アシスタントは失敗のメモで顔を平手打ちします。ああ、命令型プログラミング!

はるかに良い: 遭遇する可能性のあるすべてのケースをすぐに検討してください。その後、それに応じて行動してください。ハスケル:

makeSoupOf :: Foodstuff -> Liquid
makeSoupOf p@(Potato{..}) = mash (boil p) <> water
makeSoupOf vegetable
 | isSoft vegetable  = squeeze vegetable <> salt
makeSoupOf stuff  = boil (throwIn (water<>salt) stuff)

Haskell には、実際に重大な障害の可能性がある場合 (および他の多くのもの) のための特別なツールもあります: モナドです。しかし、ここはそれらを説明する場所ではありません。

⟨/広告⟩

于 2013-07-21T18:32:53.857 に答える
0

はい。実際、あなたはすべきです。セグメンテーション違反が発生するかどうか疑問に思っている場合は、そうではありません。

于 2013-07-21T12:09:17.313 に答える
-1

「安全ですか…?」言語標準と生成されたコードに関する質問です。

「良い習慣ですか?」は、任意の人間がステートメントを読んだ場合に、そのステートメントがどれだけよく理解されるかについての質問です。この質問をしている場合、「安全な」バージョンは将来の読者やライターにとってあまり明確ではないことを示唆しています。

于 2013-07-24T05:54:25.407 に答える
-1

経験則として、ifを次のように書き直すことができると思います

const bool local_predicate = *if-expression*;
if (local_predicate) ...

NO WARNINGS の原因となるような場合は、それがif-expressionの推奨スタイルになるはずです。(ポインタは言うまでもなく、古い C BOOL( #define BOOL int) を C++に代入すると、警告が表示されることはわかっています。)bool

于 2013-07-22T13:10:24.643 に答える
-1

はい、「IF」条件はその中の条件が真になった場合にのみ評価されるため、いつでもこれを行うことができます。C にはブール値の戻り値の型がないため、条件が真の場合はゼロ以外の値を返し、'IF' の条件が偽であることが判明した場合は常に 0 を返します。デフォルトで返されるゼロ以外の値は 1 です。したがって、コードの記述方法はどちらも正しいですが、私は常に 2 番目の方法を好みます。

于 2013-07-21T19:09:01.230 に答える