web-dev-qa-db-ja.com

C ++のポインターにNULLまたは0(ゼロ)を使用しますか?

C++がCの上に固定された初期のC++では、(void*)0として定義されていたため、NULLは使用できませんでした。 void*以外のポインターにNULLを割り当てることはできませんでした。当時、NULLポインターに0(ゼロ)を使用していたことが受け入れられました。

今日まで、ゼロポインターをヌルポインターとして使用し続けていますが、周りの人はNULLを使用することを主張しています。個人的には、既存の値に名前(NULL)を付けることには何のメリットもありません。また、ポインターを真理値としてテストすることも好きです。

if (p && !q)
  do_something();

その後、ゼロを使用するほうが理にかなっています(NULLを使用する場合、p && !qを論理的に使用することはできません-NULLがゼロであると仮定しない限り、NULL 、その場合はNULLを使用する理由。

NULLよりもゼロを好む(またはその逆)客観的な理由はありますか、それとも個人的な好みだけですか?

編集:RAIIと例外では、ゼロ/ NULLポインタを使用することはめったにありませんが、それでも必要な場合があることを追加する必要があります。

184
camh

これに関するStroustrupの見解は次のとおりです。 C++スタイルとテクニックに関するFAQ

C++では、NULLの定義は0であるため、外観上の違いのみがあります。私はマクロを避けることを好むので、0を使用します。NULLの別の問題は、人々がときどきそれが0や整数ではない、あるいはその両方と異なると誤解することです。先行標準コードでは、NULLは不適切なものに定義されていたため、避ける必要がありました。最近ではそれほど一般的ではありません。

Nullポインターに名前を付ける必要がある場合は、nullptrと呼びます。それがC++ 11で呼ばれていることです。次に、nullptrがキーワードになります。

そうは言っても、小さなものに汗をかかないでください。

175
Martin Cote

いくつかの議論がありますが(そのうちの1つは比較的最近のものです)、これに関するBjarneの立場に反すると思います。

  1. 意図の文書化

NULLを使用すると、その使用に関する検索が可能になり、開発者wantedNULLポインターを使用することに関係なく、コンパイラによってNULLとして解釈されているかどうか。

  1. ポインタと「int」のオーバーロードは比較的まれです

みんなが引用する例は次のとおりです。

void foo(int*);
void foo (int);

void bar() {
  foo (NULL);  // Calls 'foo(int)'
}

ただし、少なくとも私の意見では、上記の問題は、nullポインター定数にNULLを使用しているということではなく、非常に異なる種類の引数を取る 'foo'のオーバーロードがあることです。パラメーターもintである必要があります。他のタイプはあいまいな呼び出しになり、有用なコンパイラー警告を生成するためです。

  1. 分析ツールは今日を助けることができます!

C++ 0xがない場合でも、NULLがポインターに使用されていること、および0が整数型に使用されていることを確認するツールが現在利用可能です。

  1. C++ 11 には新しいstd::nullptr_tタイプが追加されます。

これは、テーブルへの最新の引数です。 0NULLの問題はC++ 0xで積極的に対処されており、NULLを提供するすべての実装で、最初に行うことを保証できます。

#define NULL  nullptr

0ではなくNULLを使用する場合、変更はほとんどまたはまったく労力なしで型安全性が改善されます-使用すると、NULL for 0。今日0を使用している人は誰でも...えーと...彼らが正規表現について十分な知識を持っていることを願っています...

121
Richard Corden

NULLを使用します。 NULLは意図を示します。 0であることは実装の詳細であり、重要ではありません。

43
Andy Lester

私はいつも使用します:

  • NULLポインター用
  • '\0'文字
  • 0.0 floatおよびdoubleの場合

ここで、0で問題ありません。それは信号の意図の問題です。とは言うものの、私はそれについてアナルではありません。

35
Andrew Stein

ずっと前に(他のほとんどのマクロと同様に)NULLの使用をやめました。マクロをできる限り避けたいだけでなく、CおよびC++コードでNULLが過剰に使用されているように思われるため、これを行いました。ポインタだけでなく、0の値が必要な場合に使用されるようです。

新しいプロジェクトでは、これをプロジェクトヘッダーに入れます。

static const int nullptr = 0;

さて、C++ 0x準拠のコンパイラが到着したら、その行を削除するだけです。これの素晴らしい利点は、Visual Studioがすでにnullptrをキーワードとして認識し、適切に強調表示することです。

35
Ferruccio
    cerr << sizeof(0) << endl;
    cerr << sizeof(NULL) << endl;
    cerr << sizeof(void*) << endl;

    ============
    On a 64-bit gcc RHEL platform you get:
    4
    8
    8
    ================

物語の教訓。ポインターを処理する場合は、NULLを使用する必要があります。

1)あなたの意図を宣言します(変数がポインターか数値型かを把握しようとしてすべてのコードを検索させないでください)。

