12

Consider the following code:

std::map<int, int> m;
int &ref = m[0];
int *ptr = &m[0];

m.insert({1,2});

std::cout << ref;   // #1
std::cout << *ptr;  // #2

For an associative container like std::map, the standard says:

The insert and emplace members shall not affect the validity of iterators and references to the container, ...

Which means #1 is definitely ok. However, I'm not so sure about #2.


This question has been asked and answer over a decade ago.

The accepted answer says #2 is technically not allowed but will work in practice.

The consensus answer (with more than twice the number of up-votes than the accepted answer) says #2 is ok, by simply saying that the above standard quote implies pointers are not invalidated as well.

There are also at least half a dozen relatively more recent duplicates of this question, most of them with answers, and all of them say #2 is ok, usually by quoting the same standard text above.


I don't think this is correct. To my understanding, references are not pointers, and one can't be substituted for the other, whether they are implemented in terms of each other or not. As a comparison, here's what the standard says about the validity of referents to elements in unordered associative containers, upon rehashing:

Rehashing invalidates iterators, ..., but does not invalidate pointers or references to elements.

This explicitly guarantees pointers' validity, suggesting that the validity of references does not automatically imply it.


So does the language say #2 is ok? And is it implied by the validity of #1?

cigien
  • 57,834
  • 11
  • 73
  • 112
  • The question can be rephrased: Is it allowed for objects to change their address when lvalue references (which have the inherent property that the address of the underlying object can be taken as they point to a lvalue) are supposed stay valid. Im pretty confident that the answer to this question is no, but obviously you want a more sophisticated answer. Also keep in mind that the standard is not error free and ambiguities and oversights do happen. – Sebastian Hoffmann Oct 12 '20 at 21:31
  • 5
    It is a wording defect. Pointers are OK. That's the intent of the standard, or I will eat my hat. Move on, nothing to see here. – n. m. could be an AI Oct 12 '20 at 21:32
  • Also notice that the question you cite mostly discuss pointers vs reference whereas you are concerned about references vs pointers – Sebastian Hoffmann Oct 12 '20 at 21:33
  • @SebastianHoffmann I'm fine with the question being rephrased in any way that's equivalent, if it helps to answer the question. I'm sorry, I don't understand your second comment. Did you mean to use *iterator*s in there? – cigien Oct 12 '20 at 21:34
  • @n.'pronouns'm. I think you might be right ,though it makes me feel a little funny ;) Is there a defect report that you're aware of for this? – cigien Oct 12 '20 at 21:35
  • @cigien The accepted answer says `However, stability of iterator does not guarantee stability of pointers! `, which, as far as my understanding is concerned, is a valid statement. It does not, however, discuss stability of references vs stability of pointers. Am I overlooking something? – Sebastian Hoffmann Oct 12 '20 at 21:38
  • @SebastianHoffmann The highest voted answer mentions that explicitly. Ok, not explicitly, I was reading into that a bit. I'll edit the question. – cigien Oct 12 '20 at 21:38
  • @cigien My bad, i looked at the accepted answer – Sebastian Hoffmann Oct 12 '20 at 21:40
  • @SebastianHoffmann No worries, I've edited the question anyway, my paraphrasing of that answer was not entirely fair. – cigien Oct 12 '20 at 21:42
  • I don't know of any reports. If there was a report for every little wording imperfection, the committee would drown in them. – n. m. could be an AI Oct 12 '20 at 21:45
  • A reference evaluates to an lvalue that represents the identity of an object. There is no way to magically invalidate pointers pointing to the exact same object. – Passer By Oct 12 '20 at 21:47
  • @n.'pronouns'm. Hmm, seems like the fix would be to just add "*and pointers*" in a couple of places. Hardly seems like strenuous fix for a bug that's been there for a decade. – cigien Oct 12 '20 at 21:47
  • @PasserBy Ok, that makes sense, and seems like the right behavior. I wonder why the second quote in the question explicitly mentions both then... – cigien Oct 12 '20 at 21:50
  • 1
    Would you expect `int *pref = &ref;` to be valid or invalid? `m[0]` returns a reference, so taking its address (to store in `ptr`) amounts to the same thing. – 1201ProgramAlarm Oct 22 '20 at 04:10
  • @1201ProgramAlarm Yes, I see your point, and I don't disagree. I'm just confused why the standard explicitly mentions both references and pointers in one case, and only references in the other. – cigien Oct 22 '20 at 04:17

2 Answers2

8

As many comments said, this is probably a slight standard miswording and the standard implies pointers too. However, if you wish to get into the language lawyering of it, take this: a reference cannot be reassigned (not the standard per se but an official source I found: https://isocpp.org/wiki/faq/references#reseating-refs ). That is, once a reference points to an object, the reference will always point to that object. As said in the standard here: https://eel.is/c++draft/intro.object , an object occupies a given region of storage throughout its lifetime. As stated here: https://eel.is/c++draft/basic.compound , a pointer refers to the address of the first byte of its object. Thus, if the reference is still valid, because it can't be reassigned to another object, the object it points to has not ended its lifetime, so the memory it occupies is still valid and held by that object, and so the pointer pointing to the beginning of that memory is still valid. So, within the rules of the C++ abstract machine, as outlined in the standard, the pointer would still be valid.

Anonymous1847
  • 2,568
  • 10
  • 16
2

To my understanding, references are not pointers, and one can't be substituted for the other, whether they are implemented in terms of each other or not.

I couldn't have said it better myself.

So does the language say #2 is ok? And is it implied by the validity of #1?

IMO one can't judge these matters by intent and assume that it must work, even if it seems to be some wording defect. As it stands this behavior must be regarded as implementation defined.

Your research is thorough and I believe there is no more to be done in that regard nor am I aware of any defect report about the matter, so IMO the approach is, as usual, if it's not in the standard one cannot assume it will work at all times even if it seems that it couldn't be any other way, and it does seem that way.

Ultimately a pointer to a variable is not the same as a variable reference and address-of operator is not the same of reference operator.

If you feel this should be addressed, you can always raise the issue yourself.

cigien
  • 57,834
  • 11
  • 73
  • 112
anastaciu
  • 23,467
  • 7
  • 28
  • 53