Is "Lucky" valid pointer data to local map returned data?

In my C ++ program, I have a function that returns a map containing elements, each of which may have a pointer to another element on the map. I set these pointers before returning the map at the end of the function. Code example:

#include <iostream> #include <map> #include <string> class TestObject{ public: TestObject(std::string message) : message(message), other(nullptr){} TestObject* other; std::string message; }; std::map<std::string, TestObject> mapReturningFunction(){ std::map<std::string, TestObject> returnMap; TestObject firstObject("I'm the first message!"); returnMap.insert(std::make_pair("first", firstObject)); TestObject secondObject("I'm the second message!"); returnMap.insert(std::make_pair("second", secondObject)); TestObject* secondObjectPointer = &(returnMap.at("second")); returnMap.at("first").other = secondObjectPointer; return returnMap; } int main(){ std::map<std::string, TestObject> returnedMap = mapReturningFunction(); std::cout << returnedMap.at("first").other->message << std::endl; // Gives a valid message every time std::cin.get(); return 0; } 

At the function call node, the other pointer is still valid, although I suspected that it would become invalid because the map is inside the function from which the “directional object” is an element of blanking the area.

Is this basically the same as mentioned in Is it possible to access a local folder outside its area? ? I was mostly "lucky", does the pointer still point to reliable data? Or is something else happening?

I really think that this is a “successful” hit every time, but some confirmation will be very pleasant.

+8
c ++
source share
5 answers

Yes, you are "lucky" (not so much, your program will work sooner or later or do something bad).


Explanation

returnMap is allocated on the stack: it will be destroyed when the mapReturningFunction returns.

You take the address of the object inside the map and assign it as a pointer to other .

When your function returns, returnMap copied to the return value, so now the (copied) pointer points to garbage.

The optimizer often avoids this last copy, it is called " copy elision " (or "Return Value Optimization" ) and may be the cause of your "normal" behavior. But it doesn’t matter, your program has undefined behavior .

+3
source share

This is not good luck. You are returning a pointer to a location on the stack. The place is valid, and it has the last meaning that has been put there until something else changes it.

Here is an example, and I borrow an idea from another question that you are linking too, which is exactly the same:

 #include <stdio.h> int* foo() { int a = 5; return &a; } void nukestack() { int a = 7; printf("putting 7 on the stack\n"); } void main() { int* p = foo(); printf("%d\n", *p); nukestack(); printf("%d\n", *p); } 

Printing from the program will be as follows:

 5 putting 7 on the stack 7 

The reason is this. First we call foo (), which allocates space on the stack for variable a. We write 5 to this place, then return from the function, freeing this stack space, but leaving the memory intact. Then we call nukestack (), which allocates stack space for its own variable a. Because the functions are so similar and the variables are the same size in both functions, their memory locations happen to overlap.

At this point, the new variable will still have the old value. But we are now rewriting 5 with 7. We are returning from the function, and our old pointer p still points to the same place where there is now 7.

This behavior is undefined, and you technically break the rules if you rely on it. With most compilers, you will also receive a warning when you return a pointer to a local variable, and warnings should never be ignored.

+1
source share

Yes, it’s just “lucky." You get undefined behavior by storing a pointer to the element of the map that was destroyed. This is not quite the same as holding a pointer to a local map, because map elements are allocated dynamically, but here it comes down to the same result.

It is not so simple to actually force a crash or other "wrong" behavior here. This is probably due to optimization of the return value, i.e. A copy of the card is canceled, so the source is not overwritten.

But in VC ++ 2013 the following works:

In mapReturnFunction change the return statement to

 return true ? returnMap : returnMap; 

Oddly enough, this trick will disable the optimization of the return value, resulting in an actual copy being made. Compiled with /EHsc /Za (although neither of these two flags should have any meaning here), the result on my machine is that nothing is printed.

The fact that the observed behavior changes so dramatically with a statement that makes no difference gives you a strong hint that something is terribly wrong.

+1
source share

You were unlucky. Copy permission or move controls (C ++ 11) will prevent the destruction of the original data. While the former is an optional compiler optimization, the latter will (if the former is not applicable) create a relocated version of the original without invalidating the links.

Remember that as soon as you make a copy (without moving) and the original is destroyed, pointers to other elements are invalid!

+1
source share

Pre C ++ 11 , you're in luck. The code is likely to work due to copy Skips , in particular, NRVO (Named Return Value Optimization) means that returnMap and returnedMap are actually the same object. However, you are not allowed to trust this, so the code causes undefined behavior .

Post C ++ 11 , you are "lucky", but even more so. The map has a move constructor, and return returnMap; implicitly moves the local returnMap as a prvalue , which can then be used for the returnedMap move constructor. The compiler can still handle this, but you are allowed to rely on a relocatable local value. However, the standard does not give quarantees what exactly happens when the container moves, so that you still invoke undefined behavior , but that possible changes once the LWG open issue 2321 is allowed.

+1
source share

All Articles