Llamadas repetidas del destructor y controladores de seguimiento en C ++ / CLI

Estoy jugando con C ++ / CLI, usando la documentación de MSDN y laNorma ECMAy Visual C ++ Express 2010. Lo que me llamó la atención fue la siguiente desviación de C ++:

Para las clases ref, tanto el finalizador como el destructor deben escribirse para que puedan ejecutarse varias veces y en objetos que no se hayan construido completamente.

Yo inventé un pequeño ejemplo:

#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
}

Al final del bloque en#1, la variable automaticaxmuere, y se llama al destructor (que a su vez llama al finalizador explícitamente, como es el lenguaje habitual). Todo esto está bien y bien. Pero luego borro el objeto de nuevo a través de la referencia.r! La salida es esta:

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

Preguntas:

¿Es un comportamiento indefinido, o es totalmente aceptable, llamardelete r en linea#2?

Si quitamos la linea#2, importa quer ¿Sigue siendo un controlador de seguimiento para un objeto que (en el sentido de C ++) ya no existe? ¿Es un "mango colgando"? ¿Su conteo de referencias implica que habrá un intento de doble eliminación?

Sé que no hay unreal doble eliminación, como la salida se convierte en esto:

Foo()
~Foo()
!Foo()

Sin embargo, no estoy seguro de si se trata de un accidente feliz o si se garantiza que sea un comportamiento bien definido.

¿Bajo qué otras circunstancias puede elincinerador de basuras de un objeto gestionado ser llamado mas de una vez?

¿Estaría bien insertarx.~Foo(); inmediatamente antes o despuésr = %x;?

En otras palabras, ¿los objetos administrados "viven para siempre" y pueden tener sus destructores y sus finalizadores llamados una y otra vez?

En respuesta a la demanda de @ Hans de una clase no trivial, también puede considerar esta versión (con el destructor y el finalizador hechos para cumplir con el requisito de llamadas múltiples):

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;
};

Respuestas a la pregunta(2)

Su respuesta a la pregunta