Compartilhar via


Semântica de 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 que você usaria para criar uma instância de um tipo nativo na memória da 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 destrutor 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 pelo coletor de lixo (usando gcnew).

Ao incluir uma instância de um tipo de referência por valor na assinatura ou no tipo de retorno de uma função, a função será marcada nos metadados como requerendo 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 executar funções ou consumir 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 destrutor. 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 como 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 da seguinte forma: 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.

Code

// 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 Estruturas