На самом деле, проблема в названии. У меня есть рабочий код, где я сильно использую std::map<char, T> table
. Профилер сказал мне, что метод operator[]
занимает довольно много времени. Поэтому я думаю, что поскольку char имеет только несколько разных значений (от -128 до 127, я полагаю), можно изменить тип моей переменной table
на std::vector<T>
или даже T[256]
. Мой вопрос - как это сделать безопасно. Я имею в виду, что я не могу полагаться на то, что тип char
имеет ровно 256 различных значений, поэтому я хочу добавить переносимый код, который будет использовать что-то вроде std :: numeric_limits и будет гарантировать, что размер table
охватывает все возможные значения char
. И еще одна проблема заключается в том, что мне не нравились отрицательные значения при использовании std::map
. Но я не могу сделать то же самое с std::vector
, потому что table[(char)-15]
создаст исключение. Означает ли это, что самым простым решением является передача всех ключей от char
до unsigned char
перед вызовом operator[]
моего table
? Если это не так, как мне это сделать?Рефакторинг код с <char, T> в вектор <T>
ответ
Я бы предложил ввести свой собственный класс для использования, который каким-то образом инкапсулирует std::vector<T>
и предоставит необходимый вам интерфейс.
Если вы собираетесь повторно использовать много интерфейса std::vector
«s, вы можете даже рассмотреть возможность использования внедренных-в-плана-отношений:
template <class T>
struct MyMap : protected std::vector<T>
{
using std::vector::vector;
using std::vector::push_back;
// ...
// List other members which you want to inherit verbatim
T& operator[] (char idx)
{
return std::vector::operator[](idx - std::numeric_limits<char>::min());
}
// Re-implement the members which you need to
};
Я предлагаю перейти на std::unordered_map<char, T>
.
std::unordered_map
Для сложность operator[]
формулируется как approximatley O(1)
усредненными: постоянная, наихудший случай: линейная по размеру.
Для std::map
сложность operator[]
является O(logN)
Логарифмические в размере контейнера.
Может быть, но нужно быть ориентированным: с ограниченным количеством ключей, хэширование может быть дороже, чем поиск. Все же переход на 'unordered_map' должен быть немедленным и безболезненным, поэтому стоит попробовать. – DarioP
'O (1)' не означает, что это лучше. 'unordered_map []' включает управление хэшированием и ведром, а 'map []' - это просто поиск дерева. – ElderBug
Это хорошие моменты, есть накладные расходы при использовании unordered_map (распределение, управление и т. Д.), А также карта (балансировка дерева и т. Д.). Я согласен, что самое лучшее, что нужно сделать, - это профилировать код, используя оба контейнера, и посмотреть, оправдан ли коммутатор. Если обе плохо работают, то «std :: array» с некоторой дополнительной проверкой ключа, вероятно, является другим способом. – CoryKramer
Вы уже упоминали решение: У вас есть' std :: numeric_limits :: max() - std :: numeric_limits :: min() 'возможные значения и для любых' char c', 'c - std :: numeric_limits :: min()' находится в индексе ассортимент. –
5gon12eder
@CoryKramer, Нет, я этого не сделал. Но эффективность так же важна, как и переносимость для меня. Я дам ему шанс, но я уверен, что 'std :: vector' работает быстрее в этом случае. –
antonpp
'char' гарантированно будет 1 байт, и я еще не видел архитектуру, у которой нет 8-битных байтов. Достаточно безопасно предположить, что 'char' всегда будет иметь 256 значений. – ElderBug