2)変数の引数を予期する特定のAPI呼び出しでは、NULLポインターを使用して引数リストの終わりを示します。この場合、NULLの代わりに「0」を使用すると問題が発生する可能性があります。 64ビットプラットフォームでは、va_arg呼び出しには64ビットポインターが必要ですが、32ビット整数のみを渡します。他の32ビットに依存しているように思えますか?特定のコンパイラー(Intelのicpcなど)はあまり優雅ではありませんが、これによりランタイムエラーが発生しました。

20
abonet

正しく思い出せば、使用したヘッダーでNULLの定義が異なります。 Cの場合は(void *)0として定義され、C++の場合は0として定義されます。コードは次のようになります。

#ifndef __cplusplus
#define NULL (void*)0
#else
#define NULL 0
#endif

個人的には、NULL値を使用してNULLポインターを表します。これにより、整数型ではなくポインターを使用していることが明示されます。はい、内部的にはNULL値はまだ0ですが、そのように表されていません。

さらに、整数のブール値への自動変換に依存せず、明示的に比較します。

たとえば、次の使用を好む:

if (pointer_value != NULL || integer_value == 0)

のではなく:

if (pointer_value || !integer_value)

これはC++ 11ですべて修正され、nullptrの代わりにNULLを使用でき、nullptrのタイプであるnullptr_tも使用できると言えば十分です。

16
Daemin

私は歴史が話したと言うだろうと0(ゼロ)を使用することを支持して主張した人々は間違っていた(Bjarne Stroustrupを含む)。 0を支持する議論は、主に美学と「個人的な好み」でした。

新しいnullptr型を使用したC++ 11の作成後、一部のコンパイラは、0はポインターではないため、ポインター引数を持つ関数に0を渡すことについて(デフォルトのパラメーターを使用して)文句を言い始めました。

コードがNULLを使用して記述されている場合、代わりにnullptrにするためにコードベースを介して単純な検索と置換を実行できます。 0の選択をポインターとして使用して記述されたコードで立ち往生している場合、それを更新するのははるかに面倒です。

そして、今すぐC++ 03標準に合わせて新しいコードを書く必要がある(そしてnullptrを使用できない)場合は、実際には単にNULLを使用する必要があります。これにより、将来の更新がはるかに簡単になります。

15
Gaute Lindkvist

私はかつて、0が有効なアドレスであり、NULLが特別な8進数値として定義されているマシンで働いていました。そのマシン(0!= NULL)では、次のようなコード

char *p;

...

if (p) { ... }

期待どおりに動作しません。あなたは書くことをしなければならなかった

if (p != NULL) { ... }

最近ではほとんどのコンパイラがNULLを0として定義していると思いますが、私はまだ数年前の教訓を覚えています。NULLは必ずしも0ではありません。

11
mxg

私は通常0を使用します。マクロは好きではありません。また、使用しているサードパーティのヘッダーがNULLを奇妙なものに再定義しないという保証はありません。

C++がnullptrキーワードを取得するまで、Scott Meyersなどが提案したnullptrオブジェクトを使用できます。

const // It is a const object...
class nullptr_t 
{
public:
    template<class T>
    operator T*() const // convertible to any type of null non-member pointer...
    { return 0; }

    template<class C, class T>
    operator T C::*() const   // or any type of null member pointer...
    { return 0; }

private:
    void operator&() const;  // Can't take address of nullptr

} nullptr = {};

詳細については、Google「nullptr」。

11
jon-hanson

0またはNULLを使用しても同じ効果があります。

ただし、それは両方が良いプログラミング手法であることを意味するものではありません。パフォーマンスに違いがないことを考えると、不可知論者/抽象の選択肢よりも低レベルを意識したオプションを選択することは、プログラミングの悪い習慣です。 コードの読者があなたの思考プロセスを理解するのを助ける

