Scope and return values in C++ - c++

I am starting again with c++ and was thinking about the scope of variables.
If I have a variable inside a function and then I return that variable will the variable not be "dead" when it's returned because the scope it was in has ended?
I have tried this with a function returning a string and it did work.
Can anyone explain this? Or at least point me to some place that can explain this to me please.
Thanks

When the function terminates, the
following steps happen:
The function’s return value is
copied into the placeholder that was
put on the stack for this purpose.
Everything after the stack frame
pointer is popped off. This destroys
all local variables and arguments.
The return value is popped off the
stack and is assigned as the value
of the function. If the value of the
function isn’t assigned to anything,
no assignment takes place, and the
value is lost.
The address of the next instruction
to execute is popped off the stack,
and the CPU resumes execution at
that instruction.
The stack and the heap

When you return a value, a copy is made. The scope of the local variable ends, but a copy is made, and returned to the calling function. Example:
int funcB() {
int j = 12;
return j;
}
void A() {
int i;
i = funcB();
}
The value of j (12) is copied and returned to i so that i will receive the value of 12.

It really depends on what kind of variable you are returning. If you return a primitive then it is returned by copy, not by reference so the value is copied to the top of the stack (or, more often placed into a register) where the calling function can get it. If you allocate an object or memory on the heap and return a pointer then it doesn't die because it's on the heap, not the stack. If you allocate something on the stack, however, and return it, that would be a bad thing. For instance, either of these would be very bad:
int *myBadAddingFunction(int a, int b)
{
int result;
result = a + b;
return &result; // this is very bad and the result is undefined
}
char *myOtherBadFunction()
{
char myString[256];
strcpy(myString, "This is my string!");
return myString; // also allocated on the stack, also bad
}

Just for a little bit more of a memory-model oriented explanation: when a function is called, a temporary space is made for the function to put its local variables, called a frame. When the function (callee) returns its value, it puts the return value in the frame of the function that called it (caller), and then the callee frame is destroyed.
The "frame is destroyed" part is why you can't return pointers or references to local variables from functions. A pointer is effectively a memory location, so returning the memory location of a local variable (by definition: a variable within the frame) becomes incorrect once the frame is destroyed. Since the callee frame is destroyed as soon as it returns its value, any pointer or reference to a local variable is immediately incorrect.

This depends on the type of the returned item. If you are returning by value, a new copy of the variable is made to return to the caller. I thins case you do not need to worry about object lifetime, but you may need to worry about the costs of copying objects (but please don't prematurely optimze - correctness is much more important):
std::string someFunc( std::string& const s)
{
return s + "copy";
}
If the function is returning a reference, then you need to be careful about what you're returning because it's lifetime needs to extend beyond the function's lifetime and the caller will not necessarily be able todelete it if you're using new to create the object:
std::string& someFunc2( std::string const& s)
{
return s + "reference to a copy"; // this is bad - the temp object created will
// be destroyed after the expression the
// function call is in finishes.
// Some, but not all, compilers will warn
// about this.
}
Of course, returning pointers will have similar lifetime considerations.

The local variable is copied to the return value. Copy constructors are called for non-trivial classes.
If you return a pointer or reference to a local variable you will have trouble---just as your intuition suggested.

Related

Is it undefined to return reference to a function-scoped variable as a value?

Is the code below legal?
int foo()
{
int local = 5;
int& local_ref = local;
return local_ref;
}
If yes, then it's most likely will copy value of local to the return value before destroying local, but why? Neither GCC nor MSVC doesn't complain about this, so probably it's legal... isn't it?
Its valid. The value is copied before both local and local_ref goes out of scope. On the other hand, returning local reference would invoke undefined behavior. By local reference, i mean int& foo(), not the variable local_ref.
Before function is called, the stack frame is created (space on stack for parameters, return value and as part of it, the current program counter is saved). Then during function execution, local variables (local and local_ref) are constructed on stack. Before program counter leave the scope of function, the return value (value) is copied to the functions stack frame and after this, program counter returns to the position stored in stack frame (from where foo was called).
For more information search for stack frame.

C++ new operator scope

So I was writing a piece of code where I used new operator to create an object inside a local scope function and returned the reference as a pointer.
A* operator+(A that){
int sumA = a + that.getA();
int sumB = b + that.getB();
return new A(sumA, sumB);
}
In my thought It would not work because the object was created inside the local scope and should be temporary, but it compiled and ran. Can anyone explain to me about this? I am sure there are other things that kinda have the ability of breaking the scope and stuff.. If possible, could you give me some examples? Appreciated!
When you say "created inside local scope" what you really mean is "an automatic variable." Automatic variables are automatically destroyed when the scope in which they are created is exited from.
But new does not create an automatic variable. It creates a dynamically allocated object, whose lifetime is not bound by the scope in which it's created.
The object created by, new A(sumA, sumB) is not a temporary.
Values are returned from a local scope all the time. For example:
int f(int x)
{
int y = x*x;
return y;
}
While a variable would normally disappear when it falls out of scope, values returned from functions get special treatment by the compiler.
Regarding your example, you are creating an object on the heap and have a pointer to that object on the local stack. When your function returns the stack is cleaned up, that pointer along with it. Except - since you're returning the pointer to the caller, a copy of the pointer is passed back to the caller (probably through a cpu register).
As an aside: While this works fine, you need to be certain that the caller eventually deletes the returned object, else you'll have a memory leak.
C++ does not automatically manage memory for you. This means you must manually 'delete' any objects created dynamically with the 'new' operator. Your code is valid, but I think it doesn't accomplish what you wish. I think you are looking for something like this:
A operator+(const A& that){
int sumA = a + that.getA();
int sumB = b + that.getB();
return A(sumA, sumB);
}
Yes, the value created with new will still be alive after the function exits.
As others have mentioned, it is necessary to delete these objects to avoid memory leaks.
Because of this, best general C++ practice is to not return bare pointers like this function does, but to return some sort of smart pointer object such as shared_ptr. That way, you can return a pointer to the newly created object, and the object will be automatically destroyed once there are no more active references to it.

Returning an address to a local variable vs returning a pointer to a local variable

I have this in my testing.cpp:
class Supp{
public:
virtual Supp* add(Supp& val) = 0;
};
class SubA : public Supp{
public:
int val;
SubA(int a){
val = a;
}
int getVal(){
return val;
}
Supp* add(Supp& value){
SubA& a = dynamic_cast<SubA&>(value);
int tempVal = a.getVal();
int sum = val + tempVal;
SubA b =SubA(sum);
return &b;
}
};
and the lines
SubA b = SubA(sum);
return &b;
gives and error because itreturns the address to a local variable which is very bad to do, so i changed it to
SubA* b =new SubA(sum);
return b;
and it works fine with no errors, But is this not basically the same thing? why is this legal to the compiler but the previous version not?
The reason it's illegal to return the address to a local variable is once the function returns, the local variable ceases to exist, thus you're returning an address which is known to be no longer valid. (The object may still live there but its destructor will have already been called, and the memory it occupied will be used for something else at some point -- perhaps with the very next subroutine call.)
The reason it's ok to return the address returned by new is that address is not pointing to an object that lives in a temporary location (your program stack is where locals are normally placed); rather it comes from heap memory which will persist until you dispose of it. This object doesn't rely on the scope of code it was allocated in since it's not local to that scope.
In the first example, your local variable is allocated on the stack (where all local variables for the duration of their scope) and will be immediately deallocated on returning to the calling function. As such, the pointer returned will be invalid the moment you leave the function.
In the second, you are creating a new object on the heap where it will be retained until you manually deallocate the pointer somewhere else down the line.
Initially misread the question, sorry.
The second works because you're not returning by reference, but by value. If the signature was
Supp*& add(Supp& value)
then the second would be illegal as well.
Keep in mind that objects with automatic storage duration get destroyed at the closing }. So after the functions return, the object b is no longer accessible. Copies of it are. If you return by value, the original goes away, but you're left with the copy.

