Are all variables within a C++ function pre-initialized when the function is called, regardless of where they are declared? I ask this as I would like to know if exiting a function before the entire function has been executed would lead to memory leaks of variables declared after a return statement. For instance:
string oddOrEven(int a)
{
if ((a % 2) != 0)
{
string odd{ "the number is odd" };
return odd;
}
else
{
string even{ "the number is even" };
return even;
}
}
This piece of code is just for demonstration purposes.
If it were an odd number that was handed to the function, would the string even{} never be created? Because if it were to be created, wouldnt that mean that the string will become a memory leak when the function was exited in the first part of the if-else block?
The string even is local to the else block and wouldn't be created if a had been odd.
NOTE: Local variables, even those declared directly inside a function, are NOT auto-initialized; only global variables declared outside all functions are auto-initialized..
REFERENCES:
http://www.tutorialspoint.com/cplusplus/cpp_variable_scope.htm
From the URL below: "A local variable declared inside a conditional (block) will go out of scope at the end of the conditional."
Scope of variables in if statements
Once your program leaves the function oddOrEven(int a), all of the local variables of that function are destroyed and returns your string
If it were an odd number that was handed to the function,the string even{} never be created.
The point that the other answers are trying to address is that ALL local variables including either odd or even are destroyed on exit from the scope in which they are created.
odd (or even) is NOT what is returned from the function. What is returned is a temporary copy of odd or even and the caller knows to delete this copy.
Note: this is ignoring Return Value Optimization (RVO) because that would only make the situation more confusing.
Related
int main()
{
int x;
int x;
return 0;
}
This snippet will give an error:
error: redeclaration of 'int x'
But this one, works just fine:
int main()
{
while(true)
{
int x;
{...}
}
return 0;
}
Which is the reason why in the second example, declaring x in the loop does not redeclare it every iteration? I was expecting the same error as in the first case.
You're smashing together two related but different concepts and thus your confusion. But it's not your fault, as most of the didactic material on the matter doesn't necessarily make the distinction between the two concepts clear.
Variable scope: This is the region of the source code where a symbol (a variable) is visible.
Object lifetime: this is the time during the runtime of the program that an object exists.
This brings us to other two concepts we need to understand and differentiate between:
A variable is a compile-time concept: it is a name (a symbol) that refers to objects
An object is an "entity" at runtime, an instance of a type.
Let's go back to your examples:
int main()
{
int x{};
int x{};
}
Here you try to declare 2 different variables inside the same scope. Those two variables would have the same name inside the function scope, so when you would "say" the name x (when you would write the symbol x) you wouldn't know to which variable you would refer. So it is not allowed.
int main()
{
while(true)
{
int x{};
}
}
Here you declare one variable inside the while body scope. When you write x inside this scope you refer to this variable. No ambiguity. No problems. Valid code. Note this discussion about declarations and variable scope applies at compile-time, i.e. we are discussion about what meaning has the code that you write.
When we discus object lifetime however we are talking about runtime, i.e. the moment when your compiled binary runs. Yes, at runtime, multiple objects will be created and destroyed in succession. All of these objects are referred by the symbol x inside the while body-scope. But the lifetimes of these objects don't overlap. I.e. when you run your program the first object is created. In the source code it is named x inside the while-body scope. Then the object is destroyed, the loop is re-entered and a new object is created. It is also named x in the source code inside the while-body scope. Then it is destroyed, the while is re-entered, a new object is created and so on.
To give you an expanded view on the matter, consider you can have:
A variable which never refers to an object
{ // not global scope
int a; // <-- not initialized
}
The variable a is not initialized, so an object will never be created at runtime.
An object without a name:
int get_int();
{
int sum = get_int() + get_int();
}
There are two objects returned by the two calls to the function get_int(). Those objects are temporaries. They are never named.
Multiple objects instantiated inside the scope of a variable.
This is an advanced, contrived example, at the fringe of C++. Just showing that it is technically possible:
{
int x;
// no object
new (&x) int{11}; // <-- 1st object created. It is is named `x`. Start of its lifetime
// 1st object is alive. Named x
x.~int(); // <-- 1st object destructed. End of its lifetime
// no object
new (&x) int{24}; // <-- 2nd object created. Also named `x`
// 2nd object alive. Named x
} // <-- implicit end of the lifetime of 2nd object.
The scope of x is the whole block delimited by the curly brackets. However there are two object with different non-overlapping lifetimes inside this scope.
Declarations don't happen at runtime, they happen at compile-time.
In your code int x; is declared once, because it appears in the code once. It doesn't matter if it's in a loop or not.
If the loop runs more than once, x will be created and then destroyed more than once. It's allowed, of course.
In c++, the curly braces represent the beginning {, and end }, of a scope. If you have a scope nested inside another scope, for example a while loop inside a function, then the previously declared variables from the outer scope are available inside the new loop scope.
You are not allowed to declare a variable with the same name inside the same scope twice. That's why the compiler creates the first error
error: redeclaration of 'int x'
But in the case of the loop, the variable is only declared once. It doesn't matter that the loop will reuse that declaration multiple times. Just like a function being called multiple times doesn't create a redeclaration error for the variables it declares.
Variables in loops stay in loops, and are not redeclared. This is because, to the best of my knowledge, Loops are just sets of instructions with jump points, and not actually the same code in the .exe file written over and over again.
If you try to make a for loop:
for(int x = 0; x < 10000; ++x);
The loop just reuses the same variable, then removes the variable after use. This is helpful so that loops, and do{}while(condition)'s can actally hold values, and not just have to redeclare, and reset each variable.
Back to the original question, I am going to ask my own: Why are you trying to redeclare a variable? You could just do this:
int main(void){
int variable = 0;
...
variable = 2;
}
Instead of this:
int main(void){
int variable = 0;
...
int variable = 2;
}
Curly brackets in C/C++ represent blocks of code. These blocks of code do not transfer information to other blocks. I recommend looking further into resources on blocks of code, but one resource has been linked here.
Unlike code that is written in "interpreted languages", variables require declaration. Moreover, your code is read sequentially in compiled languages.
Block example:
while (true) {
int i = 0;
}
This declaration is stored with the block somewhere in memory.
The storage is assigned to an "int" variable type. This data member has a certain memory capacity. Redeclaring, in essence, tries to override information stored in that particular block. These blocks are set aside at compilation time.
Here I am taking an example of overloading the increment operator:
class Digit
{
int m_digit;
public:
Digit (int value) //constructor
{
m_digit = value;
}
Digit& operator++();
int ret_dig (){return m_digit;}
};
Digit& Digit::operator++()
{
if (m_digit == 9)
m_digit = 0;
else ++m_digit;
return *this;
}
int main ()
{
Digit my_dig (5);
++my_dig;
return 0;
}
I have been told that local variables can't be returned. Isn't "this" a local variable? Here is what I think:
A pointer of type Digit is attached to the member function (overloaded operator function). When compiler sees the line ++my_dig, that is an instance of Digit class, it calls the member function. The address of the instance my_dig is passed as argument to the function and there is a hidden "const Digit*" named "this" to catch the argument. "this" is dereferenced(implicitly) to access m_digit, that is a member variable of class Digit. All the increment or wrapping is done inside the function and a reference to dereferenced "this" is then returned to the caller. Yes, this is the point to my confusion. If "this" is a local variable of type const Digit*, shouldn't it contain garbage when returned because "this" is going out of scope where the block ends haaa?
this is an implicit parameter to all member functions which points to the object itself -- which has a strictly longer lifetime than the method. The parameter itself is a local variable, but the object that it points to exists outside the method.
In this case the object is created on the first line of your main function and then lives until the main method exits. Thus the object is safely alive throughout the call to operator++!
The *this is the object and not a local variable. Any temporary objects which the compiler deems necessary to allocate, such as those needed to complete a expression, has a lifetime to the end of the expression.
This becomes interesting for objects which has a destrctor, as the destructor run not when the individual parts of the expression is completed, but when the entire expression completes -- hence your *this variable will survive just sufficiently long to complete what is needed.
Have a look at this question for deeper discussion
this is a local variable, but it is initialized by &my_dig when it enters the method. The value of &my_dig has the same lifetime as my_dig, which ends at the end of the main block. So while this goes out of scope, the value of this is still valid.
I capture local bool value by reference to lambda and the first time it gets captured the value is unassigned (some random value). Why?
bool singleConfirmed=false;
button->addTouchEventListener([text, &singleConfirmed](Ref*, Widget::TouchEventType type)
{
if (type != Widget::TouchEventType::ENDED) return;
if (!singleConfirmed)
{
cocostudio::ActionManagerEx::getInstance()->playActionByName(R_tutorialDialog.c_str(), "MoveToTop");
text->setString(G_str("Tutorial_Single/Multiplayer"));
singleConfirmed=true;
return;
}
else
{
cocostudio::ActionManagerEx::getInstance()->playActionByName(R_tutorialDialog.c_str(), "SwipeToLeft");
text->setString(G_str("Tutorial_Single/Multiplayer"));
return;
}
});
There's not quite enough context in the provided code to be certain, but as sharth hinted in the comments, the problem is almost certainly that singleConfirmed is an automatic, local variable that has gone out of scope (been destroyed) by the time the lambda is invoked, which means the lambda will be working with a wild reference. To solve this, you need to use something that won't be destroyed when the scope exits. That means dynamic allocation. Dynamic allocation means you'll need to deallocate when the lambda is destroyed. The simplest way to ensure that is to use a smart pointer. Putting that all together, my suggestion is to store the bool in a shared_ptr and capture it by value:
auto singleConfirmed = std::make_shared<bool>(false);
button->addTouchEventListener([text, singleConfirmed](Ref*, Widget::TouchEventType type)
{
// ...
}
(text appears to be some sort of pointer that you're capturing by value, so that should be ok as long as it doesn't get deleted before the lambda goes away)
As swarth's and dlf's comment suggest, the lambda is almost certainly being run outside the scope of the local variable singleConfirmed. The name of addTouchEventListener strongly suggests that the function object will be stored and executed in response to some user event later, and not executed now synchronously.
When a lambda is going to be executed out of the scope in which it was created, it doesn't make sense to capture variables by reference, because those variables are going to be out of scope by the time it's executed, and therefore, using the reference is invalid.
Instead, you should capture by value. However, by default, value-captured variables are const, so you cannot assign to it inside the lambda, as it seems you want to do here. You need to declare the lambda mutable to make the value-captured variables non-const:
bool singleConfirmed = false;
button->addTouchEventListener(
[text, singleConfirmed](Ref*, Widget::TouchEventType type) mutable {
// everything in here stays the same
})
I know that returning temporary variables using references doesn't work since the temporary object is lost after the function terminates, but the following piece of code works since the returned temporary is assigned to another object.
I assume the temporary objects get destroyed after the line of function call. If it is so, why isn't this working for this kind of method chaining?
Counter& Counter::doubler()
{
Counter tmp;
tmp.i = this->i * 2;
return tmp;
}
int main()
{
Counter d(2);
Counter d1, d2;
d1 = d.doubler(); // normal function call
std::cout << "d1=" << d1.get() << std::endl; // Output : d1=4
d2 = d.doubler().doubler(); // Method chaining
std::cout << "d2=" << d2.get() << std::endl; // Output : d2=0
return 0;
}
If a function returns a reference to a local object, the object will be destroyed as soon as the function returns (as local objects are). It does not persist to the end of the line of the function call.
Accessing an object after it has been destroyed will yield unpredictable results. Sometimes it may work, for some definition of "work", and sometimes it may not. Just don't do it.
Counter& doubler()
{
Counter tmp;
tmp.i=this->i*2;
return tmp;
}
It's undefined behaviour. After return from function - your reference will be dangling, since Counter destructor will be called for local object tmp.
The real question is not "why this kind of method chaining is not working?", but instead "why the first ('normal') function call works?"
The answer is there's no way to tell, because it might as well break your program.
To state it clearly: returning temporary object by reference is undefined behavior. Which, of course, means that it might work by coincidence today and stop working tomorrow. All bets are off.
When a function returns and stack roll back happens it is logical rollback the stack pointer is set with different value. If a function returns a local variable reference then memory location pointing to local may still be with process and has same bits set. However this is not guaranteed and after few more calls will not be valid and may result in undefined behavior.
Other are all right, in that 'just do not fiddle around with references to local objects'
But as to why it works in one case and not in other
When you call it singly, and when the function returns, the object is still lying on the stack. Granted a 'destructed' object - but whatever space the object used to take is still there on the stack. If you have a simple object, like with a single int member, then there is NOTHING disturbing it on the stack, unless you code allocated something else on the stack, or the destructor decided to do a much thorough job and obliterate an integer member (which most destructors do not do). Granted yada yada, but till the very next line not much is going to happen that would move it from the stack. Your reference is pointing to a valid memory location and your (destructed) object would be there. That is why it works for you.
When you call it chained, see the first call returns you a reference to that tmp on the stack. As explained in #1 above, no problem so far. Your (destructed) tmp is still very much there on stack. But notice the moment you call that second doubler. Where is the tmp inside that second doubler function call going to come up? Right where the tmp from your first call was!!! The second call overwrites the object (the tmp with value 4) with a tmp with value 0 (the default constructed one). The second call is in effect made on a Counter which has 0 value, hence you get 0. Extremely tricky - that is why just forget about fiddling with returning references to local variable.
Now Purists may scream - undefined, no no just don't do it - and I am with them - I have myself said twice (now thrice) that do not do it. But people may try it. I bet for a 'simple' object like the following, AND code exactly as in the question (so as to nothing is disturbing the stack), everyone is going to get consistent 4, 0 - no randomness, no undefined ....
class Counter
{
public:
Counter()
{
i = 0;
}
Counter(int k)
{
i = k;
}
int get()
{
return i;
}
int i;
Counter& doubler();
};
bool SomeClass::Function( bool thankYou = true )
{
static bool justAbool = false;
// Do something with justAbool;
...
}
I have searched around but I can't find anything about this except globals vars or member functions itself.
What does the above do, i.e. what happens, does justAbool keep its value after leaving the scope? Or does it 'remember' the value when it re-enters the scope?
The variable justAbool is initialized to false only once and it is initialized before the function is entered. The value will be remembered after leaving the scope of the function. It is important to note that the value will also be shared by all instances of SomeClass just like a static member variable. The variable justAbool will not be re-initialized if you create a new instance of your class and then call the function again.
static when applied to a local variable gives that variable static storage duration. This means that the justAbool's lifetime lasts to the end of the program rather than to the end of the invocation of the function. It's scope stays the same, it can only be accessed by name in the function, after the declaration appears.
justAbool will be initialized (using the supplied initializer = false) the first time that the function is called. Thereafter it will retain its previous value, it will not be reinitialized when the function is called again.
Here are some fuller details about storage duration and lifetimes, with references to the standard.
If an object has static storage duration, it means that the storage for the object lasts for the duration of the program (beginning to end). (3.7.1 [basic.stc.static])
As a bool is a type without a non-trivial constructor, its lifetime mirrors that of its storage, i.e. it lives from the beginning to the end of the program. (3.8 [basic.life])
All objects with static storage duration (including local objects) are zero-initialized before any other initialization. (6.7/4 [stmt.decl]) [For local objects with an initializer this is fairly academic because there is no way to read their value before their declaration is reached.]
Local objects of POD type with static storage duration initialized with constant-expressions are initialized before their block is entered, otherwise local objects with static storage duration are initialized when control passes through their declaration. (6.7/4 again)
An implementation is permitter, but not required, to perform early initialization in some situations.
The above function does what it does in the comment // Do something with justAbool;.
On a serious note, yes, the static variable (in this case justAbool) inside a function retains it's value even after returning from the function. It gets initialized ONLY ONCE. And each successive calls uses it as if it's a global variable. Its life-time is equal to the end of the program.
int f()
{
static int v = 0;
return ++v;
}
int main()
{
cout << f() << endl;
cout << f() << endl;
cout << f() << endl;
cout << f() << endl;
}
Output:
1
2
3
4
Online Demo : http://www.ideone.com/rvgB5
The justAbool is actually a regular static variable - it exists from the start of the program and is initialized only once. The special thing is that is is known only in this function - if you try and use it outside the function the compiler won't know what it is.
justAbool keeps its value after leaving the scope. What else did you want this code to do exactly?
function level static local variable, the initialization depends on variable types:
POD: initialized before main()
non-POD: initialized the first time, the line in the function is executed.