Доступ к ключам и значениям std :: map - PullRequest
1 голос
/ 05 января 2011

Как получить доступ к std::vector ключам или значениям std::map?

Спасибо.

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

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

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

// fill map

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

Ответы [ 4 ]

2 голосов
/ 05 января 2011

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

2 голосов
/ 05 января 2011

Нет ни одной функции, которую можно вызвать, чтобы получить все ключи или значения из карты 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.Вот хорошее объяснение этого здесь .

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

0 голосов
/ 05 января 2011

Как уже говорили другие в своих ответах, вы не можете получить доступ ко всем ключам или значениям в форме 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 гарантирует, что элементы являются последовательными по отношению друг к другу в памяти.


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

0 голосов
/ 05 января 2011

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

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

...