There is a code following code.

#pragma once #include <string> #include <iostream> using namespace std; class TestObject { public: TestObject() : st("default") { cout << st << " is created" << endl; } TestObject(const string& s) : st(s) { cout << st << " is created" << endl; } string ToString() { return st; } void Print() { cout << st << "... printed itself" << endl; } ~TestObject() { cout << st << " is destroyed" << endl; } private: string st; public: static TestObject& null() { static TestObject to("null"); return to; } }; TestObject& test() { TestObject to("Local"); return to; return TestObject::null(); } int main() { test().Print(); cout << endl; system("pause"); return 0; } 

If you run this code in Debug mode, an error occurs, which is understandable, since the function returns a reference to a local object.

However, if run in Release mode, then everything works and the following output is obtained:

 Local is created Local is destroyed ... printed itself Для продолжения нажмите любую клавишу . . . 

Which is a bit strange.

In addition, if you call test().Print(); twice in a row, an exception will be generated on the first call and the program will stop.

I had the misfortune to make a similar mistake in a real project, and, having assembled a program under Release, I wondered for a very long time why the function returns an empty default value, which I found out in this example, it is not at all. Under the debugger in Release, it is as if return TestObject::null(); , although not null is printed, but just an empty string.

Explain, please, what exactly happens in Release mode.


Following the advice of @Harry, I ran the following code:

 TestObject &t = test(); TestObject::null().Print(); t.Print(); 

At first, a lot of delirium was brought out and the jerky sounds of "pi, pi, pi" began to be generated, after which VS stopped the program with an error reading someone else's memory, but the sound stopped only when he pressed "Abort". All subsequent attempts to run the code ended with the program stopping with the following output.

 Local is created Local is destroyed null is created null... printed itself |√& √*Ф ·в┬│ L√& j3╪u р¤~М√& ☻Щлw р¤~`Я·k р¤~ X√&    ┼Xпw╠вv∟ д√& ╒Шлw°$Ф р¤~ °$Ф р¤~ 
  • What kind of exceptions do you expect? - Vladimir Gamalyan
  • Вызвано исключение по адресу 0x0F9165F6 (msvcp140d.dll) в ModernTests.exe: 0xC0000005: нарушение прав доступа при чтении по адресу 0xCCCCCCCC. - this. What happens when you debug or call test().Print(); Twice in a row - RussCoder
  • Access violation is not a thrown exception, it is only caught in debug mode because it is set there that these types of errors must be caught by the debugger. Try to put the compilation flag on / eha. - Daniel Protopopov
  • The function returned an address indicating that the memory was freed. How and when this memory will be overwritten is unknown in advance. Lucky for Release, he was able to read the line. Debug can generally overwrite freed memory with zeros. - Igor
  • @Igor, he counted from where that empty line, but not the string "Local" - RussCoder

2 answers 2

You simply have no luck :) For example, the address where the local object was located has not yet been erased, that's all. But note that the string st has already been destroyed, so it is simply output.

 ... printed itself 

but not

 Local... printed itself 

Just in the Release mode, no checks are already performed (for that, he is Release, so as not to waste time and resources on any extra checks) - the program is considered to be debugged. And an exception with such indefinite behavior is not required to be generated at all.

Try it for the sake of wedging another challenge - like this:

 TestObject &t = test(); TestObject::null().Print(); t.Print(); 

I think it will be more interesting. What exactly will be - impossible to predict :)

  • I tried your code. It turned out an interesting result, especially after the first launch. Updated the question. - RussCoder
  • Well, the stack is spoiled by the challenge. Now, when referring to the place where the string was st , there is no longer understand what, and where there was a pointer to the data in st , now the pointer is somewhere. And this is somewhere displayed on the console, and the squeak is the output of the character with code 7, it seems that the sound should output ( \b ) ... In a word, what was required to show :) - Harry

Your program causes classic undefined behavior. And not some kind of conceptual, but quite real and almost unpredictable. Why are you surprised that the manifestations of this behavior are different in the debug and release versions of the code?

(I, for example, in VS2015, the debug version of your code does not throw out any error, but simply “breaks” cout when you call Print() , after which it refuses to output anything at all.)

The fact that the release code (both your own and the standard library code) will be radically different from the debugging one due to optimizations alone, I hope, is not necessary to explain. And how this release code will depend on so many hard-to-predict variables that trying to look for some deterministic explanation here is a waste of time.

It is also not clear what kind of “swallowing the exception” you are talking about. There are no exceptions in this code.