Why is return value of queue:front() valid after queue::pop()
I am new to C++ and ran into following supposedly  bug, but somehow my program just works..
Here is the code
#include<iostream>
#include<queue>
#include <string>


int main()
{
 string s ("cat");
 queue<string> _queue;
 _queue.push(s);
 string & s1 = _queue.front();
 _queue.pop();
 // at this time s1 should become invalid as pop called destructor on s
 std::cout << s1 << std::endl;
 return 0;

 }

It just works, even though s1 is a reference to an invalid object. Is there a way i can assert that s1 truely refers to an invalid object?

This is textbook undefined behavior, which by definition is not "detectable" at runtime, because you're already in UB-land.

Ty for the excellent link to UB.

See Can a local variable's memory be accessed outside of its scope?

Trying to access a destroyed object the way you do it in your code results in undefined behavior. And no, there's no language-provided way to perform a run-time check for this situation. It is entirely your responsibility to make sure things like that do not happen in your code.
The fact that "it just works" in your experiment is just an accident (with certain degree of typical computer determinism, as usual). Something completely unrelated might change in your program, and this code will no longer "work".

Slightly related, would it be UB even if the memory was never accessed, ie you made a custom allocator which had a method to assert a pointer for validity? Not useful normally, but could be for a test.

wonder why c++ runtime does not zero out the released memory ?

@Jimm : Some implementations do, it's dependent on the allocator. But, why should it need to? What benefit does that give? Any code that would rely on that has a bug.

@Jimm: Firstly, some implementations do in "debug" configurations, to help you catch bugs in your code, i.e. to make it crash more reliably in response to invalid memory access. They don't zero it though, but rather fill it with some sort of "bad" pattern. Secondly, in this particular example the memory is not necessarily released. The object is destructed, but the raw memory is likely retained by the queue object. So, pedantically speaking, it is not about released memory, but rather about memory occupied by now-destructed objects.
