5

私はこれが賢明ではないことを認識しており、そうすることを提案していませんが、次のことが実際に正式に違法であるかどうかについて興味があります。

#include <iostream>

struct X
{
    ~X()
    {
        std::cout << "~X()\n";
    }
};

int main()
{
    X *x = new X;
    //delete x;
    x->~X();
    ::operator delete(x);
    return 0;
}

delete x;デストラクタを呼び出してから呼び出すのと同じことは私の理解ですが::operator delete(x);、標準に従って手動で行うことは合法ですか?これは、新しい配置を使用する場合に有効なことですが、配置以外の場合はどうでしょうか。delete私の勘では、それぞれに対して実行する必要があるため(ではなくoperator delete) 、違法である可能性がありますがnew、確実に知りたいと思います。

4

5 に答える 5

3

これは標準に準拠していないと確信しています。(私が知っている)標準のどこにも、のオペランドがdelete p;割り当て解除関数に直接渡されるとは書かれていません。そのためdelete []、ほぼ確実に変更されに渡されません。

ただし、おそらくすべての実用的な実装で機能します。

確かに、グローバルな割り当て解除関数を明示的に呼び出すべきではありません。ユーザー定義の割り当て関数と割り当て解除関数がない例では問題ありませんが、一般的なケースでは問題ありません(実際、クラス固有の割り当て解除関数が存在する場合はそれを呼び出し、それ以外の場合はグローバル関数を呼び出すための構文はありますか? )。

また、一般的なケースでは、割り当て解除関数に渡されるポインターは、間違いなく削除のオペランドではありません。検討:

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 B1, virtual D {};

int main( void )
{
  B3* p = new D();
  p->~B3(); // should be ok, calling virtually
  operator delete(p); // definitely NOT OK

  return 0;
}
于 2010-12-12T20:42:22.723 に答える
3

このように行く場合は、交換する必要があります

X *x = new X;

X* x = static_cast<X*>(::operator new(sizeof(X)));

try { new(x) X; }
catch (...) { ::operator delete(x); throw; }

これは(私が間違っている場合は訂正してください)あなたの破壊アプローチと一致しているはずであり、機能的にはとほぼ同等newです。

于 2011-02-09T16:44:59.957 に答える
2

デストラクタを呼び出してメモリを解放しても、未定義の動作を呼び出さないと思います。

于 2010-12-12T15:18:07.777 に答える
1

@StuartGolodetz

回答し、コメントに返信する

グローバルなものが別の方法で呼び出されるようにするために実行できるテンプレートメタプログラミングがあるかもしれませんが、私はその専門家ではありません。可能であれば、それはおそらくある種のSFINAEのものだと思います。

構造体B{
    仮想〜B();
};

構造体D:B {
    演算子new(size_t);
    演算子削除(void *);
};

B *p=新しいD;

decltype(typeid(* p)):: operator delete(...); //架空のC++++

メタこれ!

于 2011-11-01T05:02:52.647 に答える
0

と思った

::operator delete(x);

と同じです

delete x;

deleteメソッドがXによってオーバーライドされていない場合は?

于 2010-12-12T20:28:52.970 に答える