NULL、0、0.0、 '\ 0'、0x00、およびwhatelseはすべて同じものに変換されますが、プログラム内の異なる論理エンティティです。それらはそのまま使用する必要があります。 NULLはポインター、0は数量、0x0は興味深いビットなどの値です。コンパイルするかどうかにかかわらず、ポインターに「\ 0」を割り当てません。

一部のコミュニティでは、環境の契約を破ることにより、環境に関する詳細な知識を実証することを奨励しています。ただし、責任あるプログラマーは、保守可能なコードを作成し、そのような慣行をコードから排除します。

9
Chris

標準ではNULL == 0が保証されているため、どちらでも可能です。あなたの意図を記録するので、私はNULLを好みます。

9
Mark Ransom

Stroustroupを含め、奇妙なことに誰も言及していません。標準や美学について多くのことを話している間、例えば変数引数リストでNULLの代わりに0を使用することはdangerousであることに誰も気づきませんでしたsizeof(int) != sizeof(void*)のアーキテクチャ上。 Stroustroupのように、私は審美的な理由から0を好みますが、その型があいまいな場合は使用しないように注意する必要があります。

可能な場合はC++リファレンスを使用して、質問全体を避けようとします。のではなく

void foo(const Bar* pBar) { ... }

あなたはしばしば書くことができるかもしれません

void foo(const Bar& bar) { ... }

もちろん、これは常に機能するとは限りません。ただし、nullポインターは使いすぎる可能性があります。

4
Ðаn

私はこれについてStroustrupと一緒にいます:-) NULLは言語の一部ではないため、0を使用することを好みます。

3
Rob

ほとんどが個人的な好みですが、オブジェクトが現在何も指し示していないポインタであることがNULLであるとはっきりと主張することもできます。

void *ptr = &something;
/* lots o' code */
ptr = NULL; // more obvious that it's a pointer and not being used

IIRCでは、標準ではNULLを0にする必要がないため、<stddef.h>で定義されているものを使用するのがおそらくコンパイラに最適です。

引数のもう1つの側面は、論理比較(ブールへの暗黙のキャスト)を使用するか、NULLに対する明示的なチェックを使用するかということですが、それは読みやすさにもなります。

3
Jimmy

NULLは、値が算術値ではなくポインターを表すことを意図していることが明確になるため、NULLを使用することを好みます。マクロであるという事実は残念ですが、非常に広く浸透しているため、危険はほとんどありません(誰かが本当に骨の折れる何かをしない限り)。最初からキーワードだったらよかったのですが、何ができますか?

そうは言っても、ポインター自体を真理値として使用しても問題はありません。 NULLと同じように、それは染み込んだイディオムです。

C++ 09はnullptrコンストラクトを追加します。

3
Michael Burr

私は常に0を使用します。C++を初めて学習したときに、0を使用することをお勧めするものを読んだので、実際に考えたわけではありません。理論的には、読みやすさに混乱の問題があるかもしれませんが、実際には、数千時間と数百万行のコードでそのような問題に遭遇したことは一度もありません。 Stroustrupが言うように、標準がnullptrになるまで、それは本当に個人的な美学の問題です。

1
Gerald

誰かが一度私に言った...私はNULLを69に再定義するつもりです。それ以来、私はそれを使用しません:P

コードが非常に脆弱になります。

編集:

標準のすべてが完璧ではありません。マクロNULLは、C NULLマクロと完全に互換性のない、実装定義のC++ NULLポインター定数です。タイプ隠蔽以外に、役に立たずエラーが発生しやすいツールで変換するものです。

NULLはNULLポインターとしてではなく、O/OLリテラルとして動作します。

次の例は混乱しないことを教えてください:

void foo(char *); 
void foo(int); 
foo(NULL); // calls int version instead of pointer version! 

すべてのため、新しい標準ではstd :: nullptr_tが表示されます

新しい標準を待ちたくなく、nullptrを使用したい場合は、少なくともMeyersが提案したようなまともなものを使用してください(jon.hコメントを参照)。

可能であれば、0またはNULLポインターをまったく使用しないと主張します。

それらを使用すると、遅かれ早かれ、コードのセグメンテーション違反が発生します。私の経験では、これと、gereralのポインターは、C++のバグの最大の原因の1つです。

また、コード全体に「if-not-null」ステートメントが発生します。常に有効な状態に依存できる場合は、はるかに優れています。

ほとんどの場合、より良い代替手段があります。

1
Jan P