CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 8 1234 ... LastLast
Results 1 to 15 of 116

Thread: goto

  1. #1
    Join Date
    Sep 2002
    Posts
    15

    Question goto

    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...

  2. #2
    Join Date
    Oct 2002
    Location
    OH
    Posts
    100
    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.

  3. #3
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    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

  4. #4
    Join Date
    Jun 2002
    Location
    Germany
    Posts
    1,557
    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.

    You're gonna go blind staring into that box all day.

  5. #5
    Join Date
    Jul 2002
    Location
    Connecticut, U.S.
    Posts
    275
    Paul,

    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.
    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

  6. #6
    Join Date
    Apr 1999
    Location
    Altrincham, England
    Posts
    4,470
    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.
    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:
    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;
    }
    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()
    {
        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
    }
    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.

    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.
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
    --
    Sutter and Alexandrescu, C++ Coding Standards

    Programs must be written for people to read, and only incidentally for machines to execute.

    --
    Harold Abelson and Gerald Jay Sussman

    The cheapest, fastest and most reliable components of a computer system are those that aren't there.
    -- Gordon Bell


  7. #7
    Join Date
    Oct 2002
    Location
    OH
    Posts
    100
    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.

    Looking at my 30-second-to-write piece of source code, your comments about it are correct.

    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:
    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.
    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.

    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.

  8. #8
    Join Date
    Sep 2002
    Posts
    1,747

    also try SEH termination handlers

    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.

  9. #9
    Join Date
    Apr 1999
    Location
    Altrincham, England
    Posts
    4,470
    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.
    ... 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.
    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 )
    ... 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.
    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.
    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.
    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.
    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:
    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.
    Imagine that in the process of writing to the database, the system throws an exception....
    How does the above compare with:
    Code:
    void WriteToDatabase(Database* db)
    {
        db->StopOthersWriting();
    
        // Write to the database
    
    Done:
        db->AllowOthersToWrite();
    }
    How long will that database stay uncorrupt?
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
    --
    Sutter and Alexandrescu, C++ Coding Standards

    Programs must be written for people to read, and only incidentally for machines to execute.

    --
    Harold Abelson and Gerald Jay Sussman

    The cheapest, fastest and most reliable components of a computer system are those that aren't there.
    -- Gordon Bell


  10. #10
    Join Date
    Apr 1999
    Location
    Altrincham, England
    Posts
    4,470

    Re: also try SEH termination handlers

    Originally posted by galathaea
    The keyword goto is a there if you need it,
    you don't need it
    so don't be afraid to use it.
    I'm not afraid to use it - I choose not to contaminate my code with it.
    There are better design implementations possible, though,
    Absolutely
    so if you are looking for something that is consistent and readable, I would look into things like termination handlers.
    Why?
    Especially for cleanup routines.
    Use RAII. What are cleanup routines?
    Wrapping some code in __try, __finally
    No such keywords in C++
    will help if you don't have any need for strong c++ handling of scope and destructors.
    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.
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
    --
    Sutter and Alexandrescu, C++ Coding Standards

    Programs must be written for people to read, and only incidentally for machines to execute.

    --
    Harold Abelson and Gerald Jay Sussman

    The cheapest, fastest and most reliable components of a computer system are those that aren't there.
    -- Gordon Bell


  11. #11
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    Code:
    The keyword goto is a there if you need it, so don't be afraid to use it.
    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.

    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

  12. #12
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    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
    Oops What I meant was the "goto" concept. Um ... in other
    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

  13. #13
    Join Date
    Jul 2002
    Location
    American Continent
    Posts
    340
    Graham said:
    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.
    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!

    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.

  14. #14
    Join Date
    Jul 2002
    Location
    American Continent
    Posts
    340
    Graham said:
    Oops, my eyes skipped lines. The wrong statement was made by Paul, not Graham.

  15. #15
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    Originally posted by Anthony Mai
    you can jump out of a scope but not into a scope
    You can jump into a scope just fine:

    Code:
    int main()
    {
    	if( 0 )
    	{
    inner_scope:
    		return 0;
    	}
    
    	goto inner_scope;
    	return 1;
    }
    Jeff

Page 1 of 8 1234 ... LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured