C ++ Длинный оператор switch или поиск с картой?

Возможно, стоит отметить, что это также может произойти, когда Windows блокирует загрузки, которые он считает небезопасными. Это можно устранить, щелкнув правой кнопкой мыши файл jar (например, ojdbc7.jar) и проверив поле «Unblock» внизу.

Диалоговое окно свойств файла JAR для Windows: Windows JAR File Properties Dialog [/g0]

30
задан Deduplicator 12 October 2018 в 02:23
поделиться

11 ответов

Лично я бы использовал карту, поскольку ее использование подразумевает поиск данных - использование переключателя обычно указывает на разницу в поведении программы. Кроме того, изменить отображение данных с помощью карты проще, чем с помощью переключателя.

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

Другой подход к размышлениям об этом заключается в том, что было бы нецелесообразно объединять код и связанное значение в структуру данных, особенно если диапазон кодов и значений статичен:

struct Code { int code; int value; };

Code c = ...

std::cout << "Code " << c.code << ", value " << c.value << std::end;
8
ответ дан 28 November 2019 в 00:23
поделиться

Если вы можете использовать tr1, вы можете использовать unordered_map для хеширования значений (целые числа хеширования тоже могут быть очень быстрыми), что должно сделать большинство поисков постоянным.

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

1
ответ дан 28 November 2019 в 00:23
поделиться

Я думаю, что сгенерированный код структуры switch-case может стать довольно большим, если количество «кодов» станет большим, и в этом случае я думаю, что stl :: map более подходящая.

0
ответ дан 28 November 2019 в 00:23
поделиться

Я сам неравнодушен к таблицам поиска, потому что мне кажется, что необычно длинные операторы переключения затрудняют разделение между кодом и данными. Я также считаю, что таблицы лучше подходят для будущих изменений и обслуживания.

Все ИМХО, конечно.

2
ответ дан 28 November 2019 в 00:23
поделиться

Это скорее зависит от того, какие коды и сколько их. У хороших компиляторов есть различные приемы, которые они используют для оптимизации операторов switch, некоторые из которых они не используют с прямыми операторами if / then. Большинство из них достаточно умны, чтобы выполнять простые математические вычисления или использовать таблицы поиска / перехода, например, для случая 0, 1, 2 или случая 3, 6, 9.

Конечно, некоторые этого не делают, и многим легко помешать необычный или неправильный набор ценностей. Кроме того, если код для обработки нескольких случаев выглядит очень похожим, вырезание и вставка может привести к проблемам с обслуживанием. Если у вас много кодов, но они могут быть алгоритмически разделены на группы, вы можете рассмотреть несколько / вложенных операторов switch, например, а не:

switch (code) {
    case 0x0001: ...
    case 0x0002: ...
    ...
    case 0x8001: ...
    case 0x8002: ...
    ...
}

Вы можете использовать:

if (code & 0x8000) {
    code &= ~0x8000;
    switch (code) {
        case 0x0001: ... // actually 0x8001
        case 0x0002: ... // actually 0x8002
        ...
    }
}
else {
    switch (code) {
        case 0x0001: ...
        case 0x0002: ...
        ...
    }
}

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

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

5
ответ дан 28 November 2019 в 00:23
поделиться

Я предлагаю использовать статическую, постоянную, таблицу пар. Это другая форма таблицы поиска:

struct Table_Entry
{
    int code;
    int value;
};

static const Table_Entry  lookup_table[] =
{
  {1, 10},
  {2, 15},
  {3, 13},
};

static const unsigned int NUM_TABLE_ENTRIES =
    sizeof(lookup_table) / sizeof(lookup_table[0]);

Преимущество этого метода в том, что таблица создается во время компиляции, в отличие от std::map, которая должна быть инициализирована во время выполнения. Если количество данных велико, можно использовать std::lower_bound для поиска записи, при условии, что таблица упорядочена.

Еще одним преимуществом этой техники является то, что она управляется данными. Данные могут меняться без изменений в поисковой системе. Изменения в коде или процессе могут потребовать серьезного регрессионного тестирования, а изменения данных - нет; YMMV.

Это похоже на то, что может генерировать компилятор.

2
ответ дан 28 November 2019 в 00:23
поделиться

Я говорю карта, если все, что вы делаете, присваиваете значение. Моя причина в том, что он расширяемый без изменения кода, чего нет у вашего оператора switch.

кстати, как насчет перечисления ?

0
ответ дан 28 November 2019 в 00:23
поделиться

Если ваши коды достаточно смежны, и их диапазон разрешает, что вам было бы намного лучше со старомодным простым массивом, что-то вроде

int lookup[] = {-1, 10, 15, -1 222};

, тогда оператор switch можно переписать так же просто, как

value = lookup [code];

все остальные варианты в некоторой степени вводят дополнительную стоимость.

7
ответ дан 28 November 2019 в 00:23
поделиться

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

Выбирайте то, что облегчает поддержку вашего кода в долгосрочной перспективе.

Ваш образец слишком короткий, чтобы делать какие-либо значимые выводы в этом отношении.

2
ответ дан 28 November 2019 в 00:23
поделиться

Обычно я предлагаю карту или массив поиска или, возможно, даже какой-то гибридный поисковый монстр (при условии что вы оптимизируете скорее для скорости или размера кода, чем для удобочитаемости), но стоит отметить, что новые версии GCC достаточно умны, чтобы заменить такие назначения переключателей / случаев в таблицах поиска. Хотя это не так хорошо для полностью разреженных ключей, это может быть, если ключи находятся в группах, например: 0, 1, 2, 3, 4, 5, 11, 12, 13, 14, 15 , 193, 194, 195, 196, 197, 198 ...

Конечно, если бы вы могли любить какую-нибудь арифметику для преобразования, даже лучше (обычно). Никогда не упускайте из виду смещение, обратный порядок байтов или более традиционную математику, когда делаете что-то подобное.

0
ответ дан 28 November 2019 в 00:23
поделиться
  • Считайте целые числа в массив/вектор
  • сортируйте массив/вектор
  • используйте bsearch на базовом массиве
-1
ответ дан 28 November 2019 в 00:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: