Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Is this kosher?

Reply
Thread Tools

Is this kosher?

 
 
Tim H
Guest
Posts: n/a
 
      08-27-2008
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
 
Reply With Quote
 
 
 
 
Leon Timmermans
Guest
Posts: n/a
 
      08-27-2008
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
 
Reply With Quote
 
 
 
 
AnonMail2005@gmail.com
Guest
Posts: n/a
 
      08-27-2008
On Aug 27, 11:22*am, Tim H <(E-Mail Removed)> 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
 
Reply With Quote
 
Tim H
Guest
Posts: n/a
 
      08-27-2008
I should have asked this better, I was in a rush. Sorry

On Aug 27, 8:22 am, Tim H <(E-Mail Removed)> 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
 
Reply With Quote
 
gpderetta
Guest
Posts: n/a
 
      08-27-2008
On Aug 27, 8:49 pm, Paavo Helde <(E-Mail Removed)> 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
 
Reply With Quote
 
Tim H
Guest
Posts: n/a
 
      08-27-2008
On Aug 27, 3:12*pm, gpderetta <(E-Mail Removed)> wrote:
> On Aug 27, 8:49 pm, Paavo Helde <(E-Mail Removed)> 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
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      08-31-2008
On Aug 27, 8:24 pm, Tim H <(E-Mail Removed)> wrote:
> I should have asked this better, I was in a rush. Sorry


> On Aug 27, 8:22 am, Tim H <(E-Mail Removed)> 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:(E-Mail Removed)
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
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      08-31-2008
On Aug 27, 8:49 pm, Paavo Helde <(E-Mail Removed)> wrote:
> Tim H <(E-Mail Removed)> 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:(E-Mail Removed)
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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off




Advertisments