Semântica da pilha do C++ para tipos de referência

Antes do Visual Studio 2005, uma instância de um tipo de referência só podia ser criada usando o operador new, o que criava o objeto no heap coletado de lixo. No entanto, agora você pode criar uma instância de um tipo de referência usando a mesma sintaxe para criar uma instância de um tipo nativo na pilha. Portanto, você não precisa usar ref new, gcnew para criar um objeto de um tipo de referência. E quando o objeto sai do escopo, o compilador chama o destruidor do objeto.

Comentários

Ao criar uma instância de um tipo de referência usando semântica de pilha, o compilador cria internamente a instância no heap coletado de lixo (usando gcnew).

Quando o tipo de assinatura ou o retorno de uma função incluir uma instância de um tipo de referência por valor, a função será marcada nos metadados como exigindo tratamento especial (com modreq). Atualmente, esse tratamento especial é fornecido apenas por clientes do Visual C++; outros idiomas atualmente não são compatíveis com funções de consumo ou dados que usam tipos de referência criados com semântica de pilha.

Um motivo para usar gcnew (alocação dinâmica) em vez de semântica de pilha seria se o tipo não tiver destruidor. Além disso, usar tipos de referência criados com semântica de pilha em assinaturas de função não seria possível se você quisesse que suas funções fossem consumidas por idiomas diferentes do Visual C++.

O compilador não gerará um construtor de cópia para um tipo de referência. Portanto, se você definir uma função que usa um tipo de referência por valor na assinatura, precisará definir um construtor de cópia para o tipo de referência. Um construtor de cópia para um tipo de referência tem uma assinatura do seguinte formulário: R(R%){}.

O compilador não gerará operador de atribuição padrão para um tipo de referência. Um operador de atribuição permite criar um objeto usando semântica de pilha e inicializá-lo com um objeto existente criado usando semântica de pilha. Um operador de atribuição para um tipo de referência tem uma assinatura do seguinte formulário: void operator=( R% ){}.

Se o destruidor do seu tipo liberar recursos críticos e você usar semântica de pilha para tipos de referência, não será necessário chamar explicitamente o destruidor (ou chamar delete). Para obter mais informações sobre destruidores em tipos de referência, confira Destruidores e finalizadores em Como definir e consumir classes e structs (C++/CLI).

Um operador de atribuição gerado pelo compilador seguirá as regras padrão do C++ com as seguintes adições:

  • Todos os membros de dados não estáticos cujo tipo é um identificador para um tipo de referência serão copiados superficialmente (tratados como um membro de dados não estático cujo tipo é um ponteiro).

  • Qualquer membro de dados não estático cujo tipo é um tipo de valor será copiado superficialmente.

  • Qualquer membro de dados não estático cujo tipo seja uma instância de um tipo de referência invocará uma chamada para o construtor de cópia do tipo de referência.

O compilador também oferece um operador unário % para converter uma instância de um tipo de referência criado usando semântica de pilha em seu tipo de identificador subjacente.

Os tipos de referência a seguir não estão disponíveis para uso com semântica de pilha:

Exemplo

Descrição

O exemplo de código a seguir mostra como declarar instâncias de tipos de referência com semântica de pilha, como funciona o operador de atribuição e o construtor de cópia e como inicializar uma referência de rastreamento com o tipo de referência criado usando semântica de pilha.

Código

// stack_semantics_for_reference_types.cpp
// compile with: /clr
ref class R {
public:
   int i;
   R(){}

   // assignment operator
   void operator=(R% r) {
      i = r.i;
   }

   // copy constructor
   R(R% r) : i(r.i) {}
};

void Test(R r) {}   // requires copy constructor

int main() {
   R r1;
   r1.i = 98;

   R r2(r1);   // requires copy constructor
   System::Console::WriteLine(r1.i);
   System::Console::WriteLine(r2.i);

   // use % unary operator to convert instance using stack semantics
   // to its underlying handle
   R ^ r3 = %r1;
   System::Console::WriteLine(r3->i);

   Test(r1);

   R r4;
   R r5;
   r5.i = 13;
   r4 = r5;   // requires a user-defined assignment operator
   System::Console::WriteLine(r4.i);

   // initialize tracking reference
   R % r6 = r4;
   System::Console::WriteLine(r6.i);
}

Saída

98
98
98
13
13

Confira também

Classes e Structs