programacion - ¿Por qué no puedo almacenar referencias en un mapa STL en C++?
setw c++ ejemplo (6)
De la manera en que lo entiendo, las referencias se implementan como indicadores bajo el capó. La razón por la que no puedes almacenarlos en un mapa es puramente semántica; tiene que inicializar una referencia cuando se crea y ya no puede cambiarla después. Esto no encaja con la forma en que funciona un mapa.
Yo entiendo que las referencias no son punteros, sino un alias de un objeto. Sin embargo, todavía no entiendo qué significa esto para mí como programador, es decir, ¿cuáles son las referencias bajo el capó?
Creo que la mejor manera de entender esto sería entender por qué no puedo almacenar una referencia en un mapa.
Sé que necesito dejar de pensar en referencias como suger sintáctico sobre punteros, simplemente no estoy seguro de cómo: /
Debería pensar en una referencia como ''const pointer para un objeto no const'':
MyObject& ~~ MyObject * const
Además, una referencia solo puede construirse como un alias de algo que existe (que no es necesario para un puntero, aunque es aconsejable aparte de NULL). Esto no garantiza que el objeto se mantendrá (y es posible que tenga un núcleo al acceder a un objeto a través de una referencia si ya no existe), considere este código:
// Falsifying a reference
MyObject& firstProblem = *((MyObject*)0);
firstProblem.do(); // undefined behavior
// Referencing something that exists no more
MyObject* anObject = new MyObject;
MyObject& secondProblem = *anObject;
delete anObject;
secondProblem.do(); // undefined behavior
Ahora, hay dos requisitos para un contenedor STL:
- T debe ser predeterminado construible (una referencia no lo es)
- T debe ser asignable (no puede restablecer una referencia, aunque puede asignarla a su árbitro)
Entonces, en contenedores STL, debe usar proxys o punteros.
Ahora, utilizar punteros podría ser problemático para el manejo de la memoria, por lo que es posible que deba:
- usa punteros inteligentes ( boost::shared_ptr por ejemplo)
- use un contenedor especializado: Boost Pointer Container Library
NO use auto_ptr , hay un problema con la asignación ya que modifica el operando de la mano derecha.
Espero eso ayude :)
Esta publicación explica cómo se implementan los punteros bajo el capó - http://www.codeproject.com/KB/cpp/References_in_c__.aspx , que también admite la respuesta de los sebastianos.
La diferencia importante aparte del azúcar sintáctico es que las referencias no se pueden cambiar para referirse a otro objeto distinto al que se inicializaron. Es por eso que no se pueden almacenar en mapas u otros contenedores, porque los contenedores necesitan poder modificar el tipo de elemento que contienen.
Como una ilustración de esto:
A anObject, anotherObject;
A *pointerToA=&anObject;
A &referenceToA=anObject;
// We can change pointerToA so that it points to a different object
pointerToA=&anotherObject;
// But it is not possible to change what referenceToA points to.
// The following code might look as if it does this... but in fact,
// it assigns anotherObject to whatever referenceToA is referring to.
referenceToA=anotherObject;
// Has the same effect as
// anObject=anotherObject;
Un contenedor que almacena una referencia tiene que inicializar todos sus elementos cuando se construye y, por lo tanto, es menos útil.
struct container
{
string& s_; // string reference
};
int main()
{
string s { "hello" };
//container {}; // error - object has an uninitialized reference member
container c { s }; // Ok
c.s_ = "bye";
cout << s; // prints bye
}
Además, una vez inicializado, el almacenamiento de los elementos del contenedor no se puede cambiar. s_ siempre se referirá al almacenamiento de s de arriba.
en realidad puedes usar referencias en un mapa. No lo recomiendo para grandes proyectos, ya que podría causar extraños errores de compilación, pero:
map<int, int&> no_prob;
int refered = 666;
no_prob.insert(std::pair<int, int&>(0, refered)); // works
no_prob[5] = 777; //wont compile!!!
//builds default for 5 then assings which is a problem
std::cout << no_prob[0] << std::endl; //still a problem
std::cout << no_prob.at(0) << std::endl; //works!!
para que pueda usar el mapa, pero será difícil garantizar que se utilizará correctamente, pero lo usé para códigos pequeños (generalmente competitivos)