C++マニアック

C++,pair の使い方,usage of pair

pair は STL のヘッダ <utility> で定義されている、二つの要素のペアを入れる入れ物です。

  1. 二つの要素
  2. first と second の呪縛から逃れる
  3. STL 関連本

二つの要素 ページの先頭へ

pair は二つの要素を入れる入れ物です。それぞれの要素は C++ のオブジェクトで、その型はテンプレート引数で決まります。簡単な例を見て見ましょう。この場合、intfloat がテンプレート引数です。

#include <utility>
using namespace std;

int main() {
    pair<int, float> pairif;
    pairif.first  = 1;
    pairif.second = 2.3f;
}

pair は基本的には、次のように定義された struct PAIR に良く似ています。

struct PAIR {
    int   first;
    float second;
};

上記の構造体 PIAR と pair の差は、次のようなものです。

  1. pair には、コンストラクタがある。従って、pair<int, float>(1, 2.3) などと書ける。
  2. pair には、==、!=、<、>、<=、>=、 などの比較演算子が定義されている。
  3. pair には、コピーコンストラクタが定義されている。

上記のような差があるのですが、pair は、ほぼ first と second をメンバ変数として持つ構造体であるわけです。

first と second の呪縛から逃れる ページの先頭へ

pair は二つの要素を入れるには便利なのですが、メンバ変数の名前が first と second に固定されているため、少し使いにくいところがあります。例えば、次の例を見てください。山の名前と、高さ/県名を結び付けようとしています。

#include <string>
#include <utility>
using namespace std;

int main() {
    typedef pair<int, string> HEIGHTandPREFECTURE;               // 高さと県名
    pair<string, HEIGHTandPREFECTURE> mountname_height_pref;     // 山の名前と属性
    mountname_height_pref.first         = "富士山";
    mountname_height_pref.second.first  = 3776    ;
    mountname_height_pref.second.second = "静岡"  ;
}

ナオ : 富士山は、静岡だけに属するのじゃないわよね。
店主 : まぁまぁ、そういう突っ込みは無しということで。

上記の例のように、メンバ名が first と second に固定されているので、.second.first などがこれを見ただけでは何を意味するのか分からないという問題があります。

これを逃れるためには、C++マニアック的には、クラスメンバへのポインタを使って、次のようにします。プレフィックス mp はメンバへのポインタの意味で使っています。

#include <string>
#include <utility>
using namespace std;

int main() {
    // 変数型の typedef
    typedef pair<int, string>                 HEIGHTandPREFECTURE;
    typedef pair<string, HEIGHTandPREFECTURE> MOUNTNAME_ATTRIBUTE;
    // クラスメンバへのポインタの定義、ここは、料理で言えば仕込みの部分
    string              MOUNTNAME_ATTRIBUTE::*   mpstrMountName  = &MOUNTNAME_ATTRIBUTE::first ;
    HEIGHTandPREFECTURE MOUNTNAME_ATTRIBUTE::*   mpAttribute     = &MOUNTNAME_ATTRIBUTE::second;
    int                 HEIGHTandPREFECTURE::*   mpiHeight       = &HEIGHTandPREFECTURE::first ;
    string              HEIGHTandPREFECTURE::*   mpstrPrefecture = &HEIGHTandPREFECTURE::second;
    // オブジェクトの定義
    MOUNTNAME_ATTRIBUTE mountname_attribute;
    // メンバ変ポインタを使ってメンバにアクセスする。
    mountname_attribute.*mpstrMountName               = "富士山";
    mountname_attribute.*mpAttribute.*mpiHeight       = 3776    ;
    mountname_attribute.*mpAttribute.*mpstrPrefecture = "静岡"  ;
}

ナオ : ちょっと丸秘テクって感じね。
店主 : いやぁ、それほどでも。