Доступ к ключам и значениям std::map

Как вы получаете доступ к std::vector ключей или значений std::map?

Благодарю.

Изменить: я хотел бы получить доступ к фактическим элементам, а не только копии их содержимого. по сути, я хочу ссылку, а не копию.

По сути, это то, что я хочу сделать:

std::map<std::string, GLuint> textures_map;

// fill map

glGenTextures( textures_map.size(), &textures_map.access_values_somehow[0] );

4 ответа

Решение

Как сказали другие в своих ответах, вы не можете получить доступ ко всем ключам или значениям в форме std:: vector без их копирования - std::map не предназначен для этой формы доступа.

Для вашей ситуации я бы настроил 2 контейнера:

std::vector<GLuint> texture_id;
std::map<std::string, size_t> texture_map;

где вектор хранит идентификатор, а значение карты является индексом идентификатора в векторе. Когда вы добавляете новую текстуру, добавьте идентификатор в вектор с push_back(), чей индекс хранится в записи карты с индексом последнего элемента, например:

pair<map<string, size_t>::iterator, bool> result = 
    texture_map.insert(make_pair(new_texture_name, -1));    //ignore the index for now
if(result.second) { //true when the texture name isn't already in the map
    texture_id.push_back(new_id);
    result.first->second = texture_id.size()-1; //update the index in the map to this ID's element in texture_id
}

Push_back будет поддерживать те же индексы для старых идентификаторов. Инкапсулируйте все это в классе с помощью функций для добавления и поиска текстур, как в ответе на другой вопрос.

Это позволит вам позвонить после загрузки идентификаторов:

glGenTextures( textures_id.size(), &(textures_id[0]) );

... так как std:: vector гарантирует, что элементы являются последовательными по отношению друг к другу в памяти.


редактировать: изменил тип значения карты; это было ранее GLuint*, указывая на элементы вектора. Спасибо Оли Чарльзуорту за то, что он указал на недостаток этого дизайна. редактировать: добавлен пример кода

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

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

for (map<K, V>::iterator itr = myMap.begin(); itr != myMap.end(); ++itr) {
    // Access key as itr->first
    // Access value as itr->second
}

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

template <typename K, typename V>
std::vector<K> GetKeys(const std::map<K, V>& m) {
    std::vector<K> result;
    result.reserve(m.size()); // For efficiency

    for (typename std::map<K, V>::const_iterator itr = m.begin(); itr != m.end(); ++itr)
         result.push_back(itr->first);

    return result;
}

template <typename K, typename V>
std::vector<V> GetValues(const std::map<K, V>& m) {
    std::vector<V> result;
    result.reserve(m.size()); // For efficiency

    for (typename std::map<K, V>::const_iterator itr = m.begin(); itr != m.end(); ++itr)
         result.push_back(itr->second);

    return result;
}

Обратите внимание, что в этих шаблонных функциях тип итератора

typename std::map<K, V>::const_iterator

вместо

std::map<K, V>::const_iterator

Это потому что const_iterator здесь есть зависимый тип - тип, который зависит от аргумента шаблона - и, следовательно, по глупым историческим причинам должен предшествовать typename ключевое слово. Здесь есть хорошее объяснение.

Надеюсь это поможет!

В дополнение к тому, что говорили другие, звучит так, будто вы действительно хотите поместить ценности в std::vector а затем сортировать вектор; таким образом, вы можете получить доступ к содержимому, как вы хотите (т.е. через указатель на их непрерывный массив).

Обратите внимание, что это предполагает, что чтение будет вашим узким местом, и что запись (то есть установка вектора) будет выполняться относительно редко. Если нет, то вам, вероятно, лучше придерживаться std::mapи затем копировать содержимое во временный массив / вектор каждый раз, когда вы хотите использовать их таким образом.

Другие вопросы по тегам