web-dev-qa-db-ja.com

std :: pairとは何ですか?

とは std::pair for、なぜそれを使用するのか、そしてどのようなメリットがあるのか​​boost::compressed_pair持ってきますか?

42
Anthony

std::pair は、2つの値を1つのオブジェクトとしてグループ化するためのデータ型です。 std::map は、キーと値のペアに使用します。

pair を学習している間、 Tuple を確認してください。 pairに似ていますが、任意の数の値をグループ化するためのものです。 TupleはTR1の一部であり、多くのコンパイラは標準ライブラリの実装にすでにそれを組み込んでいます。

また、本の第1章「タプル」もチェックしてくださいThe C++ Standard Library Extensions:A Tutorial and Referenceby Pete Becker、ISBN-13:9780321412997 、完全な説明のために。

alt text

35
jwfearn

_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; };
_

ここでは、sizeof(A)をゼロにできない場合でも、BCが同じサイズであっても問題ありません。

そのため、_boost::compressed_pair_はこの最適化を利用し、空の場合、可能な場合はペアの型の一方または他方から継承します。

したがって、_std::pair_は次のようになります(私はかなりのこと、俳優などを省略しています)。

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

つまり、FirstTypeまたはSecondTypeAの場合、_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)と同じ大きさになります。

81
Logan Capaldo

奇妙に聞こえるかもしれませんが、compressed_pa​​irは数バイトを気にします。しかし、compressed_pa​​irをどこで使用できるかを考えると、実際に重要になる可能性があります。たとえば、次のコードを考えてみましょう:

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

上記のような場合、compressed_pa​​irを使用すると突然大きな影響が出る可能性があります。 boost :: bindが関数ポインターとプレースホルダー__1_をそれ自体のメンバーとして、または_std::pair_自体に格納するとどうなりますか?まあ、それはsizeof(&f) + sizeof(_1)まで膨らむ可能性があります。関数ポインターが8バイト(特にメンバー関数の場合は珍しくありません)で、プレースホルダーが1バイト(理由はローガンの回答を参照)であるとすると、バインドオブジェクトには9バイトが必要になる可能性があります。アラインメントのため、これは通常の32ビットシステムで最大12バイトに膨らむ可能性があります。

_boost::function_は、その実装が小さなオブジェクトの最適化を適用することを推奨します。つまり、smallファンクタの場合、_boost::function_オブジェクトに直接埋め込まれた小さなバッファがファンクタを格納するために使用されます。より大きなファンクタの場合、メモリを取得するにはnew演算子を使用してヒープを使用する必要があります。ブーストについて バージョン1.34この最適化 を採用することが決定されました。これは、非常に優れたパフォーマンス上の利点を得ることができると考えられたためです。

さて、そのような小さなバッファの妥当な(まだ、かなり小さいかもしれませんが)制限は8バイトです。つまり、非常に単純なバインドオブジェクトは小さなバッファーに合わないため、新しいオペレーターを格納する必要があります。上記のバインドオブジェクトが_compressed_pair_を使用する場合、プレースホルダーは空のオブジェクトに過ぎないため、実際にそのサイズを8バイト(または非メンバー関数ポインターの場合は4バイト)に減らすことができます。

したがって、ほんの数バイトで多くのことを考えているだけのように見えても、実際にはパフォーマンスに大きな影響を与える可能性があります。

関数から2つの値を返す必要がある場合がありますが、そのためのクラスを作成して作成するのはやり過ぎです。

それらの場合にはstd:pairが便利です。

Boost:compressed_pa​​irを使用すると、サイズ0のメンバーを最適化できると思います。これは、ライブラリ内の重いテンプレート機械に最も役立ちます。

タイプを直接制御する場合、それは無関係です。

11
David Pierre

追加情報:boost :: compressed_pa​​irは、ペアのタイプの1つが空の構造体である場合に役立ちます。これは、ペアのタイプがプログラムで他のタイプから推論されるときに、テンプレートメタプログラミングでよく使用されます。そのとき、通常は何らかの形の「空の構造体」があります。

テンプレートメタプログラミングに詳しくない限り、「通常の」使用にはstd :: pairをお勧めします。

3
rlerallut

std :: pairは、STLの他のいくつかのコンテナークラスに役立ちます。

例えば:

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

どちらもstd :: keysとvaluesのペアを格納します。

マップとマルチマップを使用する場合、ペアへのポインタを使用して要素にアクセスすることがよくあります。

3
John Mulder

値のペアを格納するための標準クラスです。 std::map::insertなどの一部の標準関数によって返される/使用されます。

boost::compressed_pairはより効率的であると主張しています: ここを参照

3
user17481

これは、内部に2つの変数を持つ構造にすぎません。

関数の戻り値にstd :: pairを使用するのは嫌いです。コードの読者は、.firstと.secondが何であるかを知っている必要があります。

私が使用する妥協案は、参照に明確な名前を付けながら、.firstと.secondへの定数参照をすぐに作成することです。

3

Std :: pairとは何ですか、なぜそれを使用するのですか?

単純な2つの要素のタプルです。これは [〜#〜] stl [〜#〜] の最初のバージョンで定義されましたが、コンパイラがテンプレートやメタプログラミング技術を広くサポートしていなかったため、より洗練されたタイプのタプルを実装する必要がありました- Boost.Tuple

多くの状況で役立ちます。 std::pairは標準の連想コンテナで使用されます。範囲の単純な形式として使用できますstd::pair<iterator, iterator>-2つのイテレータを個別にではなく、範囲を表す単一のオブジェクトを受け入れるアルゴリズムを定義できます。 (これは多くの状況で便利な代替手段です。)

2
mloskot

場合によっては、パラメーターとして、戻り値としてなど、常に一緒に渡すだけの2つの情報がある場合があります。もちろん、独自のオブジェクトを作成することもできますが、それが2つの小さなプリミティブまたはそれに類似している場合は、ペアで問題ないように見えることがあります。

1
Aaron