0

In below code I am filling a map m with elements from another container vv. I am using a pointer to the current element in the map and that element/object is being further manipulated.

struct obj_t { vector<int> w1, w2, w3, ... }; 
map<int, obj_t> m;
vector<vector<int> vv;

for (vector<int> &v : vv) { 
    obj_t *p = &m[v[0]]; // create entry at key = v[0] if none existed
    p->w1.push_back(v[1]);
    p->w2.push_back(v[2]); 
    // many fields w3, w4, ... so using pointer may be "efficient"
}

Question: Is this pointer access safe? Is the element inside m that is being manipulated, guaranteed to retain its address through each access inside the loop? And from one iteration to another? (although not required in this example).

I understand that you should normally not use pointers to elements in containers, since these may be moved around by other parts of the "program" / "runtime". But I guess that inside a tight context like this, where no other manipulation of the map m takes place, this kind of pointer access is guaranteed to be safe. Is that correct?

The suspicion that it might not be like that would come from something like this where some_large_allocation() may cause memory objects to be relocated by the operating system:

for (vector<int> &v : vv) { 
    obj_t *p = &m[v[0]]; // creates entry at key = v[0] if none existed.
    p->w1.push_back(v[1]);
    // some_large_allocation() // can force elements of m to be relocated?
    p->w2.push_back(v[2]); // *illegal* m and/or the element pointed to was moved
    ...
}

UPDATE (written here, since marked as dupe, closed for answers)

To this question, Pointers to elements of STL containers, the accepted answer states:

std::list, std::set, and std::map guarantee that the iterators (including simple pointers) will not be invalidated when a new element is added or even removed.

mrchance
  • 1,133
  • 8
  • 24
  • See the accepted answer on the dupe. It works in practice, though the language doesn't guarantee it. – cigien Oct 11 '20 at 13:45
  • @cigien, thx! do you think you might also have an answer/dupe on this question: one thing i found is that containers inside a struct/class object often change addresses (themselves and their elements) quite arbitrarily (not within one access, but rather between accesses). could somebody speak to the specific rule governing lifetimes of pointers to containers inside struct/class objects? – mrchance Oct 11 '20 at 13:47
  • @cigien, so in the above specific example, "tight context", there is also no guarantee of this working (language lawyer wise)? – mrchance Oct 11 '20 at 13:48
  • 1
    No, I don't think there is. But you should use a reference anyway, and that is guaranteed. – cigien Oct 11 '20 at 13:50
  • Re your follow up question: It's a good question, but it's not really suited to the format of SO. You should search for those terms, and read a bunch of stuff you find. If you have a specific question about some code that you just can't find, then you can ask that here. – cigien Oct 11 '20 at 13:52
  • @cigien ok, so basically the advice is: pointers to elements of containers are **generally not** guaranteed to be valid. in some contexts they are more likely to work as expected (like references and iterators) but **generally not** (or never?) *guaranteed* to work. is that correct? – mrchance Oct 11 '20 at 14:00
  • That question is not really answerable. As far is the language is concerned, pointers, iterators, and references are different things. Whether one or more of them is implemented in terms of another, is irrelevant. – cigien Oct 11 '20 at 14:05
  • certainly it must be defined whether the behaviour is "guaranteed or not". if it is not specified, then well, it is **not guaranteed** – mrchance Oct 11 '20 at 15:01
  • Certainly it's defined for specific cases. Your follow up says, "*generally not, ... in some contexts ...*" which is a bit vague. – cigien Oct 11 '20 at 15:06
  • ok, so the conclusion is that it is guaranteed in some contexts? im insisting since it was quite surprising to me that even in the tight context examplified in my question, that is not one of those situations according to your answer above. thx! – mrchance Oct 11 '20 at 15:08
  • I see you edited the question. But that's a different question, and the answer is, No, everything is invalidated if you insert into a vector. – cigien Oct 11 '20 at 19:36
  • 1
    @cigien, sorry u are right, i edited it back to reflect only the original discussion around maps. thx for the vector specific answer. – mrchance Oct 11 '20 at 21:09

1 Answers1

2

I understand that you should normally not use pointers to elements in containers, since these may be moved around by other parts of the "program" / "runtime".

...

The suspicion that it might not be like that would come from something like this where some_large_allocation() may cause memory objects to be relocated by the operating system

You might be thinking of more "managed" languages like Java, which are free to move memory around as they see fit (but will also update references to that memory so the programmer doesn't need to worry about it). C++ does not do any of this.

In C++, pointers to elements in containers are only invalidated if the container is modified in certain ways, depending on the container. For example, for std::vector, it's safe to use pointers to its elements as long as the vector doesn't need to reallocate. For std::map, pointers to elements in the map are never invalidated (as long as the element remains in the map, of course).

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • thanks, this is what i thought, better safe than sorry:-) – mrchance Oct 11 '20 at 13:17
  • Is this right? It looks like only *iterators* and *references* are not invalidated. I'm not sure if *pointers* are ok. – cigien Oct 11 '20 at 13:25
  • cigien, you doubt about maps? that actually also feels strange to me, how and why should special guarantee be given to them? – mrchance Oct 11 '20 at 13:28
  • one thing i found is that containers inside a struct/class object often change addresses (themselves and their elements) quite arbitrarily (not within one access, but rather between accesses). could somebody speak to the specific rule governing lifetimes of pointers to containers inside struct/class objects? – mrchance Oct 11 '20 at 13:34
  • @cigien If references are safe, then so are pointers, because the resulting machine code is the same. At least in practice... I'm not sure about the "language lawyer" side of things. – Thomas Oct 11 '20 at 13:35
  • Ok, found a [dupe](https://stackoverflow.com/questions/516007/stdmap-pointer-to-map-key-value-is-this-possible). I think the accepted answer on the dupe is right. – cigien Oct 11 '20 at 13:42