NULL
単純に書くことによって存在しないことへのポインターをチェックするのは安全ですか、それともif(pointer)
使用する必要がありますif(pointer != NULL)
か?
14 に答える
はい、できます。
- null ポインターは暗黙的に false に変換されます
- null 以外のポインターは true に変換されます。
これは C++ 標準変換の一部であり、ブール変換句に分類されます。
§ 4.12 ブール変換
算術、スコープなし列挙、ポインター、またはメンバー型へのポインターの prvalue は、bool 型の prvalue に変換できます。ゼロ値、NULL ポインター値、または NULL メンバー ポインター値は false に変換されます。その他の値は true に変換されます。std::nullptr_t 型の prvalue は bool 型の prvalue に変換できます。結果の値は false です。
null ポインターの関連する使用例は次のとおりです。
- 存在しないか、まだリンクされていない、より深いツリー ノードのようなものへのリダイレクト。これは、常に専用のクラスに緊密にカプセル化する必要があるため、読みやすさや簡潔さはここではそれほど問題ではありません。
動的キャスト。基本クラスのポインターを特定の派生クラスのポインターにキャストする (回避する必要がありますが、場合によっては必要になることがあります) ことは常に成功しますが、派生クラスが一致しない場合は null ポインターになります。これを確認する1つの方法は、
Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr); if(derived_ptr != nullptr) { ... }
(または、できれば
auto derived_ptr = ...
)。これは、安全保護if
ブロックのスコープ外に (おそらく無効、つまり null) 派生ポインターを残すため、悪いことです。C++ ではブール変換可能な変数を-condition内if
に導入できるため、これは必要ありません。if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }
これは短くてスコープセーフであるだけでなく、その意図もより明確です。別のif条件でnullをチェックすると、読者は「わかりました
derived_ptr
。ここでnullであってはなりません...まあ、なぜだろうヌルですか?」一方、1行のバージョンでは、「に安全にキャストできる場合は、それを...に使用してください」と非常に明白に述べてbase_ptr
いDerived*
ます。ポインターを返す他の失敗の可能性のある操作でも同じことが機能しますが、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 には、実際に重大な障害の可能性がある場合 (および他の多くのもの) のための特別なツールもあります: モナドです。しかし、ここはそれらを説明する場所ではありません。
⟨/広告⟩
はい。実際、あなたはすべきです。セグメンテーション違反が発生するかどうか疑問に思っている場合は、そうではありません。
「安全ですか…?」言語標準と生成されたコードに関する質問です。
「良い習慣ですか?」は、任意の人間がステートメントを読んだ場合に、そのステートメントがどれだけよく理解されるかについての質問です。この質問をしている場合、「安全な」バージョンは将来の読者やライターにとってあまり明確ではないことを示唆しています。
経験則として、if式を次のように書き直すことができると思います
const bool local_predicate = *if-expression*;
if (local_predicate) ...
NO WARNINGS の原因となるような場合は、それがif-expressionの推奨スタイルになるはずです。(ポインタは言うまでもなく、古い C BOOL
( #define BOOL int
) を C++に代入すると、警告が表示されることはわかっています。)bool
はい、「IF」条件はその中の条件が真になった場合にのみ評価されるため、いつでもこれを行うことができます。C にはブール値の戻り値の型がないため、条件が真の場合はゼロ以外の値を返し、'IF' の条件が偽であることが判明した場合は常に 0 を返します。デフォルトで返されるゼロ以外の値は 1 です。したがって、コードの記述方法はどちらも正しいですが、私は常に 2 番目の方法を好みます。