Pregunta

Qué es std::pair porque, ¿por qué debería usarlo y qué beneficios tiene? boost::compressed_pair ¿traer?

¿Fue útil?

Solución

std::pair es un tipo de datos para agrupar dos valores como un solo objeto. std::map lo usa para pares clave-valor.

mientras estás aprendiendo pair, podrías consultar tuple.Es como pair sino 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.

Consulte también el Capítulo 1, "Tuplas", del libro. Las extensiones de la biblioteca estándar de C++:Un tutorial y una referencia por Pete Becker, ISBN-13:9780321412997, para una explicación detallada.

alt text

Otros consejos

compressed_pair utiliza algunos trucos de plantilla para ahorrar espacio.En C++, un objeto (o pequeña) no puede tener la misma dirección que un objeto diferente.

Así que incluso si tienes

struct A { };

AEl tamaño de 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 "optimización de clase base vacía":

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

Aquí está bien B y C tener el mismo tamaño, incluso si sizeof(A) no puede ser cero.

Entonces boost::compressed_pair aprovecha esta optimización y, cuando sea posible, heredará de uno u otro de los tipos del par si está vacío.

entonces un std::pair podría verse así (he elidido mucho, ctores, etc.):

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

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

Pero si usas compressed_pair, su código generado será 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).

A veces es necesario devolver 2 valores de una función y, a menudo, es excesivo crear una clase solo para eso.

std:pair resulta útil en esos casos.

Creo que boost:compressed_pair puede optimizar los miembros de tamaño 0.Lo cual es especialmente útil para maquinaria de plantillas pesadas en bibliotecas.

Si controlas los tipos directamente, es irrelevante.

Puede parecer extraño escuchar que a comprimido_par le importan un par de bytes.Pero en realidad puede ser importante si se considera dónde se puede utilizar el par comprimido.Por ejemplo, consideremos este código:

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

De repente, puede tener un gran impacto usar comprimido_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 si mismo?Bueno, podría hincharse hasta sizeof(&f) + sizeof(_1).Suponiendo que un puntero de función tiene 8 bytes (algo común, especialmente para funciones miembro) y el marcador de posición tiene un byte (consulte la respuesta de Logan para saber por qué), entonces podríamos haber necesitado 9 bytes para el objeto de enlace.Debido a la alineación, esto podría aumentar hasta 12 bytes en un sistema habitual de 32 bits.

boost::function anima a sus implementaciones a aplicar una optimización de objetos pequeños.Eso significa que para pequeño functores, un pequeño buffer directamente incrustado en el boost::function El objeto se utiliza para almacenar el funtor.Para functores más grandes, el montón debería usarse mediante el operador new para obtener memoria.Alrededor del impulso versión 1.34, se decidió adoptar esta optimización, porque se pensó que se podían obtener grandes beneficios de rendimiento.

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

Por lo tanto, lo que puede parecer un desperdicio de pensamiento en unos pocos bytes, en realidad puede tener un impacto significativo en el rendimiento.

Es una clase estándar para almacenar un par de valores.Es devuelto/utilizado por algunas funciones estándar, como std::map::insert.

boost::compressed_pair afirma ser más eficiente: mira aquí

std::pair resulta útil para un par de otras clases de contenedores en STL.

Por ejemplo:

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

Ambos almacenan std::pares de claves y valores.

Cuando se utiliza el mapa y el mapa múltiple, a menudo se accede a los elementos mediante un puntero a un par.

Información adicional:boost::compressed_pair es útil cuando uno de los tipos del par es una estructura vacía.Esto se utiliza a menudo en la metaprogramación de plantillas cuando los tipos del par se infieren mediante programación a partir de otros tipos.Al final, normalmente tendrá algún tipo de "estructura vacía".

Preferiría std::pair para cualquier uso "normal", a menos que le guste la metaprogramación de plantillas intensas.

No es más que una estructura con dos variables bajo el capó.

De hecho, no me gusta usar std::pair para retornos de funciones.El lector del código tendría que saber qué es .first y qué es . second.

El compromiso que utilizo a veces es crear inmediatamente referencias constantes a .first y . second, mientras nombra las referencias claramente.

¿Para qué sirve std::pair? ¿Por qué debería usarlo?

Es una tupla igual de simple de dos elementos.Fue definido en la primera versión de STL en tiempos en los que los compiladores no admitían ampliamente plantillas y técnicas de metaprogramación que serían necesarias para implementar tipos más sofisticados de tuplas como Impulsar.Tupla.

Es útil en muchas situaciones. std::pair se utiliza en contenedores asociativos estándar.Se puede utilizar 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 se pasan juntas, ya sea como parámetro, valor de retorno o lo que sea.Claro, puedes escribir tu propio objeto, pero si son solo dos primitivas pequeñas o similares, a veces un par parece estar bien.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top