punteros - C#ref ¿es como un puntero en C/C++ o una referencia en C++?
punteros y matrices en c (5)
Estoy trabajando con la ref
y no entiendo claramente "¿Es como un puntero como en C / C ++ o es como una referencia en C ++?"
¿Por qué hice una pregunta tan débil como pensaste por un momento? Porque cuando leo libros de C # / .NET, msdn o hablo con desarrolladores de C # me estoy confundiendo por las siguientes razones:
- Los desarrolladores de C # sugieren NO usar
ref
en los argumentos de una función,eg ...(ref Type someObject)
no huele bien para ellos y sugieren...(Type someObject)
, realmente no entiendo claramente esta sugerencia . Las razones por las que escuché: es mejor trabajar con la copia del objeto, luego usarlo como un valor de retorno, no dañar la memoria con una referencia, etc. ... A menudo escucho tal explicación sobre los objetos de conexión DB. Como en mi experiencia simple de C / C ++, realmente no entiendo por qué usar una referencia es algo malo en C #? Yo controlo la vida del objeto y sus asignaciones / reasignaciones de memoria, etc ... Leí en libros y foros solo avisos deit''s bad, because you can corrupt your connection and cause a memory leak by a reference lose
, así que controlo la vida de objeto, puedo controlar manualmente lo que realmente quiero, entonces ¿por qué es malo? - Hoy en día, leer diferentes libros y hablar con diferentes personas, no entiendo claramente es
ref
un puntero (*
) o una referencia como en C ++ por&
? Como recuerdo, los punteros en C / C ++ siempre asignan un espacio con un tamaño de tipovoid*
- 4 bytes (el tamaño válido depende de la arquitectura), donde aloja una dirección a una estructura o variable. En C ++ pasando una referencia&
no hay nuevas asignaciones desde el montón / pila y trabajas con objetos ya definidos en el espacio de la memoria y no hay memoria secundaria para un puntero externamente como en el plano C. Entonces, ¿cuál es elref
en C # ? ¿.NET VM lo maneja como un puntero en C / C ++ simple y suGC
asigna espacio temporal para un puntero o funciona como referencia en C ++? ¿Laref
solo funciona con tipos administrados o para tipos de valores comobool, int
es mejor cambiar un códigounsafe
y pasar por un puntero en un estilo no administrado?
C # no tiene indicadores equitativos de C ++ y funciona en las referencias. ref
agrega un nivel de indirección. Hace que el argumento del tipo de valor sea una referencia y cuando se usa con el tipo de referencia lo convierte en una referencia a una referencia.
En resumen, permite llevar cualquier cambio a un tipo de valor fuera de una llamada a un método. Para el tipo de referencia, permite reemplazar la referencia original por un objeto totalmente diferente (y no solo cambiar el contenido del objeto). Se puede usar si desea reinicializar un objeto dentro de un método y la única forma de hacerlo es recrearlo. Aunque trataría de evitar ese enfoque.
Entonces, para responder a su pregunta, ref
sería como una referencia de C ++ a una referencia.
EDITAR
Lo anterior es cierto para código seguro. Los indicadores existen en C # inseguros y se usan en algunos casos muy específicos.
Cada referencia en C # es un puntero a los objetos en el montón como puntero en C ++ y la referencia de C # es igual que & en C ++
La razón por la que debe evitarse es que C # funcione en fundamental, que el método no debe cambiar el objeto pasado en el parámetro, porque para alguien que no tiene una fuente de método puede no saber si dará como resultado la pérdida de datos o no.
String a = " A ";
String b = a.Trim();
En este caso, estoy seguro de que a permanece intacto. En matemáticas, el cambio debe verse como una tarea que dice visualmente que b se cambia aquí por el consentimiento del programador.
a = a.Trim();
Este código se modificará a sí mismo y el codificador es consciente de ello.
Para preservar este método de cambio por la referencia de asignación debe evitarse a menos que sea un caso excepcional.
En C #, cuando ve algo que se refiere a un tipo de referencia (es decir, un tipo declarado con class
lugar de struct
), esencialmente siempre trata el objeto a través de un puntero. En C ++, todo es un tipo de valor por defecto, mientras que en C # todo es un tipo de referencia por defecto.
Cuando dice "ref" en la lista de parámetros de C #, lo que realmente está diciendo es más como un "puntero a un puntero". Está diciendo que, en el método, quiere reemplazar no el contenido del objeto, sino la referencia al objeto en sí, en el código que llama a su método.
A menos que esa sea su intención, entonces simplemente debe pasar el tipo de referencia directamente; en C #, pasar los tipos de referencia es barato (similar a pasar una referencia en C ++).
Aprender / comprender la diferencia entre los tipos de valores y los tipos de referencia en C #. Son un concepto importante en ese lenguaje y las cosas serán realmente confusas si intentas pensar utilizando el modelo de objetos C ++ en C # land.
Los siguientes son esencialmente programas semánticamente equivalentes:
#include <iostream>
class AClass
{
int anInteger;
public:
AClass(int integer)
: anInteger(integer)
{ }
int GetInteger() const
{
return anInteger;
}
void SetInteger(int toSet)
{
anInteger = toSet;
}
};
struct StaticFunctions
{
// C# doesn''t have free functions, so I''ll do similar in C++
// Note that in real code you''d use a free function for this.
static void FunctionTakingAReference(AClass *item)
{
item->SetInteger(4);
}
static void FunctionTakingAReferenceToAReference(AClass **item)
{
*item = new AClass(1729);
}
};
int main()
{
AClass* instanceOne = new AClass(6);
StaticFunctions::FunctionTakingAReference(instanceOne);
std::cout << instanceOne->GetInteger() << "/n";
AClass* instanceTwo;
StaticFunctions::FunctionTakingAReferenceToAReference(&instanceTwo);
// Note that operator& behaves similar to the C# keyword "ref" at the call site.
std::cout << instanceTwo->GetInteger() << "/n";
// (Of course in real C++ you''re using std::shared_ptr and std::unique_ptr instead,
// right? :) )
delete instanceOne;
delete instanceTwo;
}
Y para C #:
using System;
internal class AClass
{
public AClass(int integer)
: Integer(integer)
{ }
int Integer { get; set; }
}
internal static class StaticFunctions
{
public static void FunctionTakingAReference(AClass item)
{
item.Integer = 4;
}
public static void FunctionTakingAReferenceToAReference(ref AClass item)
{
item = new AClass(1729);
}
}
public static class Program
{
public static void main()
{
AClass instanceOne = new AClass(6);
StaticFunctions.FunctionTakingAReference(instanceOne);
Console.WriteLine(instanceOne.Integer);
AClass instanceTwo = new AClass(1234); // C# forces me to assign this before
// it can be passed. Use "out" instead of
// "ref" and that requirement goes away.
StaticFunctions.FunctionTakingAReferenceToAReference(ref instanceTwo);
Console.WriteLine(instanceTwo.Integer);
}
}
Esto parece una pesadilla de eliminación / evento. Si tengo un objeto para el que están registrados los eventos y lo paso a una función por referencia y esa referencia se reasigna, se debe llamar al desecho o la memoria se asignará hasta que se cierre el programa. Si se llama al desecho todo lo registrado en los objetos, ya no se registrarán los eventos y ya no se registrará todo para lo que está registrado. ¿Cómo alguien podría mantener esto en línea? Supongo que puedes comparar las direcciones de memoria y tratar de restaurar la cordura si no te vuelves loco.
Una ref
en C # es equivalente a una referencia de C ++:
- Su intención es pasar por referencia
- No hay referencias nulas
- No hay referencias no inicializadas
- No puedes volver a enlazar referencias
- Cuando deletreas la referencia, en realidad estás indicando la variable referida
Algunos códigos C ++:
void foo(int& x)
{
x = 42;
}
// ...
int answer = 0;
foo(answer);
Código equivalente de C #:
void foo(ref int x)
{
x = 42;
}
// ...
int answer = 0;
foo(ref answer);