web-dev-qa-db-fra.com

Qu'est-ce que std :: pair?

Quel est std::pair car, pourquoi devrais-je l'utiliser et quels sont les avantages boost::compressed_pair apporter?

42
Anthony

std::pair est un type de données pour regrouper deux valeurs en un seul objet. std::map l'utilise pour les paires clé/valeur.

Pendant que vous apprenez pair , vous pouvez consulter Tuple . C'est comme pair mais pour regrouper un nombre arbitraire de valeurs. Tuple fait partie de TR1 et de nombreux compilateurs l'incluent déjà avec leurs implémentations de bibliothèque standard.

Consultez également le chapitre 1, "Tuples", du livre Les extensions de bibliothèque standard C++: un didacticiel et une référence par Pete Becker, ISBN-13: 9780321412997 , pour une explication approfondie.

alt text

35
jwfearn

compressed_pair Utilise une astuce de modèle pour économiser de l'espace. En C++, un objet (petit o) ne peut pas avoir la même adresse qu'un objet différent.

Donc même si vous avez

struct A { };

La taille de A ne sera pas 0, car alors:

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

tiendrait, ce qui n'est pas autorisé.

Mais de nombreux compilateurs feront ce qu'on appelle "l'optimisation de la classe de base vide":

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

Ici, il est correct que B et C aient la même taille, même si sizeof(A) ne peut pas être nul.

Ainsi boost::compressed_pair Profite de cette optimisation et héritera, si possible, de l'un ou l'autre des types de la paire s'il est vide.

Donc un std::pair Pourrait ressembler à (j'ai élidé beaucoup, ctors etc.):

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

Cela signifie que si FirstType ou SecondType est A, votre pair<A, int> Doit être plus grand que sizeof(int).

Mais si vous utilisez compressed_pair, Son code généré ressemblera à:

 struct compressed_pair<A,int> : private A {
    int second_;
    A first() { return *this; }
    int second() { return second_; }
 };

Et compressed_pair<A,int> Sera seulement aussi grand que sizeof (int).

81
Logan Capaldo

Il peut sembler étrange d'entendre que compressé_pair se soucie de quelques octets. Mais cela peut en fait être important lorsque l'on considère où compress_pair peut être utilisé. Par exemple, considérons ce code:

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

Il peut soudainement avoir un grand impact pour utiliser compressé_pair dans les cas comme ci-dessus. Que pourrait-il arriver si boost :: bind stocke le pointeur de fonction et l'espace réservé _1 En tant que membres en soi ou dans un std::pair En lui-même? Eh bien, cela pourrait gonfler jusqu'à sizeof(&f) + sizeof(_1). En supposant qu'un pointeur de fonction a 8 octets (ce qui n'est pas rare en particulier pour les fonctions membres) et l'espace réservé a un octet (voir la réponse de Logan pour savoir pourquoi), alors nous aurions pu avoir besoin de 9 octets pour l'objet de liaison. En raison de l'alignement, cela pourrait gonfler jusqu'à 12 octets sur un système 32 bits habituel.

boost::function Encourage ses implémentations à appliquer une optimisation de petit objet. Cela signifie que pour les petits foncteurs, un petit tampon directement incorporé dans l'objet boost::function Est utilisé pour stocker le foncteur. Pour les plus grands foncteurs, le tas devrait être utilisé en utilisant l'opérateur new pour obtenir de la mémoire. Autour de boost version 1.34 , il a été décidé d'adopter cette optimisation , car on pensait que l'on pourrait gagner de très grands avantages en termes de performances.

Maintenant, une limite raisonnable (mais peut-être encore assez petite) pour un si petit tampon serait de 8 octets. Autrement dit, notre objet bind assez simple ne pas rentrerait dans le petit tampon, et nécessiterait que l'opérateur new soit stocké. Si l'objet de liaison ci-dessus utilise un compressed_pair, Il peut en fait réduire sa taille à 8 octets (ou 4 octets pour le pointeur de fonction non membre souvent), car l'espace réservé n'est rien de plus qu'un objet vide.

Donc, ce qui peut sembler gaspiller beaucoup de réflexion pour seulement quelques octets peut avoir un impact significatif sur les performances.

11

Vous devez parfois renvoyer 2 valeurs à partir d'une fonction, et il est souvent exagéré d'aller créer une classe juste pour cela.

std: la paire est pratique dans ces cas.

Je pense que boost: compress_pair est capable d'optimiser les membres de taille 0. Ce qui est surtout utile pour les machines de gabarit lourdes dans les bibliothèques.

Si vous contrôlez directement les types, ce n'est pas pertinent.

11
David Pierre

Informations supplémentaires: boost :: compress_pair est utile lorsque l'un des types de la paire est une structure vide. Ceci est souvent utilisé dans la métaprogrammation de modèle lorsque les types de la paire sont déduits par programmation d'autres types. À la fin, vous avez généralement une certaine forme de "structure vide".

Je préférerais std :: pair pour toute utilisation "normale", sauf si vous êtes dans la métaprogrammation de modèles lourds.

3
rlerallut

std :: pair est pratique pour quelques autres classes de conteneurs dans la STL.

Par exemple:

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

Les deux stockent std :: paires de clés et valeurs.

Lorsque vous utilisez la carte et le multimap, vous accédez souvent aux éléments à l'aide d'un pointeur sur une paire.

3
John Mulder

C'est une classe standard pour stocker une paire de valeurs. Il est retourné/utilisé par certaines fonctions standard, comme std::map::insert.

boost::compressed_pair prétend être plus efficace: voir ici

3
user17481

Ce n'est rien d'autre qu'une structure avec deux variables sous le capot.

En fait, je n'aime pas utiliser std :: pair pour les retours de fonctions. Le lecteur du code devrait savoir ce qu'est le premier et quel est le second.

Le compromis que j'utilise parfois est de créer immédiatement des références constantes à .first et .second, tout en nommant clairement les références.

3
Andrei Taranchenko

À quoi sert std :: pair, pourquoi devrais-je l'utiliser?

C'est tout aussi simple deux éléments Tuple. Il a été défini dans la première version de STL à une époque où les compilateurs ne prenaient pas largement en charge les modèles et les techniques de métaprogrammation qui seraient nécessaires pour implémenter un type de Tuple plus sophistiqué comme - Boost.Tuple .

Il est utile dans de nombreuses situations. std::pair est utilisé dans les conteneurs associatifs standard. Il peut être utilisé comme une simple forme de plage std::pair<iterator, iterator> - on peut donc définir des algorithmes acceptant un seul objet représentant une plage au lieu de deux itérateurs séparément. (C'est une alternative utile dans de nombreuses situations.)

2
mloskot

Parfois, il y a deux informations que vous passez simplement toujours ensemble, que ce soit en tant que paramètre, ou valeur de retour, ou autre chose. Bien sûr, vous pouvez écrire votre propre objet, mais s'il ne s'agit que de deux petites primitives ou similaires, parfois une paire semble très bien.

1
Aaron