What is bad on using goto statement???
I often heard:"if you use goto,you can't make good programs.."
What do you think about it?
I think you are better programmer when you can use goto statement then somebody who can't use it...;)
Printable View
What is bad on using goto statement???
I often heard:"if you use goto,you can't make good programs.."
What do you think about it?
I think you are better programmer when you can use goto statement then somebody who can't use it...;)
I was also taught Goto statements are bad. They are evil constructs that allow program flow to just jump practically anywhere.
But I do use them once in a GREAT while. Why? Lets say you have a method that is allocating a bunch of resources/memory. And at anypoint, you could receive a error condition. To keep the method clean/readable, I have used a goto statement to jump to the end of the method. This way I have one exit point of the method that frees everything up. Less chances for memory leaks.
Disclaimers:
a) The below is a VERY simple example. Just here for demonstration
b) There are other ways of solving the memory cleanup without using gotos
b1) re-organize without goto
b2) exception handling
b3) smart pointers concepts
void MyFunc()
{
type* p1 = NULL;
type* p2 = NULL;
p1 = new type[50];
if (something bad)
goto FuncExit;
p2 = new type[2];
if (something bad)
goto FuncExit;
do some other code with other possible exit points
FuncExit;
delete [] p1; // works if p1 is NULL;
delete [] p2;
}
I can't think of an example of me using goto in my current project. Buts it there in my bag of tricks.
Let the debate begin.
Honestly, anyone can use goto; that's part of the problem. When
used improperly, goto can lead to circuitous and confusing code.
When used carefully, goto can save time and ... <gasp> ... even
make things more readable. The problem is that everyone has
different opinions on what proper goto usage is. Also, most
things can be done without goto with no problem so more
tradational control structure are preferrable in my opinion.
One instance <I> consider goto useful is if you're in two [or more]
loops .. and from the inner loop, you want to break out to the
outer loop. You could just set the outer loop's terminating
condition to get out of that loop, too.
The big problem with goto and C++ is that goto will skip
destructor calls if you goto a spot that's out of a created
object's scope.
Given the inherent complexity and potential misuse, I don't use
goto. I WOULD use it if I found an instance where I really needed
it ... but I'm usually able to get by just fine with the other features
of the language. The more low-level you get with your
programming, the more useful you might find goto. I try to
program on as high a level as I can most of the time :)
--Paul
Hi gurus,
Generally we do not use goto in our group. We discourage ist use but do not forbid it.
We actually do use goto for improved readibility and clarity when dealing with assembler labels in mixed assembler / C / C++ development of hard real-time operating systems.
There are other flow-control statements such as break and continue. Along the same lines, some radical developers even try to eliminate the use of these (relatively) harmless flow controls. I've got no real opinion here.
Chris.
:)
Paul,
Could you expand on this? I just did a little test code (I had a goto exit a for loop with a variable defined in the for loop) and the destructor got called.Quote:
The big problem with goto and C++ is that goto will skip
destructor calls if you goto a spot that's out of a created
object's scope.
Thanks,
John Flegert
No, no, no (at least, in the C++ world). You have said that there are other ways of solving memory cleanup. Quite right, RAII (Resource Acquisition Is Initialisation) reduces (or eliminates) resource leaks. Do not even suggest the cleanup on exit "solution" - it isn't a solution: don't ever do it. All the points you make under (b) are valid reasons to never use the "cleanup on exit" approach. In fact, b2 is enough on its own:Quote:
Originally posted by Sput
[...] Lets say you have a method that is allocating a bunch of resources/memory. And at anypoint, you could receive a error condition. To keep the method clean/readable, I have used a goto statement to jump to the end of the method. This way I have one exit point of the method that frees everything up. Less chances for memory leaks.
Suppose the "new" at *** throws an exception (like it's supposed to do, VC++ notwithstanding), or the bulk code throws. p1 (and, possibly, p2) does not get deleted - you have a resource leak. The only way to avoid this is to allocate the resource in an object's constructor and release it in the destructor, because the the destructor will always be called.Code:void MyFunc()
{
type* p1 = NULL;
type* p2 = NULL;
p1 = new type[50];
if (something bad)
goto FuncExit;
p2 = new type[2]; ***
if (something bad)
goto FuncExit;
do some other code with other possible exit points
FuncExit;
delete [] p1; // works if p1 is NULL;
delete [] p2;
}
This code is resource safe. No matter how the function exits, the memory grabbed by p1 and p2 will be freed - and any destructors for objects stored in the vectors will be called.Code:void MyFunc()
{
std::vector<type> p1;
std::vector<type> p2;
p1.reserve(50);
p2.reserve(2); ***
do some other code with other possible exit points
and possible exceptions thrown
}
Putting in a goto to a mythical cleanup section gives a false sense of security - it is not safe.
So, the one "use" of goto that you advocate is unsafe and unnecessary.
Paul: I would suggest that goto out of a nested loop reduces readability - others may disagree: I don't want to argue the point. I would also suggest, though, that it indicates a design flaw. I've written some pretty hairy nested loops in my time and (apart from the bad old days of FORTRAN), I've not found a need for goto. in fact, in recent times, I've even managed to avoid break and continue in loops. There are no hard and fast rules, but often factoring out inner loops and conditional sections of loop bodies dramatically increases readability and maintainability. In fact, I'll stick my neck out here: if you want to use a goto, consider refactoring (or using RAII properly) instead.
Graham: Sorry about the example. Thats what the disclaimer was for. Especially the first one (A). I should of given a better (more valid) example. Maybe one not using memory, and one such that all paths don't automatically work. :o :D
Looking at my 30-second-to-write piece of source code, your comments about it are correct. :cool:
The only point I was trying to make is that if you allocate/use resources ( memory or OTHER ) and your method is coded to have multiple exit points, one use of the GOTO statement is to jump to the end and have one place for resource cleanup/release and one method/function exit point. Situations like this usually end up happening due to multiple conditions or loops. (although, you can always take a step back and see if you can restructure the source :) )
oh yea... By other resources, I'm thinking if could be files (close or delete), threads, etc... I don't know. Theres always many ways to solve the same problem. I just don't dismiss the use of Goto. Although, I don't always recommend or use it either.
One question though:
If I understand what you are stating, If you use the smart pointer concept (allocate in constructor, free in destructor) then once the exception is thrown, all destructors in the method are called. Is this true? Or just whats in the Try block. I don't use exceptions that much (nor is it encouraged at my work to do so). Only when calling code that uses exceptions.Quote:
Suppose the "new" at *** throws an exception (like it's supposed to do, VC++ notwithstanding), or the bulk code throws. p1 (and, possibly, p2) does not get deleted - you have a resource leak. The only way to avoid this is to allocate the resource in an object's constructor and release it in the destructor, because the the destructor will always be called.
As far as the smart pointers concept. Thats usually what I do. :) This concept can even be taken as far as to create a template utility classes for selecting GDI objects into the DC (in ctor) and releasing in dtor (destructor). hhmm.. I can vaguely remember dealing with this in complicated c functions (in my sdk days) using Gotos. :o :o
The keyword goto is a there if you need it, so don't be afraid to use it. There are better design implementations possible, though, so if you are looking for something that is consistent and readable, I would look into things like termination handlers. Especially for cleanup routines. Wrapping some code in __try, __finally will help if you don't have any need for strong c++ handling of scope and destructors.
... and my point is that you'll waste an awful lot of time looking for a better or more valid example. There aren't any. The set of situations in which the use of goto is elegant, readable, maintainable and correct is vanishingly small.Quote:
Originally posted by Sput
Graham: Sorry about the example. Thats what the disclaimer was for. Especially the first one (A). I should of given a better (more valid) example. Maybe one not using memory, and one such that all paths don't automatically work. :o :D
... and my point was that it doesn't address the whole problem. You can still leak resources, so do do it properly (with RAII) or don't bother.Quote:
The only point I was trying to make is that if you allocate/use resources ( memory or OTHER ) and your method is coded to have multiple exit points, one use of the GOTO statement is to jump to the end and have one place for resource cleanup/release and one method/function exit point. Situations like this usually end up happening due to multiple conditions or loops. (although, you can always take a step back and see if you can restructure the source :) )
Absolutely - that's why RAII works. As soon as a fully constructed object goes out of scope, for whatever reason (short of something disastrous, in which case it won't matter), its destructor will be called.Quote:
If I understand what you are stating, If you use the smart pointer concept (allocate in constructor, free in destructor) then once the exception is thrown, all destructors in the method are called. Is this true? Or just whats in the Try block. I don't use exceptions that much (nor is it encouraged at my work to do so). Only when calling code that uses exceptions.
RAII is about managing ALL your resources, not just memory. Don't restrict yourself to smart pointers: GDI resources, locks, whatever: if it's a resource that needs managing, RAII handles it. That's why I don't like Garbage Collectors: they may well manage memory, but in the process you lose deterministic destructors, so all the other resources that could have been managed are now subject to leaking. Here's an example that doesn't involve memory at all:Quote:
As far as the smart pointers concept. Thats usually what I do. :) This concept can even be taken as far as to create a template utility classes for selecting GDI objects into the DC (in ctor) and releasing in dtor (destructor). hhmm.. I can vaguely remember dealing with this in complicated c functions (in my sdk days) using Gotos. :o :o
Imagine that in the process of writing to the database, the system throws an exception....Code:class DatabaseLock
{
public:
DatabaseLock(Database* db)
{
// Obtain a lock on the database to prevent concurrent write
db->StopOthersWriting();
}
~DatabaseLock()
{
// Release the lock
db->AllowOthersToWrite();
}
};
void WriteToDatabase(Database* db)
{
DataBaseLock lock(db);
// Write to database
} // Lock released as lock object goes out of scope.
How does the above compare with:
How long will that database stay uncorrupt?Code:void WriteToDatabase(Database* db)
{
db->StopOthersWriting();
// Write to the database
Done:
db->AllowOthersToWrite();
}
you don't need itQuote:
Originally posted by galathaea
The keyword goto is a there if you need it,
I'm not afraid to use it - I choose not to contaminate my code with it.Quote:
so don't be afraid to use it.
AbsolutelyQuote:
There are better design implementations possible, though,
Why?Quote:
so if you are looking for something that is consistent and readable, I would look into things like termination handlers.
Use RAII. What are cleanup routines?Quote:
Especially for cleanup routines.
No such keywords in C++Quote:
Wrapping some code in __try, __finally
I don't understand that last statement - you always have to consider and deal with scope. You may only ever use simple classes that have trivial destructors, but at some point you'll have more complex needs.Quote:
will help if you don't have any need for strong c++ handling of scope and destructors.
That's the problem. It's a very simple concept to use. So simple that a beginner can use it, and feel confident he/she knows what's happening. It's so simple that it might seem like the way to go. I like the "simple is best" approach. I preach the K.I.S.S. principal. That is not the case here.Code:The keyword goto is a there if you need it, so don't be afraid to use it.
I think if you are ever considering using a goto, that you should be afraid. You should step back and take a serious look at it. You should discuss it with a colleague. You should find different solutions, and convince yourself that this is really best. And even then, you should document it heavily. I've spent enough time sifting through old (I mean old) FORTRAN, that gotos make me cringe.
I suppose you could come up with a situation where a goto really does solve the problem better than other solutions. I don't know. I can't think of one, and I have never seen one. That doesn't mean it doesn't exist.
Jeff
Oops :) What I meant was the "goto" concept. Um ... in otherQuote:
Originally posted by jflegert
Paul,
Could you expand on this? I just did a little test code (I had a goto exit a for loop with a variable defined in the for loop) and the destructor got called.
Thanks,
John Flegert
words, there are things called "nonlocal goto's"; these are the
setjmp() or longjmp() functions. If you use THESE functions, your
destructors will not get called [depending, of course, on your
compiler]. So, the 'goto' itself will let destructors be called, but
certain goto constructs won't.
I guess this discussion is about the 'goto' keyword and not the
concept of "goto" statements. Either way, I don't use very many
goto-type statements.
--Paul
Graham said:
That's a reasonable imagination of what could happen. But unfortunately it is NOT TRUE. Don't spread the rumor. Check the fact first, Graham!Quote:
The big problem with goto and C++ is that goto will skip
destructor calls if you goto a spot that's out of a created
object's scope.
I am not sure whether it is in the standard or not. But all compilers I used are smart enough to figure out that a "goto" would jump to an outside scope, and it will call appropriate destructors for objects declared in inside scopes. Same as when you call "return" it will call all appropriate destructors.
And compilers are also smart enough to prevent you from "goto" an inside scope. The only place you can go to are the places within the same scope, or outside current scope but still within the function scope. i.e., you can jump out of a scope but not into a scope.
Oops, my eyes skipped lines. The wrong statement was made by Paul, not Graham.Quote:
Graham said:
You can jump into a scope just fine:Quote:
Originally posted by Anthony Mai
you can jump out of a scope but not into a scope
JeffCode:int main()
{
if( 0 )
{
inner_scope:
return 0;
}
goto inner_scope;
return 1;
}
I did not realize this was the Non Visual c++ forum, so my last post was way off. Coding your own routines in c++ in the style of the termination handler though (all cleanup routines in one exit location) is good style, though, because it allows for easy analysis of completeness. I stand by my "use if needed" statement though, with fists up and ready.
First I have to say I'm a C programmer, ok :cool:
Graham's talk about RAII doesn't seems to solve all problems... If you define a pointer object and later create an instance of it with the new-operator. How does RAII apply to that and what's the difference between RAII and a good old goto? Goto:s unwind the stack and I guess destructors are called then, or?
It seems that many of you think that it's absolutely wrong to use goto:s.. Black or white, black or white... when the color is gray :p
...Just my view.
First I rarely find a need for the "goto" statement. I try to not to use it. Also I rarely find the need of having multiple exit points of function calls. And I try to not to have multiple exit point.
But I only follow those rules as rules of thumbs, NOT rules of principle. It is possible, as a principle, that you can absolutely stay away from both goto and multiple exit point, and use alternative ways of achieving what you want. But some times the price of alternative is just too high to be worth it.
If in a specific situation, a goto statement or multiple exit point seems to be an attractive solution, I would NOT hesitate to use them. I do NOT understand arguments of people who tries to tell people "goto" is the mother of all evils.
First. Usage of goto NEVER implies a design flaw. It never implies any thing good or bad of the design. Usage of "goto" is purely an implementation issue. There is NOT a conceiveable design which would mandate usage of goto, and which can not be implemented without goto. I can't think of any thing like that.
Usage of goto has its pros and cons. Whether to use it or not is purely an implementation decision, based on individual's opinion of the balance of pros and cons. Some claim using goto is a bad design. It is never a design issue. Some claim using goto is error prone. Well programmers make all sorts of mistakes. I don't buy it that using goto automatically means your chance of making an error is significantly higher versus when you don't use it.
Show me some statistical data to back it up if you claim goto is more error prone.
Bottom line is: it is possible to stay away from goto completely and absolutely. But it is not necessary to do so. There are both good or bad use of goto. And when it seems to be a good place to use goto, there is no reason why you shouldn't use it.
Graham:Quote:
... and my point is that you'll waste an awful lot of time looking for a better or more valid example. There aren't any. The set of situations in which the use of goto is elegant, readable, maintainable and correct is vanishingly small.
You have to realize that program code that satisfy elegant, readable, maintainable and correct all 4 conditions simply does not exist. So that's not a problem for just goto statement. Most times you have to settle for 3 out of the 4 you meantioned.
Take this computation task as an example: There are 8 short integers a0, a1, ...a7 and 8 other short integers b0, b1,...b7. I want to multiply each a with b (a0 with b0, a1 with b1, etc), divide the result of multiplication by 32768, and sum them up. And I need to make sure the result stays within the range. What's an elegant solution?
Using C/C++ you probably need to write any where from 10 to 20 lines of code and have to do a bunch of "if" to accomplish it. But using some SIMD assembly instruction I can do the whole thing in just one instruction. So who is the elegant?
Here is an example in which the use of goto is not perfect but is surely more elegant than other solutions. You need to do a switch statement in which depending on the switch value, you have to carry out a combination of tasks a0, a1,...an, and one of either b0 or b1 or b2. And the switch has about 100 differeent cases and you want to do it fast, so you really don't want to do it in two different switch statements. What do you do?
I would do this:
Code:switch (val)
{
case 1:
DoTaskA1();
goto TaskB0;
break;
case 2:
DoTaskA2();
goto TaskB0;
break;
case 3:
DoTaskA3();
goto TaskB1;
break;
case 4:
DoTaskA4();
goto TaskB0;
break;
case 99:
DoTaskA99();
Task_B1:
DoTaskB1();
break;
case 100:
DoTaskA100();
Task_B0:
DoTaskB0();
break;
default:
break;
}
I think we must have posted at the same time. Right before youQuote:
Originally posted by AnthonyMai
Paul said:
That's a reasonable imagination of what could happen. But unfortunately it is NOT TRUE. Don't spread the rumor. Check the fact first, Paul!
posted this, I made another post modifying the post where I
made the "mistake". What I was talking about in that statement
were non-local gotos [and not the goto keyword]. I should have
made that clear [and I thought I did], but oh well: time to take
my lumps :)
--Paul
A good practice to follow when programming in C++ is to not useQuote:
Originally posted by j0nas
First I have to say I'm a C programmer, ok :cool:
Graham's talk about RAII doesn't seems to solve all problems... If you define a pointer object and later create an instance of it with the new-operator. How does RAII apply to that and what's the difference between RAII and a good old goto? Goto:s unwind the stack and I guess destructors are called then, or?
It seems that many of you think that it's absolutely wrong to use goto:s.. Black or white, black or white... when the color is gray :p
...Just my view.
so-called naked pointers like you describe. If you have a pointer
and goto [the keyword] an area where the delete is never
called, you will have a resource leak. If you instead have a class
whose constructor does the new and destructor does the
delete, you won't ever have a resource leak because the
destructor will do the delete when the variable goes out of scope
... whether an exception is thrown or a goto takes you past the
delete or whatever [not the non-local gotos though].
That's the difference.
--Paul
I wholeheartedly agree. This is one of those things that's openQuote:
Originally posted by AnthonyMai
First I rarely find a need for the "goto" statement. I try to not to use it. Also I rarely find the need of having multiple exit points of function calls. And I try to not to have multiple exit point.
But I only follow those rules as rules of thumbs, NOT rules of principle. It is possible, as a principle, that you can absolutely stay away from both goto and multiple exit point, and use alternative ways of achieving what you want. But some times the price of alternative is just too high to be worth it.
If in a specific situation, a goto statement or multiple exit point seems to be an attractive solution, I would NOT hesitate to use them. I do NOT understand arguments of people who tries to tell people "goto" is the mother of all evils.
First. Usage of goto NEVER implies a design flaw. It never implies any thing good or bad of the design. Usage of "goto" is purely an implementation issue. There is NOT a conceiveable design which would mandate usage of goto, and which can not be implemented without goto. I can't think of any thing like that.
Usage of goto has its pros and cons. Whether to use it or not is purely an implementation decision, based on individual's opinion of the balance of pros and cons. Some claim using goto is a bad design. It is never a design issue. Some claim using goto is error prone. Well programmers make all sorts of mistakes. I don't buy it that using goto automatically means your chance of making an error is significantly higher versus when you don't use it.
Show me some statistical data to back it up if you claim goto is more error prone.
Bottom line is: it is possible to stay away from goto completely and absolutely. But it is not necessary to do so. There are both good or bad use of goto. And when it seems to be a good place to use goto, there is no reason why you shouldn't use it.
to a wide amount of interpretation by everyone. Each person has
his own ideas regarding what is acceptable use of the goto
keyword. That's another reason why there was a mass exodus
away from the goto keyword in general: when used badly, the
goto keyword CAN create havoc.
--Paul
Doesn't your argments in favor the GOTO apply to almost every other contriversial C/C++ statement? For example, some people say never use FILE but use streams instead. Or how about the people who swear by templates in place of macros? Or global/static non-class variables. There are a whole host of these. Use, or non-use, of any of these is not a design flaw but largly the preferences of the coder. I feel more comfortable using FILE instead of streams and my programs reflect that.
And yes, there are some rare occasions to use goto -- I've even seen it once or twice in MFC code.
It's not merely a preference. It's a maintenance issue. That's primarily why goto's are considered bad. Because it can be difficult to maintain. If you set a breakpoint after a goto flag, it's harder to determine how you got there. It's one thing to imagine a method with a single goto that goes forward. Now imagine a method with three gotos that go forward and back. This becomes very difficult to deal with.
Preferring FILE to streams is a real maintenance issue. Maybe you are certain that your code does not need to be portable or that you'll always have a good portability tool. However good and true this is, it is still an assumption.
Wether it's a good decision or not to use FILE over streams is not really important to this discussion. My point is that there is more to it than "preference." There is a potential cost to it.
Jeff
I've seen badly nested if's, do/while, and horrendous looking branched recursive function calls. Does this mean that these language features are bad or that they have been used badly?
In my opinion, it'd mean that the feature was used badly. TheQuote:
Originally posted by galathaea
I've seen badly nested if's, do/while, and horrendous looking branched recursive function calls. Does this mean that these language features are bad or that they have been used badly?
problem with the goto keyword is that it's a lot more flexible
than other commands. Everyone seems to have their own
interpretation on what is "proper" when it comes to the goto
keyword. Because of that, it's hard to quantify whether or not
a particular usage is a poor decision.
doesn't everyone have their own interpretation on what is proper if/do/while nesting or proper branched recursion style? I've seen several different styles of each. Shouldn't we just say, is this readable and maintainable. Period. Without the taboos.
I really miss the setjmp() and longjmp() -- they're like goto but can jump to anywhere within the program, while goto is limited to the function in which it is used. If you have a hard time following a goto, you ought to try figuring out where a longjmp() is going to go!! If there is only one setjmp, then its pretty easy.
Maintenance issue exists for all language features and I don't see how goto is special. It's all up to how you use it. You can do a wild goto and jump to some place never expected and it's going to be headache. You can throw in 10 different "return" here and there and some resorces never gets cleaned, and it's going to be a headache. If that happens, blame on the person who inproperly used the language feature, not the language feature itself.Quote:
It's not merely a preference. It's a maintenance issue. That's primarily why goto's are considered bad. Because it can be difficult to maintain.
goto can be used in a pretty elegant, well structures, and quite maintainable way. It's up to how you use it.
Would you be able to figure out how you get there if you set a break point right after a long loop which contains quite a number of different places where "break" is called upon various conditions? You can't either.Quote:
If you set a breakpoint after a goto flag, it's harder to determine how you got there.
As a matter of fact, if you simply replace all the "break" with a "goto" that go to the line right after the loop, chances are the compiled code will look exactly the same and contain the same assembly code.
If one has a legitimate reason to go backwards. What's wrong with goto backwards? If one does not have a good reason to go backwards, why would one goto backwards just for the sack of goto backwards?Quote:
It's one thing to imagine a method with a single goto that goes forward. Now imagine a method with three gotos that go forward and back. This becomes very difficult to deal with.
One legitimate use of goto backwards goes like this:
A side note. One language feature that I find totally unacceptable, and causes maintenance problem, is the C++ exceptions.Quote:
start_calc:
for (i=0; i<1000; i++)
{
for (j=0; j<1000; j++)
{
for (k=0; k<1000; k++)
{
Manipulate Data[i][j][k];
// If some condition raises and we have to re-start
// the calculation again.
if (Something_Goes_Wrong)
{
goto start_calc;
}
// If we have found what we want and there is no need to continue.
if (We_are_all_done_already)
{
goto end_calc;
}
}
}
}
end_calc:
Exceptions are bad because higher level code never knows who will throw exceptions and from where and under what condition. And the one who throw exceptions never knows who will catch them and where it will be catched and under what circumstance it will be catched. Such uncertainly is the worst enemy in programming.
We see so many uncatched exceptions in day to day code, and even more exceptions caught at wrong places! "Unhandled exceptions" can be accounted for a great portion of all crashing software bugs.
Even worse, C++ exceptions are some sort of contageous decease. A function that does not throw any exceptions at all itself, could be a function that actually throws exception, if amoung the functions it calls, some do throw exception, or if the functions it calls do not catch exceptions from lower level code.
So it is contagenous. And you become an exception throwing function without you even realize it.
Worse of all, no one bothers to catch exceptions. It would be ideal if wheneve you call some exception throwing function (which is basically every thing), you need to wrape the call in a try/catch block. For example when you call new. But no one does it.
Some claim he can "strategically place a few try/catch here and there", and it will catch all exceptions. First that is impossible to do. Second, it is impossible to maintain, since if the code changes, your strategically placed try/catch may need to strategically re-positioned. It is as tough as trying to catch the DC sniper or trying to catch Ben Laden. You simply can not do it with a few dozen or so soldiers "strategically" placed here and there.
Exceptions are evil.
No offence, but the above code is a poor execuse for justifying a goto statement.Quote:
switch (val)
{
case 1:
DoTaskA1();
goto TaskB0;
break;
case 2:
DoTaskA2();
goto TaskB0;
break;
case 3:
DoTaskA3();
goto TaskB1;
break;
case 4:
DoTaskA4();
goto TaskB0;
break;
case 99:
DoTaskA99();
Task_B1:
DoTaskB1();
break;
case 100:
DoTaskA100();
Task_B0:
DoTaskB0();
break;
default:
break;
}
You can easily accomplish the samething by adding another switch statement, and the code would look more readable, and be easier to follow.
Example
I can find absolutely no excuse for needing a goto statement.Code:
int main(int argc, char* argv[])
{
int SecondTask = 0;
enum {Task_B0 = 1, Task_B1 = 2};
switch (argc)
{
case 1:
DoTaskA1();
SecondTask = Task_B0;
break;
case 2:
DoTaskA2();
SecondTask = Task_B0;
break;
case 3:
DoTaskA3();
SecondTask = Task_B1;
break;
case 4:
DoTaskA4();
SecondTask = Task_B0;
break;
case 99:
DoTaskA99();
SecondTask = Task_B1;
DoTaskB1();
break;
case 100:
DoTaskA100();
SecondTask = Task_B0;
break;
default:
break;
}
switch(SecondTask)
{
case Task_B1:
DoTaskB1();
break;
case Task_B0:
DoTaskB0();
break;
}
return 0;
}
I've been programming in C/C++ since 1987.
In my first year of programming, when I didn't know any better, I did use goto's. The fact that my first language was BASIC, may it that much more tempting to use goto’s.
Since my second year of programming in C/C++ (1988) I have not found a single situation in which I had to use a goto statement.
I have not run into any condition in which I thought, “Wow! …. A goto statement would work so much better here!”
The use of goto’s too often results in spaghetti code, that is hard to read, and hard to maintain.
My advice is NEVER, NEVER, NEVER use a goto statement….. There always a better non-goto method to accomplish the same thing or better.
It’s not required for C/C++ programming, and your code will be easier to follow and easier to maintain without it.
Absolutely agree.Quote:
Originally posted by Axter
I have not run into any condition in which I thought, “Wow! …. A goto statement would work so much better here!”
The use of goto’s too often results in spaghetti code, that is hard to read, and hard to maintain.
My advice is NEVER, NEVER, NEVER use a goto statement….. There always a better non-goto method to accomplish the same thing or better.
It’s not required for C/C++ programming, and your code will be easier to follow and easier to maintain without it.
(Slightly OT, but...) Was there ever a greater abomination in a coding language than VB's "On Error GoTo"? On those occasions when I have to debug VB code, I break out into a cold sweat whenever I see that, because I just know that I'm going to find myself suddenly warping to a different place in the source with only a vague idea of where I came from.
Can any one dispute the legitimate use where you use a GOTO to break out of several nested loops. It is definitely more concise and more readable than using multiple "break"s to achieve the goal.
In principle, there is nothing that must be accomplished using goto and can't have an alternative solution. In practice, in some situations, goto is more concise, more readable, and one would be more attempted to use goto than an alternative solution.
Using good judgements and try to avoid goto where possible, but use it where it seems to be better, is one thing. Observe the abstence of goto like the eleventh commandment and swear to never ever use it, that's another thing. That's not rational. That's religious.
It's like alcohol. There are much more bad things than good things in alcohol. Drunken drivers being one, amoung other things. In principle, one can live without alcohol. In practice, it is good to try to avoid aocohol as much as possible, but DO drink it when the occasion is appropriate. If you observe the absolute abstence of alcohol, then you have become religious.
You can try to convince me in each and every specific situations, it's better NOT to drink alcohol rather than drink it. But if you are trying to convince people to observe the absolute abstence of alcohol under all situations, then that is just too much.
I never use goto and actually never use break or continue. But then again, I can see advantages of using it. Maybe Antony's example isn't compelling, although it's not easier or harder to read than Axter's change IMHO.
Programmers who write a lot of C-style code mixed with assembler code might prefer to use gotos. This would lend itself to situations where you have a few asm blocks inside a function, but don't want to code the whole function in asm. I can see nothing majorly wrong there, since using asm usually involves jumps anyways.
On a side note, the VB On Error Goto statement can be helpful for automatically debugging your application. It is also essential for working with COM objects since VB just throws an error if the HRESULT is not S_OK. But well, VB isn't the nicest programming language anyways ;)
IMHO, the above code reads and functions much better using an extra well defined bool variable then using a goto statement.Code:
for (int x = 0;x < 100;++x)
{
bool BreakOutOf_X_loop = false;
for(int y = 0;y < 10;++y)
{
if (y == 5 && x == 10)
{
BreakOutOf_X_loop = true;
break;
}
}
if (BreakOutOf_X_loop) break;
}
It's easier to maintain and the logic is easy to follow.
As I stated before, a goto statement is never needed.
If you or any one else which to use it in your code, that is your choice.
Just as it is my choice to call it as I see it. And as I see it, a goto is never, never, never needed.
Well, I prefer using while loops when execution can break inside a loop. This makes it clear that the loop is not always executed a fixed number of times (that's what a for loop means to me).
But then again I programmed in Pascal for a long time before coming to C/C++ ;)
Code:bool BreakLoop = false;
x = 0;
while ((x < 100) && !BreakLoop)
{
y = 0;
while ((y < 10) && !BreakLoop)
{
if (y == 5 && x == 10)
{
BreakLoop = true;
}
++y;
}
++x;
}
Here is the real issue. So, someone working for me submits the following code flow:
and someone else working for me submits:Code:// inside somewhere
// some code
if (//some condition) goto here;
// some more code
here:
// some more code
I look at both of them. I understand both of them. I can maintain both of them. So I give both of them paychecks and we all go home happy. Now my challenge. Is there ANY coding issue with the goto that is being missed? I don't want to know if it can be done differently, since I can think of hundreds of ways. What I am asking is: is there any development issues, actual problems that could come down the line, that can be fixed up with the if but REQUIRES removal of the goto or more work with the goto. Because I have this sneaky suspicion that the only reason people dislike the goto is because "someone greater then thee" has shown disdain at its use, and for no real coding issue.Code:// inside somewhere
// some code
if (//not some condition)
{
// some more code
}
// some more code here
Really, the while keyword can be looked at as unnecessary. Since I can always do a while with an if/goto combination. Does this really mean I should never, never, never use a while? Or are we really so c++ illiterate that we cannot understand looking at a goto what it does but we can understand a while and some of the more "common folk" tongue. I have no problems with readability, etc.
Side note: exception handling is DEFINITELY necessary in some places. Say I am writing an API interception and am performing my interception in some process in a galaxy far away. I get a list of currently loaded modules and begin patching their IAT. But that process is doing its own thing, and one of the modules I am patching is unloaded while writing the thunks. Do I let my interception crash the process, or do I catch the memory exception that is going to occur and use it to have my program realize that that module is no longer there and I should move on to the next?
Here is a real-life example from MFC COleDateTime class. Note that it would be extremly difficult to code this without the goto.
Code:static BOOL _TmFromOleDate(DATE dtSrc, struct tm& tmDest)
{
// The legal range does not actually span year 0 to 9999.
if (dtSrc > MAX_DATE || dtSrc < MIN_DATE) // about year 100 to about 9999
return FALSE;
long nDays; // Number of days since Dec. 30, 1899
long nDaysAbsolute; // Number of days since 1/1/0
long nSecsInDay; // Time in seconds since midnight
long nMinutesInDay; // Minutes in day
long n400Years; // Number of 400 year increments since 1/1/0
long n400Century; // Century within 400 year block (0,1,2 or 3)
long n4Years; // Number of 4 year increments since 1/1/0
long n4Day; // Day within 4 year block
// (0 is 1/1/yr1, 1460 is 12/31/yr4)
long n4Yr; // Year within 4 year block (0,1,2 or 3)
BOOL bLeap4 = TRUE; // TRUE if 4 year block includes leap year
double dblDate = dtSrc; // tempory serial date
// If a valid date, then this conversion should not overflow
nDays = (long)dblDate;
// Round to the second
// dblDate += ((dtSrc > 0.0) ? HALF_SECOND : -HALF_SECOND);
nDaysAbsolute = (long)dblDate + 693959L; // Add days from 1/1/0 to 12/30/1899
dblDate = fabs(dblDate);
double dblTimePart = dblDate - floor(dblDate);
double dblSecsInDay = dblTimePart * 86400.0F;
nSecsInDay = (long)(dblSecsInDay);
double deltaSecs = dblSecsInDay - (double)nSecsInDay; // milliseconds
if(deltaSecs > 0.999000F)
nSecsInDay++;
// Calculate the day of week (sun=1, mon=2...)
// -1 because 1/1/0 is Sat. +1 because we want 1-based
tmDest.tm_wday = (int)((nDaysAbsolute - 1) % 7L) + 1;
// Leap years every 4 yrs except centuries not multiples of 400.
n400Years = (long)(nDaysAbsolute / 146097L);
// Set nDaysAbsolute to day within 400-year block
nDaysAbsolute %= 146097L;
// -1 because first century has extra day
n400Century = (long)((nDaysAbsolute - 1) / 36524L);
// Non-leap century
if (n400Century != 0)
{
// Set nDaysAbsolute to day within century
nDaysAbsolute = (nDaysAbsolute - 1) % 36524L;
// +1 because 1st 4 year increment has 1460 days
n4Years = (long)((nDaysAbsolute + 1) / 1461L);
if (n4Years != 0)
n4Day = (long)((nDaysAbsolute + 1) % 1461L);
else
{
bLeap4 = FALSE;
n4Day = (long)nDaysAbsolute;
}
}
else
{
// Leap century - not special case!
n4Years = (long)(nDaysAbsolute / 1461L);
n4Day = (long)(nDaysAbsolute % 1461L);
}
if (bLeap4)
{
// -1 because first year has 366 days
n4Yr = (n4Day - 1) / 365;
if (n4Yr != 0)
n4Day = (n4Day - 1) % 365;
}
else
{
n4Yr = n4Day / 365;
n4Day %= 365;
}
// n4Day is now 0-based day of year. Save 1-based day of year, year number
tmDest.tm_yday = (int)n4Day + 1;
tmDest.tm_year = n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr;
// Handle leap year: before, on, and after Feb. 29.
if (n4Yr == 0 && bLeap4)
{
// Leap Year
if (n4Day == 59)
{
/* Feb. 29 */
tmDest.tm_mon = 2;
tmDest.tm_mday = 29;
goto DoTime;
}
// Pretend it's not a leap year for month/day comp.
if (n4Day >= 60)
--n4Day;
}
// Make n4DaY a 1-based day of non-leap year and compute
// month/day for everything but Feb. 29.
++n4Day;
// Month number always >= n/32, so save some loop time */
for (tmDest.tm_mon = (n4Day >> 5) + 1;
n4Day > _afxMonthDays[tmDest.tm_mon]; tmDest.tm_mon++);
tmDest.tm_mday = (int)(n4Day - _afxMonthDays[tmDest.tm_mon-1]);
DoTime:
if (nSecsInDay == 0)
tmDest.tm_hour = tmDest.tm_min = tmDest.tm_sec = 0;
else
{
tmDest.tm_sec = (int)nSecsInDay % 60L;
nMinutesInDay = nSecsInDay / 60L;
tmDest.tm_min = (int)nMinutesInDay % 60;
tmDest.tm_hour = (int)nMinutesInDay / 60;
}
return TRUE;
}
The danger of goto is simply that it can be easily abused, and in the past was often abused. This past abuse was largely corrected with an attitude change
It's partly because of the current attitude towards goto that you won't find it abused as it once was. Since goto does not solve any problems that cannot be solved otherwise, I'd rather maintain this attitude.
The logical flow of a method is more easily be muddled with goto. It's non-continuous. It jumps.
Used prudently, with care, goto will not cause a serious maintenance problem. But, because of the ease with which it can be abused, I still feel it is best to not use.
Jeff
Pointers can be easily abused. And as I said above, while doesn't solve any problems that can't be solved otherwise. And there are MANY keywords that jump. If your reasons apply to other keywords besides goto, I see them as invalid. Give me REAL reasons.
** galathaea gives that cheese-western squint **
"Come on space cowboys..."
What keywords jump? The only I can think of off the top of myQuote:
Originally posted by galathaea
Pointers can be easily abused. And as I said above, while doesn't solve any problems that can't be solved otherwise. And there are MANY keywords that jump. If your reasons apply to other keywords besides goto, I see them as invalid. Give me REAL reasons.
** galathaea gives that cheese-western squint **
"Come on space cowboys..."
head would be the switch/case constructs, break, and continue.
continue and break do jump, but their jumping is a lot more
limited. Even so, plenty of people have made the mistake where
they forget to put a break in one of their case: areas of a
switch statement. The jumping statements can be misused or
create problems down the road. The thing is that continue/break/
switch/case all are a lot more limited with respect to where they
can jump. Their jumping is a lot more structured than goto's
jump. It's because of goto's flexibility that it can be misused.
So ... yeah, the same problem can exist with all jumping
keywords, but goto is significantly different than these other
keywords so in my opinion, the problem is exacerbated.
--Paul
Real reasons what? There's no reason you can't use goto. It can lead to bad code when used incorrectly. So can other things. The thing with goto was that it was often used incorrectly, leading to remarkably difficult code to maintain.
This misuse was so common that a now well-known paper was written by Dijkstra as to why it was harmful. You've probably heard his name before.
This paper had a tremendous effect on the programming community. This paper is now considered by some to be a little extreme, but coming from the standpoint of 1968, I think his disdain is well placed.
This paper is largely responsible for current attitudes toward goto. Here is a link: http://www.acm.org/classics/oct95/
He sums up my standpoint entirely in "it is too much an invitation to make a mess of one's program".
Jeff
Ifs don't jump? While's don't jump? For's don't jump? I think your definition of jump is not valid since all the things I just mentioned compile to different jumps. Is the problem that you don't know where a goto jumps to but the others you can figure out? Then that sounds like a problem understanding the language. Is the problem that goto is flexible? Is that really a minus? Yes, keywords can be abused to unrecognizability. Just check out the International Obfuscated C Code contest. Mains can be arrays instead of functions. I still think this may be a problem with timid programmers folllowing unsubstantiated "guru" advice instead of independent thinking, and not a REAL issue...
** galathaea gives that cheese-western squint **
"Come on space cowboys..."
hmmmmmmm ... try to compile ...Quote:
previously posted by galathaea
Code:// inside somewhere
// some code
if (//some condition) goto here;
// some more code
here:
// some more code
Code:// inside somewhere
// some code
if (//some condition) goto here;
// some more code
std::vector<int> v(1000000);
int i = 10;
here:
// some more code
Forget some brackets ? Easy to do using goto when they were not
needed originally, but something is added later that requires
putting them in.
There is a design principle that I follow that goes like this: always declare local variables at the head of their locality. If you need to create a new locality with new variable declarations, that is simple in c++. Yes, not following good design is a problem. But such a mistake is not a goto problem. It is a design problem. If you have bad design, you have bad design with or without the goto.
** galathaeapistolero blows smoke from the barrel **
"Next space cowboy?"
I don't have the fundamental misunderstandings that you areQuote:
Originally posted by galathaea
Ifs don't jump? While's don't jump? For's don't jump? I think your definition of jump is not valid since all the things I just mentioned compile to different jumps. Is the problem that you don't know where a goto jumps to but the others you can figure out? Then that sounds like a problem understanding the language. Is the problem that goto is flexible? Is that really a minus? Yes, keywords can be abused to unrecognizability. Just check out the International Obfuscated C Code contest. Mains can be arrays instead of functions. I still think this may be a problem with timid programmers folllowing unsubstantiated "guru" advice instead of independent thinking, and not a REAL issue...
** galathaea gives that cheese-western squint **
"Come on space cowboys..."
implying. I can't give you a 1-to-1 correlation between C++
keywords and assembly statements, but I realize that if's are
broken down to low-level assembly routines that, of course, jump.
The thing is that an if is very structured; a while is very
structured. A goto ... well it's a lot more low-level. I am not
saying that that low-leveledness is a bad thing, either. I can
think of some times where I'd prefer to use a goto even though
there are other alternatives [like nested loops]. Like jfaust was
saying earlier, the thing with goto is that everyone has their
own opinion with respect to what "proper" usage of the goto
keyword is. Since goto is so low-level, its use should be
considered carefully. Because it's so flexible, I choose to be
careful with it. I, for one, never advocated NOT using it. I don't
use it often, however, and I tend to find the benefits of using it
minor compared to the potential headaches that can arise
through its use.
--Paul
As correctly stated by Anthony Mai, it is not a design problem. It is an implementation detail. As correctly demonstrated by Philip Nicoletti, goto can be more error prone.Quote:
It is a design problem.
Jeff
forget some brackets?Code:switch (//some switch variable)
{
case //case1:
std::vector<int> v(1000000);
int i = 10;
break;
// next cases
}
Nope ... I did not post that code.Quote:
previously posted by galathaea ...
switch (//some switch variable)
{
case //case1:
std::vector<int> v(1000000);
int i = 10;
break;
// next cases
}
--------------------------------------------------------------------------------
forget some brackets?
Plus you were asking why
is not as good asCode:if (something) goto here
//
//
here:
Code:if (something)
{
//
//
}
re: Phillip Nicolleti
No, but that same wiley programmer who didn't follow a good design suggestion added those variables to a switch statement like they did to my goto. You have to see how this invalidates your argument against goto being the culprit? Don't you?
Re: jfaust
Don't you?
not at all, I edited my previous post, but you
replied to fast for me ...
You were comparing the merits of two particular
constructs. That's what I did.