Оптимизация C++: строки или перечислимый тип?
Иногда в качестве входных данных разрешается применение фиксированного набора строк. Далее они хранятся и используются. Однако эти строки желательно конвертировать в перечислимый тип — это будет наилучшим вариантом. Почему? Давайте рассмотрим преимущества.
Сравнения и опечатки
Строки могут содержать практически любые последовательности символов, в том числе и бессмысленные. И если где-нибудь в сравнении допустили опечатку, найти её станет непростой задачей. А вот перечислимые типы, напротив, являются идентификаторами, поэтому компилятор пожалуется на несоответствие.
В качестве примера давайте рассмотрим небольшую функцию:
void printMessage(string const& msg, string const& messageType) { if (messageType == "waring") { std::cout << "WARN: "; //! } //... }
Помеченная строка в нашем примере никогда не будет достигнута, так как messageType никогда не станет равен "waring". Это опечатка, которая сделана намеренно. Но если бы она была случайной, пришлось бы тратить время на отладку. А если бы мы использовали перечислимый тип, IDE и компилятор указали бы на ошибку сразу.
Соответствие типов
Вызовем предыдущую функцию:
printMessage("error", "Something bad happened!");
Ой… Мы только что пытались напечатать сообщение типа "Something bad happened!" с текстом "error". Но если бы тип сообщения был перечислимым, этой проблемы бы не возникло.
По большему счёту, желательно обернуть сообщения в их собственный класс либо структуру, ведь во многих случаях мы будем передавать и использовать тип и текст вместе.
Switch/case
В языке программирования C++ мы не можем использовать строки в условном операторе switch. В результате, вместо этого, нам приходится нагромождать if/else. А вот enum’ы — можем! Вдобавок к этому, мы сможем получать предупреждения компилятора либо статического анализатора, если забудем про перечислимый тип.
Производительность
Исключительно за производительностью гнаться не стоит. Однако в нашей ситуации, кроме производительности, мы ещё получим и более поддерживаемый код, а значит, стоит разобраться в вопросе чуть подробнее.
Стоит отметить, что сравнения перечислимых типов, как правило, быстрее, чем сравнения строк. При этом размер перечислимого типа равен размеру целого типа, а строки бывают весьма большими. Также оператор switch можно транслировать в jump-таблицы, что бывает эффективнее if/else.
Да, перечислимые типы совсем не обязательно более производительны, чем строки. Но всё же они явно не хуже.
Вывод прост: если у вас есть фиксированный набор строк, применяемый в качестве входных либо выходных данных, его однозначно надо конвертировать в enum.
По материалам статьи «Strings vs. Enumerators».