Powtarzane wywołania destruktora i uchwyty śledzenia w C ++ / CLI

Bawię się C ++ / CLI, korzystając z dokumentacji MSDN iStandard ECMAi Visual C ++ Express 2010. Uderzyło mnie następujące odejście od C ++:

W przypadku klas ref, zarówno finalizator, jak i destruktor muszą być zapisane, aby mogły być wykonywane wielokrotnie i na obiektach, które nie zostały w pełni skonstruowane.

Wymyśliłem mały przykład:

#include <iostream>

ref struct Foo
{
    Foo()  { std::wcout << L"Foo()\n"; }
    ~Foo() { std::wcout << L"~Foo()\n"; this->!Foo(); }
    !Foo() { std::wcout << L"!Foo()\n"; }
};

int main()
{
    Foo ^ r;

    {
        Foo x;
        r = %x;
    }              // #1

    delete r;      // #2
}

Na końcu bloku w#1, zmienna automatycznaxumiera i wywoływany jest destruktor (który z kolei wywołuje finalizator jawnie, jak to zwykle bywa). To wszystko w porządku. Ale potem ponownie usuwam obiekt poprzez odniesienier! Wynik jest następujący:

Foo()
~Foo()
!Foo()
~Foo()
!Foo()

Pytania:

Czy jest to niezdefiniowane zachowanie, czy jest to całkowicie dopuszczalne, zadzwonićdelete r online#2?

Jeśli usuniemy linię#2, czy to ma znaczenier nadal jest uchwytem śledzenia obiektu, który (w sensie C ++) już nie istnieje? Czy to „zwisający uchwyt”? Czy liczenie odniesień pociąga za sobą próbę podwójnego usunięcia?

Wiem, że nie marzeczywisty podwójne usuwanie, ponieważ wyjście ma postać:

Foo()
~Foo()
!Foo()

Nie jestem jednak pewien, czy jest to szczęśliwy wypadek, czy też gwarantowane jest dobrze zdefiniowane zachowanie.

W jakich innych okolicznościach możeburzyciel obiektu zarządzanego można wywołać więcej niż raz?

Czy byłoby dobrze wstawićx.~Foo(); bezpośrednio przed lub por = %x;?

Innymi słowy, czy zarządzane obiekty „żyją wiecznie” i mogą wywoływać zarówno ich destruktory, jak i ich finalizatory?

W odpowiedzi na zapotrzebowanie @ Hansa na nietrywialną klasę, możesz również rozważyć tę wersję (z destruktorem i finalizatorem dostosowanym do wymagań wielokrotnego wywołania):

ref struct Foo
{
    Foo()
    : p(new int[10])
    , a(gcnew cli::array<int>(10))
    {
        std::wcout << L"Foo()\n";
    }

    ~Foo()
    {
        delete a;
        a = nullptr;

        std::wcout << L"~Foo()\n";
        this->!Foo();
    }

    !Foo()
    {
        delete [] p;
        p = nullptr;

        std::wcout << L"!Foo()\n";
    }

private:
    int             * p;
    cli::array<int> ^ a;
};

questionAnswers(2)

yourAnswerToTheQuestion