Thread: goto

  1. #1
    Registered User
    Join Date
    Feb 2003
    Posts
    596

    goto

    In a function that has multiple exit points, and also has multiple dynamically allocated variables, I could repeat all the necessary delete statements before every return statement (if I remember), or I could put an Exit: label followed by all of the deletes at the end of the function and simply ( ) goto Exit at the various exit points. I'm thinking that the latter seems more efficient, more readable, and easier to maintain, and that therefore this is one of those "rare" situations in which goto is appropriate. Any comments?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I tend to agree, but in C++ there is a possibly better solution: make use of RAII, e.g., use smart pointers such that all the deletes are performed automatically.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    There have been several times that I have coded a GOTO statement, and every time, it eventually got in the way of an otherwise well structured module or a refactoring process.

    Depending on the environment for which your code will run, you can let the operating system free the storage, or you have to do it yourself. If the latter, you could keep an internal list of memory chunks that are allocated, and instead of coding an exit everywhere with a host of DELETE statements, you could call a cleanup routine that would in turn be a single point for freeing any storage and then exit from there.
    Mainframe assembler programmer by trade. C coder when I can.

  4. #4
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Quote Originally Posted by Laserlight View Post
    I tend to agree, but in C++ there is a possibly better solution: make use of RAII, e.g., use smart pointers such that all the deletes are performed automatically.
    I'm not familiar with RAII. I'll have to look into that.

    Quote Originally Posted by Dino View Post
    ... you could keep an internal list of memory chunks that are allocated, and instead of coding an exit everywhere with a host of DELETE statements, you could call a cleanup routine that would in turn be a single point for freeing any storage and then exit from there.
    I thought of writing an "exit" function, but then I'd have to pass it pointers to each variable to be deleted -- not very appealing. But unless I misunderstood, you seem to be suggesting yet another function to handle all the dynamic allocation, along with some sort of global structure containing or pointing to the dynamically allocated memory? Is that what you are suggesting?

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by R.Stiltskin
    I'm not familiar with RAII. I'll have to look into that.
    You could start by reading Stroustrup's answer to the FAQ How do I deal with memory leaks?.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    Quote Originally Posted by R.Stiltskin View Post
    ... But unless I misunderstood, you seem to be suggesting yet another function to handle all the dynamic allocation, along with some sort of global structure containing or pointing to the dynamically allocated memory? Is that what you are suggesting?
    Yes.

    (EDIT: But use of auto_ptr seems to be a simpler solution)
    Last edited by Dino; 12-29-2009 at 10:51 AM.
    Mainframe assembler programmer by trade. C coder when I can.

  7. #7
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Thanks, laserlight and Dino. auto_ptr is clearly something I should add to my repertoire. Oh, and I haven't come across that Stroustrup FAQ before either -- very handy.

    Happy New Year!

  8. #8
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    You can always use a destructor. If you have
    Code:
    foo a = new foo;
    boo b = new boo;
    you can do something like
    Code:
    class ab
    {
    foo* a;
    boo* b;
    class()
    {
    a = new foo;
    b = new boo;
    }
    ~class()
    {
       delete a;
       delete b;
    }
    };
    //use like
    ab myVar;
    Just a general example. Depends on exactly what you want. The idea is to wrap around new/delete a class that will be statically allocated so you can use the destructor mechanism.
    You also try something like
    Code:
    template<class T>
    class ptr
    {
       T* p;
        ptr(){p = new T;}
       ~ptr() {delete T;}
    };
    //use like
    ptr<foo> f;
    f.p->value = 1;
    You get the general idea.

    I would prefer a keyword like "breakAll" to break from nested loops.

  9. #9
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    Quote Originally Posted by C_ntua View Post
    You can always use a destructor. If you have
    Code:
    foo a = new foo;
    boo b = new boo;
    you can do something like
    Code:
    class ab
    {
    foo* a;
    boo* b;
    class()
    {
    a = new foo;
    b = new boo;
    }
    ~class()
    {
       delete a;
       delete b;
    }
    };
    //use like
    ab myVar;
    Just a general example. Depends on exactly what you want. The idea is to wrap around new/delete a class that will be statically allocated so you can use the destructor mechanism.
    You also try something like
    Code:
    template<class T>
    class ptr
    {
       T* p;
        ptr(){p = new T;}
       ~ptr() {delete T;}
    };
    //use like
    ptr<foo> f;
    f.p->value = 1;
    You get the general idea.

    I would prefer a keyword like "breakAll" to break from nested loops.
    It is a much better idea to use existing smart pointer implementations that attempting to create your own as you have done. Your "simple" example is incomplete and has several bugs.
    bit∙hub [bit-huhb] n. A source and destination for information.

  10. #10
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    ...and before you get too cozy with std::auto_ptr keep in mind it is not a 'shared' pointer in the truest sense. It also has some very weird copy semantics. I highly recommend using boost's various assortment of pointer types.

    And to answer your first question it seems to me that the function in question is probably too complex and needs to be broken out into several functions.

  11. #11
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    One serious problem with any use of goto in C++ is this:

    Code:
    class X;
    
    void foo()
    {
        goto label;
    
        X obj;
    label:
        // obj may, or may not be constructed at this point, depending whether we got here via goto or not
    }
    In other words, it can produce a situation where names are in scope but the objects they refer to are uninitialized. VERY BAD. The compiler should warn, but if it doesn't, your code will silently be wrong and it will be maddening to figure out what the problem is.

    "Failure ladders" are useful in C, but in C++ resources should be managed with containers, such as smart pointers.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  12. #12
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by Bubba View Post
    ...and before you get too cozy with std::auto_ptr keep in mind it is not a 'shared' pointer in the truest sense. It also has some very weird copy semantics. I highly recommend using boost's various assortment of pointer types.
    Seconded. The std::auto_ptr is too limited for most applications - definitely check out the Boost suite of smart-pointers.

    Also, another good replacement for the std::auto_ptr that is still quite light-weight is this one, which was designed by yours truly.

    Whatever you do, though, be sure to always use smart-pointers, and generally speaking, RAII techniques. There's absolutely no excuse for managing raw pointers "by hand"...EVER!!!
    Last edited by Sebastiani; 12-29-2009 at 07:01 PM.

  13. #13
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    Quote Originally Posted by laserlight View Post
    I tend to agree, but in C++ there is a possibly better solution: make use of RAII, e.g., use smart pointers such that all the deletes are performed automatically.
    That doesn't always work, for example, if there exist execution paths where the object is not deleted. If the object is always deleted then simply putting the deletes before the return would have worked.

  14. #14
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by abachler View Post
    That doesn't always work, for example, if there exist execution paths where the object is not deleted. If the object is always deleted then simply putting the deletes before the return would have worked.
    If the object isn't deleted, then it must be returned from the function or stored somewhere (otherwise it would be a memory leak). In that case the smart pointer will manage its lifetime correctly.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  15. #15
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    In other words, it can produce a situation where names are in scope but the objects they refer to are uninitialized. VERY BAD. The compiler should warn, but if it doesn't, your code will silently be wrong and it will be maddening to figure out what the problem is.
    I thought GCC won't even allow that. I don't think it allows goto's to fly over initializations (or even declarations?)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. add,view=ok, search,edit got error... help!
    By private0430 in forum C Programming
    Replies: 4
    Last Post: 09-27-2009, 01:36 PM
  2. temperature sensors
    By danko in forum C Programming
    Replies: 22
    Last Post: 07-10-2007, 07:26 PM
  3. Does goto have a glitch or...?
    By Blackroot in forum C++ Programming
    Replies: 9
    Last Post: 02-18-2006, 10:40 AM
  4. helpppp
    By The Brain in forum C Programming
    Replies: 1
    Last Post: 07-27-2005, 07:05 PM
  5. Need some help with a basic tic tac toe game
    By darkshadow in forum C Programming
    Replies: 1
    Last Post: 05-12-2002, 04:21 PM