web-dev-qa-db-ja.com

不完全な型のnullポインタでdeleteを呼び出すことは合法ですか?

もしそうなら、なぜ次のコードは私に警告を与えるのですか?

注:クラスの定義時に宣言されている場合でも、デストラクタもクラス固有の演算子deleteも呼び出されません。

struct C;

int main()
{
    C *c = nullptr;

    delete c;

    return 0;
}

I nderstand why it mightCに自明でない/仮想のデストラクタがあるが、標準の保証/定義がない場合、一般的なケースでは未定義の動作になりますdeletenullptrは、状況に関係なく常にnoopですか?

繰り返しになりますが、不完全な型へのポインタがnullptrである場合について具体的に質問しています!

19
Dan M.

標準では([expr.delete]/5):

削除されるオブジェクトの削除時点でのクラスタイプが不完全であり、完全なクラスに重要なデストラクタまたは割り当て解除関数がある場合、動作は定義されていません。

したがって、Tに重要なデストラクタがある場合、または_operator delete_オーバーロードがある場合は、UBを取得します。 UBがポインタのvalueに基づいていることについては何も言われていません(つまり、それがnullポインタであるかどうか)。


「削除されるオブジェクト」とはどういう意味ですか?

「削除されるオブジェクト」とは、この句が実際のオブジェクトに対するdelete呼び出しにのみ適用されることを意味すると考えることができます。したがって、nullポインターを渡しても、適用されません。

まず、deleteの動作に関する残りの標準的な説明では、その動作はnullポインタには適用されないことを明示的に示しています。 [expr.delete]/6&7はどちらも、「delete-expressionのオペランドの値がnullポインター値でない場合」で始まります。パラグラフ5 明示的にこれらの単語は含まれていません。したがって、nullポインタに適用されると想定する必要があります。

次に、nullポインタが渡された場合、「削除されるオブジェクト」の意味は何でしょうか。結局のところ、そこには「オブジェクト」はありません。

「削除されるオブジェクト」がそのポインタの最後にあるオブジェクトについて具体的に説明している場合、このテキストを解釈することの意味を考えてみてください。さて、重要なデストラクタで不完全なクラスの配列を削除するとどうなりますか?

その論理により、この節適用されません、ポインタがnullであるかどうかに関係なく。どうして? 「削除されるオブジェクト」はarrayタイプであり、クラスタイプではないためです。したがって、この条項は適用できません。つまり、コンパイラは、不完全なクラスの配列に対して_delete[]_を呼び出すことができなければなりません。

しかし、それは不可能実装することです。コンパイラーは、まだ存在していないコードを追跡できる必要があります。

したがって、「削除されるオブジェクト」はstd::remove_pointer_t<std::decay_t<decltype(expr)>>を参照するために意図されたであるか、標準では実装できない動作が必要です。 「削除されるオブジェクトの削除時点でクラスタイプが不完全な場合」を「TUまたは配列へのポインタである場合」に置き換えて、標準の表現を少し整理することができます。 Uの、およびUの削除時点で、クラスタイプが不完全です...」

16
Nicol Bolas