Грамотное кодирование Vs. std :: pair, решения? - PullRequest
12 голосов
/ 25 июня 2009

Как и большинство программистов, я восхищаюсь и стараюсь следовать принципам грамотного программирования, но в C ++ я обычно использую std::pair для множества общих задач. Но std::pair, IMHO, подлый враг грамотного программирования ...

Я имею в виду, когда я возвращаюсь к коду, который я написал день или два назад, и я вижу манипуляции с std::pair (обычно в качестве итератора). первое и второе-> второе среднее ???".

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

Ответы [ 8 ]

17 голосов
/ 25 июня 2009

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

6 голосов
/ 25 июня 2009

Как насчет этого:

struct MyPair : public std::pair < int, std::string >
{
    const int& keyInt() { return first; }
    void keyInt( const int& keyInt ) { first = keyInt; }
    const std::string& valueString() { return second; }
    void valueString( const std::string& valueString ) { second = valueString; }
};

Это немного многословно, однако использование этого в вашем коде может немного облегчить чтение, например:

std::vector < MyPair > listPairs;

std::vector < MyPair >::iterator iterPair( listPairs.begin() );
if ( iterPair->keyInt() == 123 )
    iterPair->valueString( "hello" );

Кроме этого, я не вижу никакой серебряной пули, которая прояснит ситуацию.

4 голосов
/ 25 июня 2009
typedef std::pair<bool, int> IsPresent_Value;
typedef std::pair<double, int> Price_Quantity;

... вы понимаете.

2 голосов
/ 25 июня 2009

Вы можете использовать буст-кортежи, но они на самом деле не меняют основную проблему: действительно ли ваш хочет получить доступ к каждой части пары / кортежа с помощью небольшого целочисленного типа, или вы хотите больше «грамотный» код. См. этот вопрос Я недавно отправил.

Однако, boost :: необязательный - это полезный инструмент, который, как я обнаружил, заменяет довольно много случаев, когда пары / кортежи рекламируются как ответ.

2 голосов
/ 25 июня 2009

Недавно я обнаружил, что использую boost::tuple вместо std::pair. Вы можете определить перечислители для каждого члена, поэтому очевидно, что это за член:

typedef boost::tuple<int, int> KeyValueTuple;
enum {
  KEY
  , VALUE
};

void foo (KeyValueTuple & p) {
    p.get<KEY> () = 0;
    p.get<VALUE> () = 0;
}

void bar (int key, int value)
{
  foo (boost:tie (key, value));
}

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

РЕДАКТИРОВАТЬ: Удалить имена из глобальной области.

Просто быстрый комментарий относительно глобального пространства имен. В общем, я бы использовал:

struct KeyValueTraits
{
  typedef boost::tuple<int, int> Type;
  enum {
    KEY
    , VALUE
  };
};

void foo (KeyValueTuple::Type & p) {
    p.get<KeyValueTuple::KEY> () = 0;
    p.get<KeyValueTuple::VALUE> () = 0;
}

Это выглядит так, что boost::fusion связывает идентичность и ценность ближе друг к другу.

2 голосов
/ 25 июня 2009

Вы можете создать две пары получателей (const и non), которые будут просто возвращать ссылку на первое и второе, но будут гораздо более удобочитаемыми. Например:

string& GetField(pair& p) { return p.first; }
int& GetValue(pair& p) { return p.second; }

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

Если вы планируете много использовать это, вы также можете создать макрос, который будет генерировать для вас эти методы получения, учитывая имена и типы: MAKE_PAIR_GETTERS (Field, string, Value, int) или около того. Простое получение методов получения, возможно, позволит компилятору оптимизировать их, поэтому они не добавят накладных расходов во время выполнения; и использование макроса позволит легко создавать эти геттеры для любого использования пар.

1 голос
/ 25 июня 2009

Мне не нравится std :: pair, используемый в std :: map, записи карты должны иметь ключ и значение участника.
Я даже использовал boost :: MIC, чтобы избежать этого. Тем не менее, boost :: MIC также имеет свою стоимость.

Кроме того, возвращение std :: pair приводит к получению менее читаемого кода:

if (cntnr.insert(newEntry).second) { ... }

???

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

1 голос
/ 25 июня 2009

Как упомянул Алекс, std::pair очень удобно, но когда это сбивает с толку, создайте структуру и используйте ее таким же образом, посмотрите на код std::pair, это не так сложно.

...