Что такое std :: pair? - PullRequest
       47

Что такое std :: pair?

42 голосов
/ 19 сентября 2008

Для чего нужен std::pair, зачем мне его использовать и какие преимущества дает boost::compressed_pair?

Ответы [ 10 ]

81 голосов
/ 21 февраля 2009

compressed_pair использует некоторые шаблоны для экономии места. В C ++ объект (small 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 может выглядеть (я упустил хорошую сделку, ctors и т. Д.):

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).

35 голосов
/ 19 сентября 2008

std::pair - это тип данных для группировки двух значений в один объект. std::map использует его для ключей, пар значений.

Пока вы учитесь pair, вы можете проверить tuple. Это как pair, но для группировки произвольного количества значений. tuple является частью TR1, и многие компиляторы уже включают его в свои реализации стандартной библиотеки.

Кроме того, ознакомьтесь с главой 1 «Кортежи» книги Расширения стандартной библиотеки C ++: учебное пособие и справочник , автор Pete Becker, ISBN-13: 9780321412997, для подробного объяснения.

alt text

11 голосов
/ 21 февраля 2009

Может показаться странным слышать, что сжатая_пара заботится о паре байтов. Но на самом деле это может быть важно, если учесть, где можно использовать сжатый_пар. Например, давайте рассмотрим этот код:

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

Это может внезапно оказать большое влияние на использование сжатой_пары в случаях, подобных описанным выше. Что может произойти, если boost :: bind сохранит указатель функции и заполнитель _1 как члены в себе или в std::pair в себе? Ну, это может раздуться до sizeof(&f) + sizeof(_1). Предполагая, что указатель на функцию имеет 8 байтов (что не редкость, особенно для функций-членов), а заполнитель имеет один байт (см. Ответ Логана, почему), тогда нам может понадобиться 9 байтов для объекта связывания. Из-за выравнивания это может увеличить размер до 12 байт в обычной 32-битной системе.

boost::function побуждает свои реализации применять оптимизацию небольших объектов. Это означает, что для функторов small для хранения функтора используется небольшой буфер, непосредственно встроенный в объект boost::function. Для больших функторов куча должна использоваться с помощью оператора new для получения памяти. В районе boost версии 1.34 было решено принять эту оптимизацию , потому что считалось, что можно получить очень большие преимущества в производительности.

Теперь, разумный (но, может быть, все еще довольно маленький) предел для такого маленького буфера был бы 8 байтов. То есть наш довольно простой объект связывания будет , а не помещаться в маленький буфер и потребует сохранения оператора new. Если вышеуказанный объект связывания будет использовать compressed_pair, он может фактически уменьшить свой размер до 8 байт (или 4 байт для указателя на функцию, не являющуюся членом, часто), потому что заполнитель является не чем иным, как пустым объектом.

Так что то, на что может быть потрачено много времени только на несколько байтов, может оказать существенное влияние на производительность.

11 голосов
/ 19 сентября 2008

Иногда вам нужно вернуть 2 значения из функции, и часто бывает слишком сложно пойти и создать класс для этого.

std: пара пригодится в этих случаях.

Я думаю, что boost :ressed_pair может оптимизировать количество членов размера 0. Что в основном полезно для тяжелых шаблонных машин в библиотеках.

Если вы управляете типами напрямую, это не имеет значения.

3 голосов
/ 21 февраля 2009

Это не что иное, как структура с двумя переменными под капотом.

Я на самом деле не люблю использовать std :: pair для возврата функций. Читатель кода должен знать, что такое .first и что такое .second.

Компромисс, который я иногда использую, заключается в немедленном создании постоянных ссылок на .first и .second, в то же время четко называя ссылки.

3 голосов
/ 23 сентября 2008

Дополнительная информация: boost ::ressed_pair полезна, когда один из типов пары является пустой структурой. Это часто используется в метапрограммировании шаблонов, когда типы пары программно выводятся из других типов. В конце концов, у вас обычно есть какая-то форма «пустой структуры».

Я бы предпочел std :: pair для любого "нормального" использования, если только вы не увлекаетесь метапрограммированием сложных шаблонов.

3 голосов
/ 19 сентября 2008

Это стандартный класс для хранения пары значений. Он возвращается / используется некоторыми стандартными функциями, такими как std::map::insert.

boost::compressed_pair утверждает, что более эффективен: см. Здесь

3 голосов
/ 19 сентября 2008

std :: pair пригодится для пары других контейнерных классов в STL.

Например:

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

Оба хранят std :: пары ключей и значений.

При использовании карты и мультикарты вы часто получаете доступ к элементам, используя указатель на пару.

2 голосов
/ 23 января 2010

Для чего нужен std :: pair, зачем мне его использовать?

Это просто кортеж из двух элементов. Это было определено в первой версии STL во времена, когда компиляторы не широко поддерживали шаблоны и методы метапрограммирования, которые потребовались бы для реализации более сложного типа кортежа, такого как Boost.Tuple .

Это полезно во многих ситуациях. std::pair используется в стандартных ассоциативных контейнерах. Его можно использовать как простую форму диапазона std::pair<iterator, iterator> - поэтому можно определить алгоритмы, принимающие один объект, представляющий диапазон, вместо двух итераторов по отдельности. (Это полезная альтернатива во многих ситуациях.)

1 голос
/ 19 сентября 2008

Иногда есть две части информации, которые вы просто всегда передаете вместе, будь то параметр, или возвращаемое значение, или что-то еще. Конечно, вы могли бы написать свой собственный объект, но если это всего лишь два небольших примитива или подобное, иногда пара выглядит просто отлично.

...