The memory model and expected semantics of the standard speak about an observable behaviour which implementations must conform to (see paragraphs 1.7 - The C++ memory model - to 1.10 - Multi-threaded executions and data races - of the standard(1)). This observable behaviour shall match the one of the abstract machine described in the standard. It notably define memory of programs as a set of sequences of bytes, which may be modified through side effect operations (I/O on the memory). Pointers are themselves sequences of bytes stored in memory, and thus subjected to that same rule. The model also specifies situations of undefined behaviour, for which anything may happen, including memory corruption. Furthermore, a multithreaded program may, through race condition (see 1.10), modify memory "behind its own back" (my own wording, not an actual quote).
new
operators works through the use of allocation functions, which return memory addresses, and must also comply to the rule of observable behaviour.
That being said, paragraph 1.9 (Program execution), states in point 8, among the least requirements for a conforming implementation, that:
access to volatile objects are evaluated strictly according to the rules of the abstract machine.
In other words, though the program should render the same results as demonstrated by the model described in the standard, only volatile
are garanteed to be observed exactly as the standard describes it. Non volatile storage may well not be observed in a consistent manner (if you've already used a debugger on optimized code, you can clearly witness odd patterns in memory content updates with regard to what the program source actually specify).
Another important point is that new
operators are overloadable, meaning that the default behaviour described in the standard may be somewhat overriden. If a minimally conformant implementation of the standard (ie, one only enforcing volatile
variable observation) runs a program where new
has been overriden and does not rely on volatile
data to keep track of its memory heaps, with optimization and strong inlining, the values of returned pointers may not be immediately visible in the variables storing them. If optimization passes determined that the variable lifetime could be shortened from what the program describes, it is also possible that the memory location corresponding to that variable may be repurposed and its content changed and observed in a debugger as such, though the program did not indicate such update. That is however the compiler's job to make sure that the program's execution fits the expected behaviour: from the program perspective, the variable will hold its value during its whole lifetime, and will not change unless the program specifies it by an update in any way allowed by the memory model.
In your example, if you access the variable p
several times after the new
assignment in your program, you won't notice a change of the value it contains since that assignment, the standard requires it. If you try to observe the memory location of that variable through some external device, you step out of the standard's abstract memory model, and could potentially witness changes in its content.
(1) using revision N3485 as reference, the paragraph numbering may have changed in later revisions.