2011-11-13 5 views
5

contenedores STL tienen un reference y const_referencetypedef, que, en muchos casos que he visto (contenedores de bool siendo las únicas excepciones que se me ocurre), podrían ser trivialmente definido como¿Cómo se comporta exactamente el typedef de "referencia"?

typedef value_type& reference; 
typedef const value_type& const_reference; 

¿Qué es exactamente, sin embargo , son la semántica de estos tipos?

Por lo que entiendo, se supone que deben "comportarse como referencias al tipo de valor", pero ¿qué significa exactamente eso?

MSDN dice que reference es:

un tipo que proporciona una referencia a un elemento almacenado en un vector.

Pero, ¿qué significa esto exactamente? ¿Necesitan sobrecargar operadores específicos o tener un comportamiento específico? Si es así, ¿cuál es el comportamiento requerido?

+2

No creo que nadie esté entendiendo esta pregunta. Él pregunta qué tipo de comportamientos se denominan "referencias". No es el tipo de referencia C++ (como 'int &'). –

+0

Pensándolo bien, no creo entender ahora la Q. El tipo 'reference' o' const_reference' se comporta como una referencia normal o la referencia de referencia se comporta, ¿Por qué crees que debería comportarse de manera diferente? –

+0

@ Alls: La pregunta, literalmente, es: ¿Qué significa "se comporta como una referencia normal"? Es una oración vaga en sí misma, así que no sé qué condiciones tendría que cumplir antes de que mi tipo "se comporte como una referencia normal" (si estuviera haciendo un contenedor, por ejemplo). – Mehrdad

Respuesta

1

Lo que estamos pidiendo es "¿Puedo eliminar la referencia siempre una referencia? Y sí, se puede. Eso significa sin referencia reference puede hacer todo dereferenced value_type& puedo hacer todo lo que es value_type puede hacer. Si eso tiene sentido para usted.


no se puede sobrecargar los operadores de typedefs. typedefs tienen el mismo comportamiento que el tipo que están asignados. la razón por la que son typedef'd es para que sean menos engorrosos y proporcionar una "interfaz" común

Existe la razón reference es para evitar este tipo de cosas:

template<typename T> 
struct foo { 
    T& bar(); 

    typedef T& reference; 
    reference baz(); 
} 

foo<int> x; 
foo<int>::T& y = x.bar(); // error! returns a T& but I can't create one! 
foo<int>::reference z = x.baz(); // ok! 

También hace una interfaz más limpia y permite el uso de SFINAE:

template<typename T> 
typename T::reference second(T::reference& t) { return t.at(1); }; 

template<typename T> 
T& second(T& t) { return t[1]; }; 

std::vector v(10); 
foo f(10); // type with [] overloaded but no reference typedef 
second(x) = 5; // calls first def 
second(f) = 3; // calls second def 
+1

Lo siento, pero creo que te perdiste la pregunta. Estaba preguntando qué operadores/características debe soportar el tipo 'referencia' ... no si puedo o no sobrecargar lo que está allí ... Ya sé cómo funciona' typedef' y por qué introdujeron la abstracción, etc .; Solo me gustaría saber qué debe cumplir una 'referencia' según el estándar. – Mehrdad

+0

@Mehrdad 'reference' puede hacer todo lo que' value_type & 'puede hacer, lo cual es todo lo que' value_type' puede hacer. – Pubby

+1

Entonces, ¿de qué sirve usar 'referencia' cuando puedes usar' value_type & ', si son lo mismo? * Tiene * que ser un conjunto de condiciones necesarias y suficientes que 'referencia's debe satisfacer, que sin duda * no *" todo "... – Mehrdad

4

Creo que parte del problema proviene de la suposición de que los colocadores son útiles. Asignadores (al menos 11 ++ pre-C) were something of a late addition to the STL:

La gente quería contenedores independientes del modelo de memoria, que era algo excesivo porque el lenguaje no incluye los modelos de memoria. La gente quería que la biblioteca proporcionara algún mecanismo para abstraer los modelos de memoria. Las versiones anteriores de STL suponían que el tamaño del contenedor se puede expresar como un número entero del tipo size_t y que la distancia entre dos iteradores es del tipo ptrdiff_t. Y ahora nos dijeron, ¿por qué no abstraen de eso? Es una tarea difícil porque el lenguaje no se abstrae de eso; Las matrices C y C++ no están parametrizadas por estos tipos. Inventamos un mecanismo llamado "asignador", que encapsula información sobre el modelo de memoria. Eso causó graves consecuencias para cada componente de la biblioteca. Tal vez se pregunte qué tienen que ver los modelos de memoria con los algoritmos o las interfaces de contenedor. Si no puede usar cosas como size_t, tampoco puede usar cosas como T* debido a diferentes tipos de punteros (T*, T huge *, etc.). Entonces no puede usar referencias porque con diferentes modelos de memoria tiene diferentes tipos de referencia. Hubo tremendas ramificaciones en la biblioteca.

