views:

3872

answers:

5
std::map<std::string, std::string> myMap;

std::map<std::string, std::string>::iterator i = m_myMap.find(some_key_string);
if(i == m_imagesMap.end())
    return NULL;

string *p = &i->first;

Is the last line valid? I want to store this pointer p somewhere else, will it be valid for the whole program life? But what will happen if I add some more elements to this map (with other unique keys) or remove some other keys, won’t it reallocate this string (key-value pair), so the p will become invalid?

A: 

It's not guaranteed to be safe. I think it strongly depends on implementation.

EDIT: Anyway "p" MUST be const or you could use pointer to change the key value which is bad! Actually without "const" that code should not compile on a modern compiler.

happy_emi
+6  A: 

First, maps are guaranteed to be stable, i.e. the iterators are not invalidated by element insertion or deletion (beside the element being deleted of course).

However, stability of iterator does not guarantee stability of pointers. It so happens that most implementation use pointers at least at some level to implement iterators, so it is quite safe to assume your solution will work. But what you should really store it the iterator.

What you could do is create a small object like:

struct StringPtrInMap
{
  typedef std::map<string,string>::iterator iterator;
  StringPtrInMap(iterator i) : it(i) {}
  string& operator*() { return it->first; }
  const string& oeprator*() const { return it->first; }
  string* operator->() { return &it->first; }
  const string* operator->() const { return &it->first; }
  iterator it;
}

And then store that instead of a string pointer.

PierreBdR
Thanks, but I need to pass a pointer as windows message LPARAM, can I cast iterator to LPARAM and then back to iterator again?
michael
Gorpik
+7  A: 

Section 23.1.2#8 (associative container requirements):

The insert members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.

So yes storing pointers to data members of a map element is guaranteed to be valid, unless you remove that element.

Greg Rogers
Actually, not quite ... the /iterator/ is stable, but keeping an iterator stable doesn't imply keeping the pointer stable (you could imagine a garbage collector making sure every iterator trace the data, but not pointers).
PierreBdR
Hmmmm, looks like you are right. While the standard explicitly makes notes about vector, list, and deque - when references and iterators are invalidated, I can't find anything in there about map/set iterator/reference validity.
Greg Rogers
Greg, iterators keep being valid, even if you erase other iterators. only the iterator that is being erased is invalidated by such an operation. i believe (though i have no looked up) data is not moved around in a map. would be nice if someone finds a quote on this - or a quote proving it wrong.
Johannes Schaub - litb
yeah, Greg, we are right. 23.1.2/8: "The insert members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements." you get +1 by me, of course.
Johannes Schaub - litb
Thanks for the reference. I don't have a copy of the actual standard, and the draft standard on the web doesn't have this. The C++0x draft standard does have this in 23.1.4#8
Greg Rogers
I've just told a crowd of people to upvote this answer. Let's hope they make it bubble up :)
Johannes Schaub - litb
+1  A: 

If you're not sure which operations will invalidate your iterators, you can look it up pretty easily in the reference. For instance for vector::insert it says:

This effectively increases the vector size, which causes an automatic reallocation of the allocated storage space if, and only if, the new vector size surpases the current vector capacity. Reallocations in vector containers invalidate all previously obtained iterators, references and pointers.

map::insert on the other hand doesn't mention anything of the sort.

As Pierre said, you should store the iterator rather than the pointer, though.

drby
cplusplus.com is a bad source for quoting that kind of stuff. In general, examples of cplusplus.com are poor. I'm not saying that just because of fun, but i know it - i've seen it many times. best example of its poor quality is http://www.cplusplus.com/reference/iostream/ostream/operator%3C%3C.html
Johannes Schaub - litb
nothing regarding your answer though. just to tell you what i think about that site.
Johannes Schaub - litb
So what do you use for a reference if you don't have a book handy?www.cppreference.com still feels incomplete.
drby
hackingwords. i often end up looking at cplusplus.com for quick reference on function names. for "stl", i look into the SGI site, which i find quite good. they don't document c++ streams and others that wasn't in the SGI stl, so i look into cplusplus.com for those.
Johannes Schaub - litb
but i would not recommend you to trust its examples or even learn from it. i've seen too many cases where it oversimplificates things or even is wrong (like in my example, they say operator<< takes references-to-nonconst (copied from operator>>?).and they keep saying functions in std:: are global).
Johannes Schaub - litb
http://www.sgi.com/tech/stl/ for reference. have fun. wg21 is http://www.open-std.org/jtc1/sc22/wg21/ here. last working paper (c++1x though) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2800.pdf . you can find c++98 drafts too, of course.
Johannes Schaub - litb
of course i'm not alone with what i think about cplusplus.com and similar sites. people from ##c++ irc channel at freenode told me, and i've seen they are right over time. anyway, as i say i still use it for quick references. hope this helps somewhat :) have fun
Johannes Schaub - litb
+2  A: 

Why are you wanting to do this?

You can't change the value of *p, since it's const std::string. If you did change it, then you might break the invariants of the container by changing the sort order of the elements.

Unless you have other requirements that you haven't given here, then you should just take a copy of the string.

Richard Wolf