简体   繁体   中英

Accessing std::map keys and values

How do you access an std::vector of the keys or values of an std::map ?

Thanks.

Edit: I would like to access the actual elements, not just copies of their contents. essentially I want a reference, not a copy.

This is essentially what I am wanting to do:

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

// fill map

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

You can't do that because neither the values nor the keys are laid out consecutively in memory. Each key/value pair is allocated independently in memory. In a situation like yours, you have to copy the values around.

There isn't a single function you can call to get all of the keys or values from an STL map. Instead, you can use the map iterators to access this information:

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

If you want to write a function that takes these values and wraps them up in an STL vector, then you could do so like this:

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;
}

Note that in these template functions, the type of the iterator is

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

instead of

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

This is because const_iterator here is a dependent type - a type that depends on a template argument - and consequently for silly historical reasons must be prefaced by the typename keyword. There's a good explanation of this here .

Hope this helps!

Further to what others have said, it sounds very much like you really want to put the values into a std::vector and then sort the vector; that way you can access the contents like you want to (ie via a pointer to a contiguous array of them).

Note that this assumes that reading will be your bottleneck, and that writing (ie setting up the vector) will be done relatively infrequently. If not, then you're probably better off sticking with the std::map , and then copying the contents into a temporary array/vector every time you want to use them in this fashion.

As others have said in their answers, you can't access all the keys or values in the form of a std::vector without copying them - std::map isn't designed for this form of access.

For your situation, I would set up 2 containers:

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

where the vector stores the ID, and the map's value is the index to the ID in the vector. When you add a new texture, add the ID into the vector with push_back() , whose index is stored in a map entry with the last element's index, eg:

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
}

The push_back would maintain the same indexes for old IDs. Encapsulate all this within a class with functions to add and search for textures, just like in the answer to your other question.

This would let you call, after the IDs are loaded:

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

... since std::vector guarantees that elements are consecutive to one another in memory.


edit: changed the map's value type; this was previously GLuint*, pointing at the vector's elements. Thanks to Oli Charlesworth for pointing out this design's flaw. edit: added sample code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM