简体   繁体   中英

Reference as key in std::map

Suppose some data structure:

typedef struct {
    std::string s;
    int i;
} data;

If I use the field data.s as key when adding instances of data in a map of type std::map<std::string&, data> , do the string gets copied? Is it safe to erase an element of the map because the reference will become invalid?

Also do the answers to these questions also apply to an unordered_map ?

EDIT:

This is my current solution... but adding iterator to the map is UGLY:

typedef struct {
    const std::string* s;
    int i;
} data;

std::map<std::string, data> map;
typedef std::map<std::string, data>::iterator iterator;

// add an element to the map
iterator add_element(const std::string& s) {
    std::pair<iterator, bool> p = states.insert(std::make_pair(s, data()));
    iterator i = p.first;
    if(p.second) {
        data& d = (*i).second;
        d.s = &(*i).first;
    }
    return i;
}

C++11

Since C++11 reference wrapper is part of standard.

#include <functional> 

std::map<std::reference_wrapper<std::string>, data>

Using Boost

You may want to take a look at boost.ref . It provides a wrapper that enables references to be used in STL-containers like this:

std::map<boost::reference_wrapper<std::string>, data>

You can't store references in Standard Library containers - your map should look like:

map <string,data> mymap;

The map will manage both the key string and the struct instances, which will be copies, for you. Both map and unordered_map work in the same way in this regard, as do all other Standard Library containers.

Note that in C++, you don't need typedefs to declare structs:

struct data {
    std::string s;
    int i;
};

You cannot use the reference. The map can copy the content. This is I guess implementation dependent.

But tested with the microsoft STL.

struct data
{
            data(data const& rhs)
            {
               a new object will be created here
            }
            std::string s;
            int i; 
};

Add some objects to the map and you will run into the copy constructor. This should invalidate your reference.

I don't think there's a big performance gain if you choose pointer instead of object. Only do this if you're managing data with lot of existing string objects which need to hold inside the container. Also the destruction of the objects has to be managed manually before destructing the container.

Regarding your question about unordered_map , std::reference_wrapper will not work in the case.

std::reference_wrapper is not a default constructible class. To create a hasher, std::unordered_map needs type of the key to be a default constructible, copy assignable, destructible, and swappable class. See the std::hash .

You could try write your own reference_wrapper which would be a default constructible class, and use your class as the key type for a std::unordered_map specialization. To check whether your class satisfy each criterion mentioned above, use related functions from the type_traits library.

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