Chamadas de destruidor repetidas e identificadores de rastreamento em C ++ / CLI

Estou brincando com o C ++ / CLI, usando a documentação do MSDN ePadrão ECMAe Visual C ++ Express 2010. O que me impressionou foi a seguinte saída do C ++:

Para as classes ref, tanto o finalizador quanto o destruidor devem ser escritos para que possam ser executados várias vezes e em objetos que não foram totalmente construídos.

Eu criei um pequeno exemplo:

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

No final do quarteirão em#1, a variável automáticaxmorre, eo destruidor é chamado (que por sua vez chama o finalizador explicitamente, como é o idioma usual). Está tudo bem e bem. Mas então eu apago o objeto novamente através da referênciar! A saída é esta:

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

Questões:

É um comportamento indefinido, ou é totalmente aceitável, chamardelete r conectados#2?

Se nós removermos a linha#2, isso importa quer ainda é um identificador de rastreamento para um objeto que (no sentido de C ++) não existe mais? É uma "alça pendurada"? A sua contagem de referência implica que haverá uma tentativa de eliminação dupla?

Eu sei que não háreal dupla eliminação, como a saída se torna isso:

Foo()
~Foo()
!Foo()

No entanto, não tenho certeza se é um acidente feliz ou se é um comportamento bem definido.

Em que outras circunstâncias pode odestruidor de um objeto gerenciado ser chamado mais de uma vez?

Seria correto inserirx.~Foo(); imediatamente antes ou depoisr = %x;?

Em outras palavras, os objetos gerenciados "vivem para sempre" e podem ter seus destrutores e seus finalizadores chamados repetidas vezes?

Em resposta à demanda de @ Hans por uma classe não-trivial, você também pode considerar esta versão (com o destruidor e o finalizador feitos de acordo com o requisito de múltiplas chamadas):

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