Is this kosher?

Discussion in 'C++' started by Tim H, Aug 27, 2008.

  1. Tim H

    Tim H Guest

    class Foo {};

    template <typename Tdata>
    const Foo &operator<<(const Foo &foo, const Tdata &data)
    {
    std::cout << "FOO: " << data << std::endl;
    }


    Foo
    MyFunction1()
    {
    // returning a copy - can this ever trigger Foo::Foo() and
    Foo::~Foo() ?
    return Foo() << "MyFucntion1";
    }

    const Foo &
    MyFunction2()
    {
    // chaining calls on a temporary?
    // is the temporary's life extended by returning a reference?
    return MyFunction1() << "MyFunction2" << "something" << "else";
    }


    Tim
    Tim H, Aug 27, 2008
    #1
    1. Advertising

  2. On Wed, 27 Aug 2008 08:22:15 -0700, Tim H wrote:
    > // returning a copy - can this ever trigger Foo::Foo() and Foo::~Foo

    () ?

    What do you mean with 'triggering Foo::Foo()'?

    > // chaining calls on a temporary?
    > // is the temporary's life extended by returning a reference? return
    > return MyFunction1() << "MyFunction2" << "something" << "else";


    The temporary is destroyed at the end of the statement. Returning a
    reference to a variable made on the stack is going to make your program
    crash.

    Regards,

    Leon Timmermans
    Leon Timmermans, Aug 27, 2008
    #2
    1. Advertising

  3. Tim H

    Guest

    On Aug 27, 11:22 am, Tim H <> wrote:
    > class Foo {};
    >
    > template <typename Tdata>
    > const Foo &operator<<(const Foo &foo, const Tdata &data)
    > {
    >     std::cout << "FOO: " << data << std::endl;
    >
    > }
    >
    > Foo
    > MyFunction1()
    > {
    >     // returning a copy - can this ever trigger Foo::Foo() and
    > Foo::~Foo() ?
    >     return Foo() << "MyFucntion1";
    >
    > }
    >
    > const Foo &
    > MyFunction2()
    > {
    >     // chaining calls on a temporary?
    >     // is the temporary's life extended by returning a reference?
    >     return MyFunction1() << "MyFunction2" << "something" << "else";
    >
    > }
    >
    > Tim


    I think I see what you're trying to do.

    Make operator << a member function of your foo object.
    Remove the first argument (it will be implicit for a member function)
    and have it return *this.

    Then, both your functions should work fine. Of course, MyFunction1
    will return a copy of your object.

    HTH
    , Aug 27, 2008
    #3
  4. Tim H

    Tim H Guest

    I should have asked this better, I was in a rush. Sorry

    On Aug 27, 8:22 am, Tim H <> wrote:
    > class Foo {};
    >
    > template <typename Tdata>
    > const Foo &operator<<(const Foo &foo, const Tdata &data)
    > {
    > std::cout << "FOO: " << data << std::endl;
    >
    > }


    This code works:
    Foo() << "string";

    This code seems to work:
    Foo() << "string" << 99 << "other" << "more";

    Is the temporary Foo guaranteed to exist until the end of this full
    statement, or can the temporary possibly go away somewhere in the
    middle?

    This code works, and returns a valid Foo.
    Foo MyFunction1()
    {
    return Foo();
    }

    Is this guaranteed to only construct one Foo? Or can the compiler
    optionally construct a local Foo and then copy construct the returned
    Foo in caller's scope?


    This code works, and returns a valid Foo.
    Foo MyFunction2()
    {
    return Foo() << "MyFunction1";
    }

    As I understand, it returns a copy of the temporary Foo, right?
    Meaning that the Foo constructor will be called twice (for two
    seperate instances).


    How about this?
    const Foo &MyFunction3()
    {
    return MyFunction1();
    }

    Or this?
    const Foo &MyFunction4()
    {
    return MyFunction1() << "something" << "else";
    }

    Both of those are returning references to temporaries, right? Yet the
    compiler did not complain. Both of these are illegal, as I
    understand. The temporary values do not have their lifetime extended,
    am I correct?

    Thanks

    Tim
    Tim H, Aug 27, 2008
    #4
  5. Tim H

    gpderetta Guest

    On Aug 27, 8:49 pm, Paavo Helde <> wrote:
    >
    > > This code works, and returns a valid Foo.
    > > Foo MyFunction1()
    > > {
    > > return Foo();
    > > }

    >
    > > Is this guaranteed to only construct one Foo? Or can the compiler
    > > optionally construct a local Foo and then copy construct the returned
    > > Foo in caller's scope?

    >
    > Depends on the caller. If it is bound to a const reference, no copy ctor
    > calls occur.


    This is not guaranteed. A compiler is still free to make a copy (most
    recent compilers don't, but that's another story).

    --
    gpd
    gpderetta, Aug 27, 2008
    #5
  6. Tim H

    Tim H Guest

    On Aug 27, 3:12 pm, gpderetta <> wrote:
    > On Aug 27, 8:49 pm, Paavo Helde <> wrote:


    > > > This code works, and returns a valid Foo.
    > > >     Foo MyFunction1()
    > > >     {
    > > >         return Foo();
    > > >     }

    >
    > > > Is this guaranteed to only construct one Foo? Or can the compiler
    > > > optionally construct a local Foo and then copy construct the returned
    > > > Foo in caller's scope?

    >
    > > Depends on the caller. If it is bound to a const reference, no copy ctor
    > > calls occur.

    >
    > This is not guaranteed. A compiler is still free to make a copy (most
    > recent compilers don't, but that's another story).


    What if the use case is
    MyFunction1() << "some" << "stuff";

    Does the compiler have the option to make a copy (e.g. can the Foo
    ctor/dtor be called more than once) ??

    Tim
    Tim H, Aug 28, 2008
    #6
  7. Tim H

    James Kanze Guest

    On Aug 27, 8:24 pm, Tim H <> wrote:
    > I should have asked this better, I was in a rush. Sorry


    > On Aug 27, 8:22 am, Tim H <> wrote:


    > > class Foo {};


    > > template <typename Tdata>
    > > const Foo &operator<<(const Foo &foo, const Tdata &data)
    > > {
    > > std::cout << "FOO: " << data << std::endl;
    > > }


    > This code works:
    > Foo() << "string";


    > This code seems to work:
    > Foo() << "string" << 99 << "other" << "more";


    > Is the temporary Foo guaranteed to exist until the end of this
    > full statement, or can the temporary possibly go away
    > somewhere in the middle?


    The temporary is guaranteed to last until the end of the full
    expression, in this case, until the end of the statement.

    > This code works, and returns a valid Foo.
    > Foo MyFunction1()
    > {
    > return Foo();
    > }


    > Is this guaranteed to only construct one Foo? Or can the
    > compiler optionally construct a local Foo and then copy
    > construct the returned Foo in caller's scope?


    The formal semantics are for it to construct a temporary Foo,
    then copy construct it for the return. The compiler is
    explicitly allowed to elide the copy, however, even if it has
    side effects. Whoever uses the return value is likely to have
    to copy construct it as well, formally; again, in certain
    contexts, the compiler is allowed to elide the copy.

    Note that even if the compiler does elide the copy, the copy
    must be legal.

    > This code works, and returns a valid Foo.
    > Foo MyFunction2()
    > {
    > return Foo() << "MyFunction1";
    > }


    > As I understand, it returns a copy of the temporary Foo,
    > right?


    Almost certainly, since all it has to return is a reference, and
    not an object (with known lifetime, etc.).

    > Meaning that the Foo constructor will be called twice
    > (for two seperate instances).


    Two different constructors will be called; the default
    constructor and the copy constructor.

    > How about this?
    > const Foo &MyFunction3()
    > {
    > return MyFunction1();
    > }


    That's a good recepe for undefined behavior. You're returning a
    reference to a temporary object, which will be destructed before
    the return.

    > Or this?
    > const Foo &MyFunction4()
    > {
    > return MyFunction1() << "something" << "else";
    > }


    > Both of those are returning references to temporaries, right?


    Right.

    > Yet the compiler did not complain. Both of these are illegal,
    > as I understand. The temporary values do not have their
    > lifetime extended, am I correct?


    Correct. It's undefined behavior, so the compiler is not
    required to complain. In the second case, supposing separate
    compilation and a non-inlined operator<<, it's difficult to see
    how it could detect the error to begin with.

    Are you trying to do something specific, or are these just
    general questions? Some of your code looks very much like my
    logging objects; the solution here will be an rvalue reference,
    once the next version of the standard is adopted and
    implemented. Until then, it can be simulated using reference
    counting, implementing copy so that all copied instances are
    idempotent, and destruction so that only the destructor of the
    last copied instance does whatever is critical.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Aug 31, 2008
    #7
  8. Tim H

    James Kanze Guest

    On Aug 27, 8:49 pm, Paavo Helde <> wrote:
    > Tim H <> kirjutas:


    [...]
    > > This code works, and returns a valid Foo.
    > > Foo MyFunction1()
    > > {
    > > return Foo();
    > > }


    > > Is this guaranteed to only construct one Foo? Or can the
    > > compiler optionally construct a local Foo and then copy
    > > construct the returned Foo in caller's scope?


    > Depends on the caller. If it is bound to a const reference, no
    > copy ctor calls occur.


    That's wrong. The formal syntax is to create a temporary
    instance using the default constructor, then copy it (using a
    copy constructor) to where ever the compiler puts return values.
    The compiler may elide the copy (and most do), but it's not
    required, and it is required that the copy constructor exist and
    is accessible, even if the copy doesn't take place.

    > > This code works, and returns a valid Foo.
    > > Foo MyFunction2()
    > > {
    > > return Foo() << "MyFunction1";
    > > }


    > > As I understand, it returns a copy of the temporary Foo, right?
    > > Meaning that the Foo constructor will be called twice (for two
    > > seperate instances).


    > Copy ctor is a different thing than a ctor (although
    > pronounced the same ;-)


    A copy constructor is just another constructor. The only
    particularity it has is that if you don't declare one, the
    compiler will. Other than that, however, the fact that you are
    "copying" is irrelevant; overload resolution chooses which
    constructor will be called, exactly like in any other context
    (and there are a few exotic cases where the constructor which is
    called in the above is NOT the copy constructor, but some other
    constructor).

    > It will be called here probably, yes, but can be optimized
    > away as well, I guess (copy ctor can always be optimized away
    > AFAIK).


    Not always, but most of the time. (In this case, I don't think
    it can legally be optimized away, except under the as if rule.
    But I'm not 100% sure.)

    [...]
    > Yes, the lifetime extension by assigning to a const reference
    > only works on the caller side.


    There is never a lifetime extension due to assignment. The
    lifetime of a temporary will be extended if the temporary is
    used to initialize a reference (which must be const), but only
    if the temporary is the initialization expression. It has
    nothing to do with caller side or otherwise. (There's also a
    special rule which says that this extension doesn't apply when
    returning a reference.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Aug 31, 2008
    #8
    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. MikeC

    Is this kosher?

    MikeC, Nov 10, 2006, in forum: C Programming
    Replies:
    24
    Views:
    680
    Simon Biber
    Nov 13, 2006
  2. Roedy Green

    kosher jpgs

    Roedy Green, Oct 31, 2008, in forum: Java
    Replies:
    4
    Views:
    315
    Nigel Wade
    Nov 3, 2008
  3. luserXtrog

    longjmp from a signal handler ... kosher?

    luserXtrog, Aug 26, 2010, in forum: C Programming
    Replies:
    13
    Views:
    1,080
Loading...

Share This Page