質問
とは std::pair
なぜそれを使用するのか、そしてどのようなメリットがあるのか boost::compressed_pair
持ってくる?
解決
std::pair
2 つの値を 1 つのオブジェクトとしてグループ化するためのデータ型です。 std::map
キーと値のペアに使用します。
学習している間 pair
, 、チェックしてみてもいいかもしれません tuple
. 。まるで pair
ただし、任意の数の値をグループ化する場合に使用します。 tuple
は TR1 の一部であり、多くのコンパイラは標準ライブラリ実装にすでにこれを含んでいます。
この本の第 1 章「タプル」もチェックしてください。 C++ 標準ライブラリ拡張:チュートリアルとリファレンス ピート・ベッカー著、ISBN-13:9780321412997 で徹底解説します。
他のヒント
compressed_pair
スペースを節約するためにテンプレートのトリックを使用します。C++ では、オブジェクト (小さな o) が別のオブジェクトと同じアドレスを持つことはできません。
したがって、たとえ持っていたとしても
struct A { };
A
のサイズは 0 にはなりません。その理由は次のとおりです。
A a1;
A a2;
&a1 == &a2;
が成立しますが、これは許可されていません。
しかし 多くのコンパイラは、いわゆる「空の基底クラスの最適化」を実行します。
struct A { };
struct B { int x; };
struct C : public A { int x; };
ここで、大丈夫です B
そして C
たとえ同じサイズであっても、 sizeof(A)
ゼロになることはできません。
それで boost::compressed_pair
はこの最適化を利用し、空の場合は可能な限りペア内の一方または他方の型を継承します。
それで、 std::pair
次のようになります (CTOR など、かなりの部分を省略しました):
template<typename FirstType, typename SecondType>
struct pair {
FirstType first;
SecondType second;
};
つまり、どちらかが FirstType
または SecondType
は A
, 、 あなたの pair<A, int>
より大きくなければなりません sizeof(int)
.
しかし、使用する場合は、 compressed_pair
, 、生成されたコードは次のようになります。
struct compressed_pair<A,int> : private A {
int second_;
A first() { return *this; }
int second() { return second_; }
};
そして compressed_pair<A,int>
sizeof(int) と同じ大きさにしかなりません。
関数から 2 つの値を返す必要がある場合がありますが、そのためだけにクラスを作成するのはやりすぎです。
std:pair はそのような場合に便利です。
boost:compressed_pair はサイズ 0 のメンバーを最適化できると思います。これは、ライブラリ内の重いテンプレート機構に主に役立ちます。
型を直接制御する場合、それは無関係です。
COMPLEX_PAIR が数バイトを考慮すると聞くと奇妙に聞こえるかもしれません。しかし、実際には、compressed_pair をどこで使用できるかを考えると重要になることがあります。たとえば、次のコードを考えてみましょう。
boost::function<void(int)> f(boost::bind(&f, _1));
上記のような場合に、compressed_pair を使用すると、突然大きな影響が生じる可能性があります。boost::bind が関数ポインタとプレースホルダを格納するとどうなるか _1
それ自体のメンバーとして、または std::pair
それ自体で?まあ、それは膨らむ可能性があります sizeof(&f) + sizeof(_1)
. 。関数ポインターが 8 バイト (特にメンバー関数では珍しいことではありません) で、プレースホルダーが 1 バイト (理由については Logan の回答を参照) だと仮定すると、バインド オブジェクトには 9 バイトが必要になる可能性があります。アライメントにより、通常の 32 ビット システムでは最大 12 バイトまで肥大化する可能性があります。
boost::function
実装では小さなオブジェクトの最適化を適用することが推奨されます。つまり、 小さい ファンクター、直接埋め込まれた小さなバッファー boost::function
オブジェクトはファンクターを格納するために使用されます。より大きなファンクターの場合、演算子 new を使用してヒープを使用してメモリを取得する必要があります。ブースト周り バージョン1.34, を採用することが決定しました。 この最適化, 非常に大きなパフォーマンス上の利点が得られると考えられたからです。
さて、このような小さなバッファの妥当な (それでも、おそらくかなり小さい) 制限は 8 バイトです。つまり、非常に単純なバインド オブジェクトは次のようになります。 ない 小さなバッファに収まるため、演算子 new を格納する必要があります。上記のバインド オブジェクトが compressed_pair
, 、プレースホルダーは空のオブジェクトにすぎないため、実際にはそのサイズを 8 バイト (非メンバー関数ポインターの場合は 4 バイト) に減らすことができます。
したがって、ほんの数バイトのために多くの考えを無駄にしているように見えるかもしれませんが、実際にはパフォーマンスに重大な影響を与える可能性があります。
値のペアを格納するための標準クラスです。これは、次のようないくつかの標準関数によって返されたり、使用されたりします。 std::map::insert
.
boost::compressed_pair
より効率的であると主張します。 ここを参照してください
std::pair は、STL 内の他のいくつかのコンテナ クラスで便利です。
例えば:
std::map<>
std::multimap<>
どちらもキーと値の std::pair を保存します。
マップとマルチマップを使用する場合、多くの場合、ペアへのポインターを使用して要素にアクセスします。
追加情報:boost::compressed_pair は、ペアの型の 1 つが空の構造体である場合に便利です。これは、ペアの型が他の型からプログラム的に推論される場合に、テンプレートのメタプログラミングでよく使用されます。最終的には、通常、何らかの形式の「空の構造体」が得られます。
大量のテンプレートメタプログラミングに興味がない限り、「通常の」用途には std::pair を使用することをお勧めします。
これは、内部に 2 つの変数を備えた構造にすぎません。
私は実際のところ、関数の戻り値に std::pair を使用するのが嫌いです。コードを読む人は、.first が何であるか、.second が何であるかを知っている必要があります。
私が時々使用する妥協策は、参照に明確な名前を付けながら、.first と .second への定数参照をすぐに作成することです。
std::pair は何のために使用するのでしょうか?
これも単純な 2 つの要素のタプルです。の最初のバージョンで定義されました STL コンパイラが、次のようなより洗練されたタイプのタプルを実装するために必要となるテンプレートやメタプログラミング手法を広くサポートしていなかった時代。 ブーストタプル.
多くの場面で役立ちます。 std::pair
標準の連想コンテナで使用されます。単純な範囲の形式として使用できます std::pair<iterator, iterator>
- そのため、2 つの反復子を別々に扱う代わりに、範囲を表す単一のオブジェクトを受け入れるアルゴリズムを定義できます。(これは多くの状況で便利な代替手段です。)
パラメーターとして、戻り値として、またはその他として、常に一緒に渡す 2 つの情報が存在することがあります。確かに、独自のオブジェクトを作成することもできますが、それが 2 つの小さなプリミティブなどの場合は、ペアで問題ないように思えることがあります。