Returning an Object and Scope

I was working on a fraction class as a CS assignment, and wrote the following code:
fraction fraction::add(fraction other) {
fraction temp;
/* manipulate temp */
return temp;
}
This worked perfectly, creating a new fraction object and then returning it to the calling code.
The question is, why did this work? My fraction temp should go out of scope when the add method returns and thus be destroyed, but it is passed back out to the calling code without so much as an error.
Why does returning something with local scope cause it to continue to exist after it goes out of scope?
You're returning the value of temp, not the temp object itself. The value gets copied and returned to the calling function, the fact that temp then gets destroyed is irrelevant, here.
It's like this:
int a;
{
int b = 5;
a = b;
}
std::cout << a << std::endl;
After the closing brace, b has gone out of scope, but a still contains the value 5, and is fine. Approximately the same thing is happening for your function call.
If you return a pointer to a local object, it's a very different story. Attempts to dereference that pointer will invoke undefined behavior, since you're trying to access an object which no longer exists. But when you're just using the returned value, it doesn't matter whether that object exists or not, because you just have your own copy of the value it used to contain, at that point. (Technically it's still returning by value, here, and the pointer in the calling function will just contain its own copy of the address at which the local object used to reside - you just can't do anything useful with it, because the lifetime of the object that used to reside at that address has ended.)
It doesn't continue to exist. You are returning by value temp is copied (or moved in C++11) into whatever the return value of the function is assigned to, then temp goes out of scope and is destroyed.
Or, on most modern compilers where Return Value Optimization is implemented, temp will actually be the same as the object you're assigning the return value of the function to wich won't have gone out of scope yet.
Looking at a simple example
fraction value;
fraction other_value;
fraction returned = value.add(other_value);
When value.add(other_value) is called it constructs temp in the member function's scope, then once it reaches the line return temp;, temp is copied into returned which is in the callers scope. Now the return statement has completed, the function ends, temp goes out of scope and is destroyed.
In the case of RVO, temp and returned are actually the same object and no copy is performed at all.

Temporary variables created when using const reference

I am making some matrix class and I was wondering when a temporary object is created it is local to the function right? so it should get out of scope when function return but I don't know why that don't happen in this case I can use it after the function have returned.
Here is an example, this is the constructor:
int *data; //member of class
Matrix3(const int (&ar)[N*N])
{
data = const_cast<int*>(ar);
}
and here is how I use it:
Matrix3 m = { {1,2,3,4,5,6,6,6,6} };
Now I can still access that object from the destructor through the data pointer is this normal? the temporary variable is created on the heap then?!
The lifetime of a temporary ends at the semicolon of the statement or declaration that introduced it, not at the end of the function. (Otherwise, an innocuous loop could easily cause a stack overflow.)
If you use a reference to an object after its lifetime has ended (such as the array here), then you get undefined behavior. C++ does not keep track of dead objects in order to tell you when you are using one. You happen to find the information from the dead array. But something else could have reused the memory, or it could have been returned to the system and you could get a segfault.
Avoid dangling references and pointers. Do not suppose that if it works in a test-case, that it works in the field.
After your line executes, the temporary array is destroyed and the data pointer becomes invalid.
int *data; // is a member, so it goes out of scope when the object is destroyed
However, if you declared it in a function like this:
void someFunction() {
int *data;
}
// pointer is lost now and is inaccessible