Will using goto leak variables?
Warning: This answer pertains to C++ only; the rules are quite different in C.
Won't
x
be leaked?
No, absolutely not.
It is a myth that goto
is some low-level construct that allows you to override C++'s built-in scoping mechanisms. (If anything, it's longjmp
that may be prone to this.)
Consider the following mechanics that prevent you from doing "bad things" with labels (which includes case
labels).
1. Label scope
You can't jump across functions:
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..] The scope of a label is the function in which
it appears. [..]
2. Object initialisation
You can't jump across object initialisation:
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
If you jump back across object initialisation, then the object's previous "instance" is destroyed:
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
int x = 0;
lol:
T t;
if (x++ < 5)
goto lol;
}
// Output: *T~T*T~T*T~T*T~T*T~T*T~T
[n3290: 6.6/2]:
[..] Transfer out of a loop, out of a block, or back
past an initialized variable with automatic storage duration involves
the destruction of objects with automatic storage duration that are in
scope at the point transferred from but not at the point transferred
to. [..]
You can't jump into the scope of an object, even if it's not explicitly initialised:
int main() {
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘std::string x’
... except for certain kinds of object, which the language can handle regardless because they do not require "complex" construction:
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:
It is possible to transfer into a block, but not in
a way that bypasses declarations with initialization. A program that
jumps from a point where a variable with automatic storage duration
is not in scope to a point where it is in scope is ill-formed unless
the variable has scalar type, class type with a trivial default
constructor and a trivial destructor, a cv-qualified version of one of
these types, or an array of one of the preceding types and is declared
without an initializer. [..]
3. Jumping abides by scope of other objects
Likewise, objects with automatic storage duration are not "leaked" when you goto
out of their scope:
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
On exit from a scope (however accomplished), objects
with automatic storage duration (3.7.3) that have been constructed in
that scope are destroyed in the reverse order of their construction.
[..]
Conclusion
The above mechanisms ensure that goto
doesn't let you break the language.
Of course, this doesn't automatically mean that you "should" use goto
for any given problem, but it does mean that it is not nearly as "evil" as the common myth leads people to believe.
Will using goto cause memory leaks?
No, you will not cause a memory leak. Using a goto
is not "exiting loops improperly." It's just not generally recommended from a code-structure point-of-view.
That aside, when you leave the loop, the local variables will go out of scope and be popped off of the stack (i.e. cleaned up) in the process.
Using goto after a variable declaration at block scope in C
Not possible to answer for certain; however most compilers allocate all the memory for the function at once.
As a practical matter, if it's gone out of scope, accessing a pointer to it is a bad idea and otherwise you don't care. Even at -O0
, the memory for an out-of-scope variable might be reused.
In no case will the local variables leak. The stack will not become imbalanced. There is nothing dangerous in the code in the question.
Is everything cleaned up when using 'goto'?
Yeah, it gets cleaned up. Because C++ frees variables that go out of scope.
Can `goto LABEL` cause a memory leak?
After 1 minute of testing, the answer seems to be: yes no (see update below)
Watching top
while this is running, %MEM
continually increments
{
THIS:
my $x = 1;
goto THIS;
}
This does not exhibit the same incrementing %MEM
counter
while (1) {
my $x = 1;
}
UPDATE
I misunderstood the question. My take on the question was whether memory would be allocated for a lexical variable that already existed in that lexical scope with the use of a goto
, and my test seems to say yes. Strictly speaking, this is not a memory leak. Should perl ever exit this lexical scope, the allocated space would be released.
If program exits loop by goto are local variables deleted?
Will be deleted. The variable goes out of scope and hence destructor is called (and memory freed) This is guaranteed even if you exit this way:
for(int i=0; i<10; i++)
{
vector <int> v;
for(int j=0; j<1000000; j++) v.push_back(j);
throw std::runtime_error("xyz") ;
}
Is using goto a legitimate way to break out of two loops?
return
is a "structured" goto
which many programmers find more acceptable! So:
static int findit(int sum, int* pa, int* pb, int* pc)
{
for (int a = 1; a<sum; a++) {
for (int b = 1; b < sum; b++) {
int c = sum-a-b;
if (a*a+b*b == c*c) {
*pa = a; *pb = b; *pc = c;
return a*b*c;
}
}
return -1;
}
int main() {
int a, b, c;
const int sum = 1000;
int result = findit(sum, &a, &b, &c);
if (result == -1) {
std::cout << "No result!" << std::endl;
return 1;
}
std::cout << "a:" << a << std::endl;
std::cout << "b:" << b << std::endl;
std::cout << "c:" << c << std::endl;
std::cout <<"Result:" << result << std::endl;
return 0;
}
The effect of a goto statement in C++ on the stack
This program:
#include <iostream>
class X {
public:
X() { std::cout << "ctor" << std::endl; }
~X() { std::cout << "dtor" << std::endl; }
};
int main(int argc, char** argv) {
int i = 0;
label:
X a;
if (i == 0) {
i = 1;
goto label;
}
return 0;
}
Produces this output:
$ ./a.out
ctor
dtor
ctor
dtor
C usage of goto
goto
is rarely the right solution for control flow. While there are valid use cases for goto
, in this particular function you could simply restructure the control flow into if-else
branches like this:
void do_stuff(int value)
{
int errorCode = 0;
if (state1 == 1)
{
errorCode = -1;
}
else if (state1 == 2 && switch2)
{
errorCode = 2;
}
else // unconditional case for no errors
{
printf("No error!");
return;
}
printf("%s", errorCode); // if control reaches here, print the error
}
Related Topics
Getting Std :: Ifstream to Handle Lf, Cr, and Crlf
Why Must the Copy Assignment Operator Return a Reference/Const Reference
How to Sort Two Vectors in the Same Way, With Criteria That Uses Only One of the Vectors
Why Does Integer Overflow on X86 With Gcc Cause an Infinite Loop
How Does C++ Linking Work in Practice
What Is the Partial Ordering Procedure in Template Deduction
Tellg() Function Give Wrong Size of File
Capturing Stdout from a System() Command Optimally
C++: Catch a Divide by Zero Error
Is C++ Context-Free or Context-Sensitive
Dynamic_Cast and Static_Cast in C++
Proper Stack and Heap Usage in C++
How to Make Cmake Output into a 'Bin' Dir
C++11 Reverse Range-Based For-Loop