2015-10-08 1 views
1

На самом деле, проблема в названии. У меня есть рабочий код, где я сильно использую 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>

+2

Вы уже упоминали решение: У вас есть' std :: numeric_limits :: max() - std :: numeric_limits :: min() 'возможные значения и для любых' char c', 'c - std :: numeric_limits :: min()' находится в индексе ассортимент. – 5gon12eder

+0

@CoryKramer, Нет, я этого не сделал. Но эффективность так же важна, как и переносимость для меня. Я дам ему шанс, но я уверен, что 'std :: vector ' работает быстрее в этом случае. – antonpp

+0

'char' гарантированно будет 1 байт, и я еще не видел архитектуру, у которой нет 8-битных байтов. Достаточно безопасно предположить, что 'char' всегда будет иметь 256 значений. – ElderBug

ответ

3

Я бы предложил ввести свой собственный класс для использования, который каким-то образом инкапсулирует 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 
}; 
4

Я предлагаю перейти на std::unordered_map<char, T> .

std::unordered_map Для сложность operator[] формулируется как approximatley O(1)

усредненными: постоянная, наихудший случай: линейная по размеру.

Для std::map сложность operator[] является O(logN)

Логарифмические в размере контейнера.

+2

Может быть, но нужно быть ориентированным: с ограниченным количеством ключей, хэширование может быть дороже, чем поиск. Все же переход на 'unordered_map' должен быть немедленным и безболезненным, поэтому стоит попробовать. – DarioP

+2

'O (1)' не означает, что это лучше. 'unordered_map []' включает управление хэшированием и ведром, а 'map []' - это просто поиск дерева. – ElderBug

+0

Это хорошие моменты, есть накладные расходы при использовании unordered_map (распределение, управление и т. Д.), А также карта (балансировка дерева и т. Д.). Я согласен, что самое лучшее, что нужно сделать, - это профилировать код, используя оба контейнера, и посмотреть, оправдан ли коммутатор. Если обе плохо работают, то «std :: array» с некоторой дополнительной проверкой ключа, вероятно, является другим способом. – CoryKramer