Desafortunadamente, they turned out to be substandard:

he inventado asignadores para hacer frente a la arquitectura de memoria de Intel. No son ideas tan malas en teoría, ya que tienen una capa que encapsula todo el material de la memoria: punteros, referencias, ptrdiff_t, size_t. Lamentablemente no pueden funcionar en la práctica. Por ejemplo,

vector<int, alloc1> a(...); 
vector<int, alloc2> b(...); 

no se puede decir ahora:

find(a.begin(), a.end(), b[1]); 

b[1] devuelve un alloc2::reference y no int&. Podría ser un error de tipo. Es necesario cambiar la forma en que el lenguaje central trata las referencias para hacer que los asignadores sean realmente útiles.

El typedef reference está destinado a devolver cualquiera que sea el equivalente de T& es para el asignador de que se trate. En las arquitecturas modernas, esto es probablemente T&. Sin embargo, se suponía que en algunas arquitecturas podría ser algo diferente (por ejemplo, un compilador dirigido a una arquitectura con punteros "cercanos" y "lejanos" podría necesitar una sintaxis especial para referencias "cercanas" y "lejanas"). Lamentablemente, esta brillante idea resultó ser menos que brillante. C++ 11 realiza cambios sustanciales en los asignadores, agregando asignadores de alcance, y el modelo de memoria. Tengo que admitir que no sé lo suficiente sobre los cambios de C++ 11 w.r.t. asignadores para decir si las cosas mejoran o empeoran.


En cuanto a los comentarios sobre la pregunta original, ya que el estándar en realidad no especifica cómo se deben implementar los contenedores (aunque la Norma no poner tantos requisitos sobre el comportamiento de los contenedores que puede ser que también. ..), cualquiera que sea el tipo que digas como reference debe tener los comportamientos de T& que alguien podría potencialmente confiar al implementar el contenedor: un objeto de tipo reference debe ser un alias transparente para el objeto original, asignándole debe cambiar el valor de el objeto original sin cortar, no hay necesidad de apoyar "volver a colocar" el reference, tomando la dirección del reference debe devolver la dirección del o objeto riginal, etc. De ser posible, debería ser T&; y el único caso que puedo imaginar donde no sería posible sería si estuviera asignando memoria que no podría manipular a través de punteros o referencias (por ejemplo, si la "memoria" estaba realmente en el disco, o si la memoria era en realidad asignado en una computadora separada y accesible a través de la red a través de llamadas RPC, etc.).

+0

Esto parece ser para STL, no STD. – Pubby

+1

"el único caso que puedo imaginar donde no sería posible sería si estuviera asignando memoria que no podría manipular a través de punteros o referencias" El estándar no le permite crear asignadores con eso de todos modos, porque no puede falsificar una referencia en C++. No puedes dar una referencia a objetos sematics. Es por eso que 'vector ' no es técnicamente un contenedor estándar. No sigue las reglas establecidas para instancias 'std :: vector'. Y no es así porque tienes que ser capaz de hacer '& vec [3]', lo cual es imposible con 'vector '. –

+0

@Pubby: el STL existía antes del estándar, y se modificó significativamente cuando se convirtió en parte del estándar (un cambio es que 2/3 de los algoritmos que Stepanov tenía originalmente se eliminaron). Según Stepanov, C++ se modificó de alguna manera cuando se adoptó el STL en el estándar (un cambio es la adición de funtores). Mis comentarios en el último párrafo de la respuesta son, creo, solo "correctos" para C++ - 98. C++ - 03 cambió las reglas de tal manera que las implementaciones pueden suponer que 'referencia 'es, de hecho,' T & '(como su respuesta lo indica, bastante claro). –

2

sacado de la norma:

enter image description here

También define reference como un typedef de value_type& que es un typedef de T

(respuesta Nueva como uno anterior fue enfoque diferente)

Cuestiones relacionadas