12

このコードは明らかに機能しないため、違法であるべきだと確信していますが、C++0x FCD では許可されているようです。

class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X(); // according to the standard, the RHS is a placement-new expression
::operator delete(p); // definitely wrong, per litb's answer
delete p; // legal?  I hope not

おそらく、言語弁護士の1人が、標準がこれをどのように禁止しているかを説明できるでしょう.

配列形式もあります:

class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X[1]; // according to the standard, the RHS is a placement-new expression
::operator delete[](p); // definitely wrong, per litb's answer
delete [] p; // legal?  I hope not

これは私が見つけることができた最も近い質問です。

編集:関数への引数を制限する標準の言語が、delete-expressionvoid ::operator delete(void*)のオペランドに意味のある方法で適用されるという引数を購入していません。せいぜい、2 つの間の接続は非常に希薄であり、多くの式に渡すのに有効でないオペランドとして許可されます。例えば:deletedeletevoid ::operator delete(void*)

struct A
{
  virtual ~A() {}
};

struct B1 : virtual A {};

struct B2 : virtual A {};

struct B3 : virtual A {};

struct D : virtual B1, virtual B2, virtual B3 {};

struct E : virtual B3, virtual D {};

int main( void )
{
  B3* p = new E();
  void* raw = malloc(sizeof (D));
  B3* p2 = new (raw) D();

  ::operator delete(p); // definitely UB
  delete p; // definitely legal

  ::operator delete(p2); // definitely UB
  delete p2; // ???

  return 0;
}

void operator delete(void*)これが、ポインタを に渡すことができるかどうかが、同じポインタを のオペランドとして使用できるかどうかに関係がないことを示していることを願っていますdelete

4

4 に答える 4

7

[basic.stc.dynamic.deallocation]p3 の標準ルール

それ以外の場合、標準ライブラリで に提供される値は、標準ライブラリのまたはoperator delete(void*)の以前の呼び出しによって返された値の 1 つであり、標準ライブラリで に提供された値は、 の以前の呼び出しによって返された値の 1 つでなければなりません。または標準ライブラリのいずれか。operator new(size_t)operator new(size_t, const std::nothrow_t&)operator delete[](void*)operator new[](size_t)operator new[](size_t, const std::nothrow_t&)

上書きしていない限り、あなたdeleteの呼び出しはライブラリの を呼び出します。operator delete(void*)あなたはそれについて何も言わなかったので、私はあなたがそれについて何も言わなかったと思います。

上記の「shall」は、実際には「behavior is undefined if not」のようなものである必要があるため、[lib.res.on.arguments]p1 によるものではない、診断可能なルールであると誤解されません。これは n3225 によって修正されたため、もう間違えることはありません。

于 2010-12-11T18:59:30.950 に答える
3

pコンパイラーは、それが配置呼び出しから来ることを実際には気にしないので、オブジェクトでのnew発行を妨げることはありません。deleteこのように、あなたの例は「合法」と見なすことができます。

ただし、「配置delete」演算子を明示的に呼び出すことはできないため、これは機能しません。これらは、コンストラクタがスローした場合にのみ暗黙的に呼び出されるため、デストラクタを実行できます。

于 2010-12-11T18:39:55.747 に答える
2

もしあなたが(特定のコンパイラで)それでうまくいくかもしれないと思います

  1. new/deletemalloc/freeおよび
  2. 配置newは実際には、割り当てに関連付けられたデストラクタを追跡するために標準と同じメカニズムを使用するnewため、 への呼び出しがdelete正しいデストラクタを見つけることができます。

しかし、携帯性や安全性を確保する方法はありません。

于 2010-12-11T18:46:48.067 に答える
2

これは、標準のライブラリセクションで見つけました。これは、可能な限り直感に反する場所(IMO)です。

C++0x FCD (および n3225 ドラフト) セクション 18.6.1.3 [new.delete.placement]:

これらの関数は予約されています。C ++ プログラムは、標準 C ++ ライブラリ (17.6.3) のバージョンを置き換える関数を定義できません。(3.7.4) の規定は、演算子 new および演算子削除のこれらの予約配置形式には適用されません。

void*  operator  new(std::size_t  size,  void*  ptr)  throw();
void*  operator  new[](std::size_t  size,  void*  ptr)  throw();
void  operator  delete(void*  ptr,  void*)  throw();
void  operator  delete[](void*  ptr,  void*)  throw();

それでも、渡す正当な式を定義するセクションdeleteは、3.7.4 ではなく 5.3.5 です。

于 2010-12-11T18:47:34.503 に答える