program - stl c++ español
¿Qué es std:: pair? (10)
¿Para qué sirve std::pair
, por qué debería usarlo y qué beneficios ofrece boost::compressed_pair
?
¿Para qué es std :: pair, por qué debería usarlo?
Es tan simple como dos elementos de tupla. Se definió en la primera versión de STL en momentos en que los compiladores no soportaban ampliamente las plantillas y las técnicas de metaprogramación que se necesitarían para implementar un tipo de tupla más sofisticado como Boost.Tuple .
Es útil en muchas situaciones. std::pair
se usa en contenedores asociativos estándar. Se puede usar como una forma simple de rango std::pair<iterator, iterator>
- por lo que se pueden definir algoritmos que acepten un solo objeto que represente el rango en lugar de dos iteradores por separado. (Es una alternativa útil en muchas situaciones).
A veces hay dos piezas de información que siempre pasan juntos, ya sea como un parámetro, o un valor de retorno, o lo que sea. Claro, podrías escribir tu propio objeto, pero si solo son dos pequeños primitivos o similares, a veces un par parece estar bien.
A veces necesitas devolver 2 valores de una función, y a menudo es exagerado ir y crear una clase solo para eso.
std: pair es útil en esos casos.
Creo que boost: compressed_pair es capaz de optimizar los miembros de tamaño 0. Lo cual es más útil para la maquinaria de plantillas pesadas en las bibliotecas.
Si controlas los tipos directamente, es irrelevante.
Es una clase estándar para almacenar un par de valores. Es devuelto / usado por algunas funciones estándar, como std::map::insert
.
boost::compressed_pair
dice ser más eficiente: mira aquí
Información adicional: boost :: compressed_pair es útil cuando uno de los tipos de pares es una estructura vacía. Esto se usa a menudo en la metaprogramación de plantillas cuando los tipos del par se infieren mediante programación de otros tipos. En ese momento, generalmente tienes alguna forma de "estructura vacía".
Preferiría std :: pair para cualquier uso "normal", a menos que esté en metaprogramación de plantillas pesadas.
No es más que una estructura con dos variables bajo el capó.
De hecho, no me gusta usar std :: pair para los retornos de funciones. El lector del código debería saber qué es primero y qué segundo.
El compromiso que uso a veces es crear inmediatamente referencias constantes a .primero y segundo, al tiempo que nombro las referencias claramente.
Puede sonar extraño escuchar que compressed_pair se preocupa por un par de bytes. Pero en realidad puede ser importante cuando uno considera dónde se puede usar compressed_pair. Por ejemplo, consideremos este código:
boost::function<void(int)> f(boost::bind(&f, _1));
De repente, puede tener un gran impacto el uso de compressed_pair en casos como el anterior. ¿Qué podría pasar si boost :: bind almacena el puntero de función y el marcador de posición _1
como miembros en sí mismo o en un std::pair
en sí mismo? Bueno, podría hincharse hasta sizeof(&f) + sizeof(_1)
. Suponiendo que un puntero de función tiene 8 bytes (no es raro especialmente para las funciones de miembro) y el marcador de posición tiene un byte (ver respuesta de Logan por qué), entonces podríamos haber necesitado 9 bytes para el objeto de vinculación. Debido a la alineación, esto podría hincharse hasta 12 bytes en un sistema habitual de 32 bits.
boost::function
anima a sus implementaciones a aplicar una pequeña optimización de objetos. Eso significa que para pequeños funtores, un pequeño buffer directamente integrado en el objeto boost::function
se usa para almacenar el functor. Para functors más grandes, el montón tendría que ser usado usando un operador nuevo para obtener memoria. Alrededor de impulsar la versión 1.34 , se decidió adoptar esta optimización , porque se pensó que uno podría obtener beneficios de rendimiento muy grandes.
Ahora, un límite razonable (aunque quizás aún bastante pequeño) para un buffer tan pequeño sería de 8 bytes. Es decir, nuestro objeto de enlace bastante simple no cabría en el pequeño buffer, y requeriría que se almacene el operador nuevo. Si el objeto de vinculación anterior usaría un par compressed_pair
, en realidad puede reducir su tamaño a 8 bytes (o 4 bytes para el puntero de la función no miembro a menudo), porque el marcador de posición no es más que un objeto vacío.
Entonces, lo que puede parecer simplemente desperdiciar una gran cantidad de pensamiento por solo unos pocos bytes realmente puede tener un impacto significativo en el rendimiento.
std :: pair es útil para un par de las otras clases de contenedor en el STL.
Por ejemplo:
std::map<>
std::multimap<>
Ambos almacenan std :: pares de claves y valores.
Al usar el mapa y el multimapa, a menudo se accede a los elementos usando un puntero a un par.
std::pair
es un tipo de datos para agrupar dos valores juntos como un solo objeto. std::map
usa para claves, pares de valores.
Mientras aprende un std::pair , puede ver tuple
. Es como un pair
pero para agrupar un número arbitrario de valores. tuple
es parte de TR1 y muchos compiladores ya lo incluyen con sus implementaciones de Biblioteca estándar.
Además, consulte el Capítulo 1, "Tuplas", del libro Extensiones estándar de la biblioteca C ++: un tutorial y referencia de Pete Becker, ISBN-13: 9780321412997, para obtener una explicación detallada.
texto alternativo http://ak.buy.com/db_assets/prod_images/225/202452225.jpg
compressed_pair
usa algunos trucos de plantilla para ahorrar espacio. En C ++, un objeto (pequeño o) no puede tener la misma dirección que un objeto diferente.
Entonces, incluso si tienes
struct A { };
A
tamaño de A no será 0, porque entonces:
A a1;
A a2;
&a1 == &a2;
se mantendría, lo cual no está permitido.
Pero muchos compiladores harán lo que se llama la "optimización de clase base vacía":
struct A { };
struct B { int x; };
struct C : public A { int x; };
Aquí, está bien que B
y C
tengan el mismo tamaño, incluso si sizeof(A)
no puede ser cero.
Así que boost::compressed_pair
aprovecha esta optimización y, si es posible, heredará uno u otro de los tipos del par si está vacío.
Así que una std::pair
podría ser similar (he elidido un buen trato, ctors, etc.):
template<typename FirstType, typename SecondType>
struct pair {
FirstType first;
SecondType second;
};
Eso significa que si FirstType
o SecondType
es A
, su pair<A, int>
tiene que ser más grande que sizeof(int)
.
Pero si usa compressed_pair
, su código generado se verá similar a:
struct compressed_pair<A,int> : private A {
int second_;
A first() { return *this; }
int second() { return second_; }
};
Y compressed_pair<A,int>
solo será tan grande como sizeof (int).