Semántica de pila de C++ para los tipos de referencia
Antes de Visual Studio 2005, solo se podía crear una instancia de un tipo de referencia mediante el operador new
, que creó el objeto en el montón recopilado de elementos no utilizados. Sin embargo, ahora puede crear una instancia de un tipo de referencia con la misma sintaxis que usaría para crear una instancia de un tipo nativo en la pila. Por lo tanto, no es necesario usar ref new, gcnew para crear un objeto de un tipo de referencia. Y cuando el objeto sale del ámbito, el compilador llama al destructor del objeto.
Comentarios
Cuando se crea una instancia de un tipo de referencia mediante la semántica de pila, el compilador crea internamente la instancia en el montón recopilado de elementos no utilizados (mediante gcnew
).
Cuando la firma o el tipo de valor devuelto de una función incluye una instancia de un tipo de referencia por valor, la función se marcará en los metadatos como que requiere un control especial (con modreq). Actualmente, este control especial solo lo proporcionan los clientes de Visual C++; Otros lenguajes no admiten actualmente el consumo de funciones o datos que usan tipos de referencia creados con semántica de pila.
Una razón para usar gcnew
(asignación dinámica) en lugar de la semántica de pila sería si el tipo no tiene ningún destructor. Además, el uso de tipos de referencia creados con semántica de pila en firmas de función no sería posible si desea que los lenguajes diferentes de Visual C++ consuman las funciones.
El compilador no generará un constructor de copia para un tipo de referencia. Por lo tanto, si define una función que usa un tipo de referencia por valor en la firma, debe definir un constructor de copia para el tipo de referencia. Un constructor de copia para un tipo de referencia tiene una firma con el siguiente formato: R(R%){}
.
El compilador no generará un operador de asignación predeterminado para un tipo de referencia. Un operador de asignación permite crear un objeto mediante la semántica de pila e inicializarlo con un objeto existente creado mediante la semántica de pila. Un operador de asignación para un tipo de referencia tiene una firma con el formato siguiente: void operator=( R% ){}
.
Si el destructor de su tipo libera recursos críticos y usa la semántica de pila para los tipos de referencia, no es necesario llamar explícitamente al destructor (o llamar a delete
). Para obtener más información sobre los destructores en tipos de referencia, vea Destructores y finalizadores en Procedimiento: Definir y consumir clases y structs (C++/CLI).
Un operador de asignación generado por el compilador seguirá las reglas de C++ estándar habituales con las siguientes adiciones:
Los miembros de datos no estáticos cuyo tipo es un identificador de un tipo de referencia se copiarán de forma superficial (tratados como un miembro de datos no estáticos cuyo tipo es un puntero).
Cualquier miembro de datos no estático cuyo tipo sea un tipo de valor se copiará de forma superficial.
Cualquier miembro de datos no estático cuyo tipo sea una instancia de un tipo de referencia invocará una llamada al constructor de copia del tipo de referencia.
El compilador también proporciona un operador unario %
para convertir una instancia de un tipo de referencia creado mediante la semántica de pila en su tipo de identificador subyacente.
Los siguientes tipos de referencia no están disponibles para su uso con la semántica de pila:
Ejemplo
Descripción
En el ejemplo de código siguiente se muestra cómo declarar instancias de tipos de referencia con semántica de pila, cómo funciona el operador de asignación y el constructor de copia y cómo inicializar una referencia de seguimiento con el tipo de referencia creado mediante la semántica de pila.
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);
}
Resultados
98
98
98
13
13