Это соответствующие практики при работе с std :: map? - PullRequest
9 голосов
/ 28 января 2009

У меня есть несколько вопросов по использованию std::map:

  1. Является ли использование enum в качестве ключа в std::map хорошей практикой? Рассмотрим следующий код:

    enum Shape{
        Circle,
        Rectangle
    };
    
    int main(int argc, char* argv[])
    {
         std::map<Shape,std::string> strMap;
         // strMap.insert(Shape::Circle,"Circle"); // This will not compile
         strMap[Shape::Circle] = "Circle";         // But this will work
         return 0;
    }
    
  2. Почему в приведенном выше примере вызов insert() вызывает ошибку компилятора, а перегруженный оператор [] работает правильно? Какой из этих методов рекомендуется для вставки элементов в std::map?

  3. Я понимаю, что когда метод find() используется в классе std::map, он не выполняет последовательный поиск в контейнере, а выполняет некоторый логарифмический поиск, который будет намного быстрее, чем последовательный поиск. Это понимание правильно?

Ответы [ 5 ]

12 голосов
/ 28 января 2009
  1. Наличие enum в качестве key_type само по себе неплохо. ( edit ) Но если вы используете только последовательные enum-значения, std::vector с доступом O (1) будет еще лучше.
  2. insert должен использоваться следующим образом: mapVar.insert(make_pair(key, value)); Смотрите также cppreference.com .
  3. Да, std::map имеет поиск O (log (n)), как гарантировано стандартом, и это быстрее, чем O (n), если n достаточно велико.
5 голосов
/ 28 января 2009

Вставить не удалось, так как тип_значения: std :: pair

3 голосов
/ 28 января 2009

1) Является ли использование enum в качестве ключа в std :: map хорошей практикой?

Что ж, для эффективности при таком маленьком перечислении вам лучше использовать вектор или массив tr1 :: либо значений (если ваш тип значений поддерживает «пустые» значения), либо умных указателей. например: vector<string>

Для правильности - я верю, что ты в порядке. Map может работать с любым типом ключей, которые можно сортировать, то есть с оператором <или для которых вы предоставляете функцию сортировки. Перечисления имеют порядок по умолчанию </p>

2) В strMap.insert(Shape::Circle,"Circle") почему метод вставки [дает] ошибку компилятора?

Потому что insert не принимает два значения. требуется пара. попробовать:

#include <utility>
...
strMap.insert(make_pair(Circle, string("Circle")));

3) Когда метод find () используется в классе карты, [он] выполняет некоторый логарифмический поиск ... правильно?

Да. map :: find - время O (LG (map :: size ())). Карта хранит свои пары ключ-значение в структуре данных, отсортированной по ключу. вставка и стирание O (LG (N)), как найти. Он также предоставляет двунаправленные итераторы, что означает, что вы можете найти следующий или предыдущий элемент на карте в O (1) постоянное время, но вы не можете пропускать вперед и назад более одного элемента за раз.

Редактировать: исправлено, что перечисления имеют порядок по умолчанию.

1 голос
/ 28 января 2009

Попробуйте использовать

strMap.insert(std::pair<Shape, std::string>(Circle,"Circle"));

вместо (не Shape :: Circle!).

Значения перечисления видны в той же области видимости, что и перечисление в C ++ (очень некрасиво, и мне это совершенно не нравится, но это так!)

0 голосов
/ 02 февраля 2009

В подобных ситуациях, когда вам часто требуется статическое отображение перечислений в строки, часто проще сделать что-то вроде этого:

enum Shape{
    Circle,
    Rectangle,
    NShapes,
};

char *ShapeNames[] = 
{  
    "Circle",
    "Rectangle",    
};

void CheckShapeNames()
{
    // Use a static_assert here instead if you have it in your library
    int ShapeNamesCount[(sizeof(ShapeNames)/sizeof(char*)) == NShapes];
}

С этого момента доступ к именам фигур становится простым путем доступа к массиву ShapeNames:

string name = ShapeNames[Shape::Circle];

или даже:

for (int i=0; i < Shape::NShapes; ++i)
{
    cout << ShapeNames[i];
}
...