multiple return paths question

Discussion in 'C++' started by cimple, Jan 16, 2006.

  1. cimple

    cimple Guest

    I've always made sure never to have multiple return paths in a function
    because i thought it produced bigger code (and for readability). I
    remember Lippman from Inside the Object Model saying something about
    this. For every return point in a function, destructor calls for every
    object created on the stack needs to be called. But when i tested this,
    i saw no increase in executable size in release builds. Is my compiler
    (VS7.0, Win2k) just optimizing or was my original assumption incorrect?

    For example:

    void Foo()
    {
    Object x;
    Object y;
    Object z;

    if (x == y)
    return;

    if (x == z)
    return;

    if (y == z)
    return;
    }

    Doesn't the above Foo bloat into this:

    void Foo()
    {
    Object x;
    Object y;
    Object z;

    if (x == y)
    {
    x.~x();
    y.~y();
    z.~z();
    return;
    }

    if (x == z)
    {
    x.~x();
    y.~y();
    z.~z();
    return;
    }

    if (y == z)
    {
    x.~x();
    y.~y();
    z.~z();
    return;
    }

    x.~x();
    y.~y();
    z.~z();
    return;
    }

    Hence, never produce functions with multiple return paths?

    Thank you in advance.
     
    cimple, Jan 16, 2006
    #1
    1. Advertising

  2. cimple

    mlimber Guest

    cimple wrote:
    > I've always made sure never to have multiple return paths in a function
    > because i thought it produced bigger code (and for readability). I
    > remember Lippman from Inside the Object Model saying something about
    > this. For every return point in a function, destructor calls for every
    > object created on the stack needs to be called. But when i tested this,
    > i saw no increase in executable size in release builds. Is my compiler
    > (VS7.0, Win2k) just optimizing or was my original assumption incorrect?
    >
    > For example:
    >
    > void Foo()
    > {
    > Object x;
    > Object y;
    > Object z;
    >
    > if (x == y)
    > return;
    >
    > if (x == z)
    > return;
    >
    > if (y == z)
    > return;
    > }
    >
    > Doesn't the above Foo bloat into this:
    >
    > void Foo()
    > {
    > Object x;
    > Object y;
    > Object z;
    >
    > if (x == y)
    > {
    > x.~x();
    > y.~y();
    > z.~z();
    > return;
    > }
    >
    > if (x == z)
    > {
    > x.~x();
    > y.~y();
    > z.~z();
    > return;
    > }
    >
    > if (y == z)
    > {
    > x.~x();
    > y.~y();
    > z.~z();
    > return;
    > }
    >
    > x.~x();
    > y.~y();
    > z.~z();
    > return;
    > }
    >
    > Hence, never produce functions with multiple return paths?
    >
    > Thank you in advance.


    First, I don't see why a compiler couldn't do it differently. Second,
    according to _C++ Coding Standards_ by Sutter and Alexandrescu, the
    single entry/single exit philosophy doesn't apply well to C++:
    "Historically, some coding standards have required that each function
    have exactly one exit, meaning one return statement. Such a requirement
    is obsolete in languages that support exceptions and destructors, where
    functions typically have numerous implicit exits. Instead, follow
    standards like Item 5 [in the same book] that directly promote simpler
    and shorter functions that are inherently easier to understand and to
    make error-safe."

    Cheers! --M
     
    mlimber, Jan 16, 2006
    #2
    1. Advertising

  3. * mlimber:
    >
    > according to _C++ Coding Standards_ by Sutter and Alexandrescu, the
    > single entry/single exit philosophy doesn't apply well to C++:
    > "Historically, some coding standards have required that each function
    > have exactly one exit, meaning one return statement. Such a requirement
    > is obsolete in languages that support exceptions and destructors, where
    > functions typically have numerous implicit exits. Instead, follow
    > standards like Item 5 [in the same book] that directly promote simpler
    > and shorter functions that are inherently easier to understand and to
    > make error-safe."


    In the SESE/SEME debates in clc++m Andrei has mostly been a majority of
    one... ;-)

    I don't think he's wrong, but I don't think he's right.

    There are different approaches, and they're just different, not mutually
    exclusive (except within the same code) such that one is better in any
    absolute sense, in the sense of being the preferred style. If I had to
    draw a distinction it would be that SEME works fine for expert
    programmers and is much favored by novices, while SESE works fine for
    novices and is much favored by the mediocre. But of what practical
    utility that observation is, and whether it is correct, well.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Jan 16, 2006
    #3
  4. cimple

    cimple Guest

    Alright i just looked it up in my Lippman book. In section 6.1 Object
    Construction and Destruction.

    "..It gets slightly more confusing when there are multiple exits from a
    block or function. The destructor must be placed at each exit point at
    which the object is "alive"...[given an example similar to the one
    above] In this example, the destructor for "point" [in our case x, y,
    and z] must be generated prior to the return statement at the three
    exit points..."

    He goes on to say...

    "In general, place an object as close as possible to the code segment
    actually using it. Doing this can save you unncessary object creation
    and destruction..This may seem self-evident, but many Pascal and C
    programmers using C++ still place all their objects at the beginning of
    a function or a local block."


    I've looked at a lot of code from both beginners and "experts" and very
    rarely do either stick to single exit point philosophy.
     
    cimple, Jan 16, 2006
    #4
  5. * cimple:
    > Alright i just looked it up in my Lippman book. In section 6.1 Object
    > Construction and Destruction.


    I think there must be something wrong with your quoting or the quotes
    only make sense in some outer context not evident here, because...


    > "..It gets slightly more confusing when there are multiple exits from a
    > block or function. The destructor must be placed at each exit point at
    > which the object is "alive"...[given an example similar to the one
    > above] In this example, the destructor for "point" [in our case x, y,
    > and z] must be generated prior to the return statement at the three
    > exit points..."


    .... a destructor is not generated, except in the sense of
    inline-expanded, at different places in the code (could Lippman be
    talking about destructor _calls_?), and ...


    > He goes on to say...
    >
    > "In general, place an object as close as possible to the code segment
    > actually using it. Doing this can save you unncessary object creation
    > and destruction..This may seem self-evident, but many Pascal and C
    > programmers using C++ still place all their objects at the beginning of
    > a function or a local block."


    .... declaring objects as close as possible to the code segment using
    them is not incompatible with declaring them at the beginning of a local
    block, except visual layout for one rather uncommon indentation style.


    > I've looked at a lot of code from both beginners and "experts" and very
    > rarely do either stick to single exit point philosophy.


    If you just count returns and perhaps throws, breaks, whatever, that
    would appear to be the case.

    If you analyze the meaning of the code it's different.

    Early returns for failed preconditions is common (SEME), with the meat
    of the function in SESE style, except sometimes breaks from nested loops
    and functions that are really just value or action selectors. It's a
    matter of using the right tool for the right job. SESE/SEME debates, at
    least above the novice nevel, are not about whether it can be a good
    idea to force an early exit on some failed precondition, say (it _is_ a
    good idea), but whether the preference for SESE or SEME in the meat of
    the function provides the most clear, readable code, to which the answer
    is SESE if you're used to that, and SEME if you're used to that... ;-)

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Jan 16, 2006
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Donald
    Replies:
    1
    Views:
    479
    Roel van der Steen
    Mar 7, 2004
  2. Noah
    Replies:
    5
    Views:
    795
  3. Greenhorn
    Replies:
    15
    Views:
    840
    Keith Thompson
    Mar 6, 2005
  4. Bruce W.1

    Not all code paths return a value?

    Bruce W.1, Dec 11, 2003, in forum: ASP .Net Web Services
    Replies:
    6
    Views:
    242
    Colin Savage
    Dec 17, 2003
  5. Ohad Lutzky

    Paths, gentleman, paths

    Ohad Lutzky, Nov 6, 2006, in forum: Ruby
    Replies:
    2
    Views:
    205
    David Vallner
    Nov 7, 2006
Loading...

Share This Page