una - ¿Estoy inicializando correctamente mis variables de referencia de C++?
tipos de variables en c++ pdf (6)
He intentado buscar en Google este problema y no encuentro nada que considere relevante. Así que debo estar buscando lo incorrecto; Sin embargo, agradecería algún consejo ...
Foobar &foobar = *new Foobar(someArg, anotherArg);
¿Soy yo o eso me parece mal?
Entiendo que la new
palabra clave está diseñada para usarse con punteros (como tales):
Foobar *foobar = new Foobar(someArg, anotherArg);
Pero, ¿qué sucede si no necesita un puntero en esa instancia y desea utilizar una referencia en su lugar? O, es el caso de que no es necesario inicializarlo explícitamente (como las variables locales); y si este es el caso, ¿qué pasa si quiero inicializar con parámetros?
Lo siguiente no funciona (a menos que esté haciendo algo mal):
// the last argument is of type: int
Foobar &foobar(someArg, anotherArg);
... da el error del compilador:
lista de expresiones de inicialización tratadas como expresiones compuestas inicialización no válida de referencia no constante de tipo ''Foobar &'' a partir de un temporal de tipo ''int''
Y también esto no parece funcionar:
Foobar &foobar = Foobar(someArg, anotherArg);
... da el error del compilador:
error: inicialización no válida de referencia no constante de tipo ''Foobar &'' desde un temporal de tipo ''Foobar''
Actualización 1:
Tenga en cuenta que estoy devolviendo este valor, por lo que no quiero usar una variable local; Quiero usar un valor en el montón, no la pila:
Foobar &helloWorld()
{
Foobar &foobar = *new Foobar(someArg, anotherArg);
foobar.HelloWorld();
return foobar;
}
¿Debería usar punteros en su lugar o esto es completamente válido?
¿Por qué crees que necesitas utilizar nuevos y referencias en absoluto? Por qué no:
Foobar foobar(someArg, anotherArg);
Para su función - devuelva un valor:
Foobar helloWorld()
{
Foobar foobar(someArg, anotherArg);
foobar.HelloWorld();
return foobar;
}
o un puntero:
Foobar * helloWorld()
{
Foobar * foobar = new Foobar(someArg, anotherArg);
foobar->HelloWorld();
return foobar;
}
Si hace esto, la persona que llama es responsable de eliminar el objeto asignado en algún momento.
El retorno de una función que no es miembro es un lugar donde las referencias normalmente no se pueden usar con sensatez, ya que la cosa a la que le gustaría referirse generalmente ya no existe.
Estás escribiendo bien. Pero tenga en cuenta que es raro liberar al ptr haciendo eliminar y refVar; (podría confundirse con una variable que no fue creada por una nueva).
Debería revisar GotW para conocer las buenas prácticas de http://www.gotw.ca/gotw/ No recuerdo de qué lección fue (hubo más de una), pero leerlo es más valioso de lo que cualquiera se da cuenta (los gotchas serán menos de una sorpresa)
Debes intentar escribir código que NUNCA use punteros. Lo hago pero una vez me quedé atascado cuando necesitaba un contenedor de BaseObj. No había forma de trabajar alrededor de eso. Normalmente, usé los contenedores STL y tengo la mayoría de las variables con vida en la pila {MyClass myVar; ...} o como miembro y pásalo según sea necesario.
Es fácil de eliminar los punteros una vez que comience a pasar referencias en lugar de punteros y use contenedores stl en lugar de nuevos. Tenga en cuenta que nunca uso auto_ptr. El vector, la cadena, el deque, la lista y el mapa deben hacer la mayor parte de lo que necesita. Hay otros contenedores.
Las referencias en C ++ realmente no son tan fuertes como la gente espera, creo que la confusión proviene de personas que están acostumbradas a lenguajes como Java y C # que no tienen punteros y tienen referencias que se pueden reasignar y usar.
Una referencia en C ++ generalmente se usa mejor como un alias para una variable, por lo que puede simplificar cosas como el paso de parámetros y los valores de retorno. Hay muy pocas situaciones en las que trataría de adquirir una referencia de la forma en que lo está haciendo en la primera línea. Por lo general, no necesitas hacer lo que parece que estás tratando de hacer :)
La segunda línea es correcta, por supuesto, y puedes hacer algo como return * foobar desde una función que devuelve una referencia.
No, lo tienes. Un foo & "apunta al" objeto real, por lo que si realmente desea una referencia foo, debe desreferir el puntero foo.
Sin embargo, @Neil tiene un punto: sintácticamente, así es como obtienes lo que quieres, pero ¿por qué lo quieres?
Recomiendo usar un puntero inteligente. Debe administrar la propiedad y una referencia no lo hará por usted. De hecho, no será claro para la persona que llama que existe algún problema de propiedad. Como Scott Langham mencionó en un comentario, std :: auto_ptr funcionaría. El uso de shared_ptr de Boost o TR1 podría ser una mejor idea.
boost::shared_ptr<Foobar> helloWorld()
{
boost::shared_ptr<Foobar> foobar(new Foobar(someArg, anotherArg));
foobar->HelloWorld();
return foobar;
}
Sí, eso es maloliente!
Si ''nuevo'' algo, asignarlo a un puntero (o tipo de puntero inteligente), ya que tendrá que eliminarse de nuevo para evitar una pérdida de memoria. Las referencias no se consideran convencionalmente como cosas que necesitas eliminar de nuevo, por lo que si alguien ve ese código (asignando un objeto nuevo a una referencia), puede confundirlo.
Tu puedes hacer...
const Foobar &foobar = Foobar(someArg, anotherArg);
... si realmente quieres una referencia. Tenga en cuenta que una vez que el foobar quede fuera del alcance, el objeto temporal al que hace referencia morirá. Pero, no tiene mucho sentido por escrito que cuando pueda escribir directamente:
Foobar foobar(someArg, anotherArg);
Probablemente no necesite realmente una referencia ... generalmente se usan (pero no exclusivamente) para los tipos de argumentos de método. Esto es para que pueda pasar algo que parece un objeto, pero que solo tiene el tamaño de un puntero, y que el método puede modificar. La referencia se introdujo principalmente para permitirle escribir un constructor de copia (¡no lo explicaré aquí!).