Cuando hago esto:
std::vector<int> hello;
Todo funciona muy bien. Sin embargo, cuando lo convierto en un vector de referencias en su lugar:
std::vector<int &> hello;
Recibo errores horribles como
error C2528: 'puntero': el puntero a referencia es ilegal
Quiero poner un montón de referencias a estructuras en un vector, para no tener que entrometerme con punteros. ¿Por qué el vector está haciendo un berrinche sobre esto? ¿Es mi única opción usar un vector de punteros en su lugar?
Respuestas:
El tipo de componente de los contenedores, como los vectores, debe ser asignable . Las referencias no son asignables (solo puede inicializarlas una vez cuando se declaran, y no puede hacer que hagan referencia a otra cosa más adelante). Otros tipos no asignables tampoco están permitidos como componentes de contenedores, por ejemplo,
vector<const int>
no está permitido.fuente
Sí, puede, busque
std::reference_wrapper
, que imita una referencia pero es asignable y también puede ser "reubicado"fuente
get()
primero al intentar acceder a un método de una instancia de una clase en este contenedor? Por ejemplo,reference_wrapper<MyClass> my_ref(...); my_ref.get().doStuff();
no es muy referencia como..get()
. Lo que Timdiels quiere esoperator.
; Eche un vistazo a las últimas propuestas / discusiones sobre eso.Por su propia naturaleza, las referencias solo se pueden establecer en el momento en que se crean; es decir, las siguientes dos líneas tienen efectos muy diferentes:
Además, esto es ilegal:
Sin embargo, cuando crea un vector, no hay forma de asignar valores a sus elementos en la creación. Básicamente solo estás haciendo un montón del último ejemplo.
fuente
Ion Todirel ya mencionó una respuesta SÍ usando
std::reference_wrapper
. Desde C ++ 11 tenemos un mecanismo para recuperar objetosstd::vector
y eliminar la referencia mediante el usostd::remove_reference
. A continuación se muestra un ejemplo compilado usandog++
yclang
con la opción-std=c++11
y ejecutado con éxito.fuente
std::remove_reference<>
aquí. El puntostd::remove_reference<>
es permitirle escribir "el tipo T, pero sin ser una referencia si es uno". Entoncesstd::remove_reference<MyClass&>::type
es lo mismo que escribirMyClass
.for (MyClass obj3 : vec) std::cout << obj3.getval() << "\n";
(ofor (const MyClass& obj3: vec)
si declaragetval()
const, como debería).boost::ptr_vector<int>
trabajará.Editar: fue una sugerencia de uso
std::vector< boost::ref<int> >
, que no funcionará porque no se puede construir por defecto aboost::ref
.fuente
resize
.Es una falla en el lenguaje C ++. No puede tomar la dirección de una referencia, ya que intentar hacerlo daría lugar a la dirección del objeto al que se hace referencia y, por lo tanto, nunca puede obtener un puntero a una referencia.
std::vector
funciona con punteros a sus elementos, por lo que los valores que se almacenan deben poder señalarse. Tendrás que usar punteros en su lugar.fuente
sizeof
una referencia.TL; DR
Usar
std::reference_wrapper
así:Demo
Respuesta larga
Como sugiere el estándar , para un contenedor estándar que
X
contiene objetos de tipoT
,T
debe serErasable
deX
.Erasable
significa que la siguiente expresión está bien formada:A
es el tipo de asignador del contenedor,m
es la instancia del asignador yp
es un puntero de tipo*T
. Ver aquí para laErasable
definición.Por defecto,
std::allocator<T>
se utiliza como asignador de vectores. Con el asignador predeterminado, el requisito es equivalente a la validez dep->~T()
(Tenga en cuenta queT
es un tipo de referencia yp
apunta a una referencia). Sin embargo, el puntero a una referencia es ilegal , por lo tanto, la expresión no está bien formada.fuente
Como otros han mencionado, probablemente terminarás usando un vector de punteros en su lugar.
Sin embargo, ¡puede considerar usar un ptr_vector en su lugar!
fuente
Como sugieren los otros comentarios, está limitado a usar punteros. Pero si ayuda, aquí hay una técnica para evitar enfrentar directamente con punteros.
Puedes hacer algo como lo siguiente:
fuente
reinterpret_cast
no es necesario