2008-09-18 16 views

Respuesta

34

std::pair es un tipo de datos para agrupar dos valores juntos como un solo objeto. std::map lo usa para llaves, pares de valores.

Mientras está aprendiendo pair, puede consultar tuple. Es como 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, la caja Capítulo 1, "tuplas", del libro Las extensiones ++ biblioteca estándar C: A Tutorial y Referencia por Pete Becker, ISBN-13: 9780321412997, para una explicación detallada.

alt text http://ak.buy.com/db_assets/prod_images/225/202452225.jpg

+1

Además, las bibliotecas de impulso tienen una buena implementación de tuplas, si su compilador aún no es compatible con TR1. –

11

A veces tiene que devolver 2 valores de una función, y a menudo es exagerado ir y crear una clase solo para eso.

std: pair es muy útil en esos casos.

Creo que boost: compressed_pair es capaz de optimizar los miembros de tamaño 0. Que es principalmente útil para la maquinaria de plantillas pesadas en las bibliotecas.

Si controla los tipos directamente, es irrelevante.

+3

Y puede usar boost :: tie para escribir código que se aproxime a "a, b = func();". En lugar de instanciar explícitamente un par, escriba: "boost :: tie (a, b) = func();". – rlerallut

3

std :: pair es útil para un par de las otras clases de contenedor en el STL.

Por ejemplo:

std::map<> 
std::multimap<> 

Tanto tienda std :: pares de claves y valores.

Al usar el mapa y multimapa, a menudo se accede a los elementos usando un puntero a un par.

3

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: see here

1

A veces hay dos piezas de información que acaba de pasar alrededor siempre 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.

3

Otros detalles: boost :: compressed_pair es útil cuando uno de los tipos de la pareja 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 la metaprogramación de plantillas pesadas.

3

No es más que una estructura con dos variables debajo del capó.

Realmente no me gusta usar std :: pair para la función devuelve. El lector del código debería saber qué.primero es y qué. segundo es.

El compromiso que uso a veces es crear inmediatamente referencias constantes a .first y .second, al tiempo que nombro las referencias claramente.

+1

Estoy de acuerdo con usted acerca de la convención de nomenclatura. Hace el mantenimiento más difícil. – Adam

80

compressed_pair utiliza 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.

Así que incluso si usted tiene

tamaño
struct A { }; 

A 's no va a ser 0, ya continuación:

A a1; 
A a2; 
&a1 == &a2; 

sostendría, que no está permitido.

Pero muchos compiladores va a hacer lo que se llama la "optimización clase base vacía":

struct A { }; 
struct B { int x; }; 
struct C : public A { int x; }; 

En este caso, está muy bien para B y C que tienen el mismo tamaño, incluso si no puede sizeof(A) ser cero

Así boost::compressed_pair se aprovecha de esta optimización y será, siempre que sea posible, heredar de uno u otro de los tipos en el par si está vacío.

Así que un std::pair podría parecerse a (He elididas un buen trato, ctors etc.):

template<typename FirstType, typename SecondType> 
struct pair { 
    FirstType first; 
    SecondType second; 
}; 

Eso significa que si bien FirstType o SecondType es A, su pair<A, int> tiene que ser más grande que sizeof(int).

Pero si utiliza 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> sólo será tan grande como sizeof (int).

+3

buena respuesta compañero :) –

+0

Estaba leyendo esto pensando, maldita sea la respuesta de este tipo está pensada y completa, y luego se dio cuenta de quién era, y ni siquiera se sorprendió un poco! Hola Logan! –

+0

¿Me he perdido algo importante? por favor dime, ¿quién es este tipo? también quiero felicitarlo :) –

11

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 vamos a considerar este código:

boost::function<void(int)> f(boost::bind(&f, _1)); 

repente puede tener un gran impacto a utilizar 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 fomenta sus implementaciones para aplicar una pequeña optimización de objetos. Eso significa que para pequeños funtores, se usa un pequeño búfer directamente incrustado en el objeto boost::function 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 version 1.34, se decidió adoptar this optimization, porque se pensó que uno podría obtener algunos beneficios de rendimiento muy grandes.

Ahora, un límite razonable (aunque quizás bastante pequeño) para un búfer tan pequeño sería de 8 bytes. Es decir, nuestro objeto de vinculación bastante simple sería no encajar en el pequeño buffer, y requeriría que se almacene el operador nuevo. Si el objeto de vinculación anterior usaría un compressed_pair, en realidad puede reducir su tamaño a 8 bytes (o 4 bytes para el puntero de función no miembro a menudo), porque el marcador de posición no es más que un objeto vacío.

Por lo tanto, lo que puede parecer simplemente desperdiciar una gran cantidad de pensamiento por solo unos pocos bytes en realidad puede tener un impacto significativo en el rendimiento.

2

¿Qué es std :: pair for, why would I use it?

Es tan simple dos elementos 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).

Cuestiones relacionadas