views:

101

answers:

5

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;
}
+3  A: 

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 an 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;
};
anon
Thanks for the answer. If I want to avoid having two copies of the string, should I rather use a reference in the `struct data` instead?
Helltone
Also, when you say I can't store references, does you mean that the STL forces a copy?
Helltone
@Helltone References are hard to use correctly as members of structs or classes - that's not really what they were intended for. Instead, you should use a pointer, or omit the string from the struct altogether.
anon
@Helltone Yes, all Standard Library containers store copies.
anon
A: 

You should use pointer in this case. With reference i'm not sure it'll be able to compile at all.

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

Deleting should not be a problem. String should not be copied. It'll probably work with reference too, but i never considered/tried such a usage.

Drakosha
That would also need a custom comparator to compare the string contents; the default would compare the address, which is almost certainly wrong.
Mike Seymour
It compiles with the reference. And I would rather avoid a pointer here...
Helltone
@Helltone: or a pointer in the struct. The problem with references you must init them in constructor, and you not always have the value to init with, especially in this case.
Drakosha
+5  A: 

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>
Space_C0wb0y
A: 

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.

mkaes
A: 

Hi, 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.

Sarath