Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Binding temporary to member reference

133 views
Skip to first unread message

Holger Grund

unread,
Jan 2, 2003, 10:05:57 AM1/2/03
to
The following code should be well-formed according to the
standard. I just don't seem to understand why it should be.

Why would you want to have a member reference that is
valid during the constructor call only? In the example below
you could easily make str_ a local variable of Foo::Foo.

I guess I'm missing something. Neither Comeau nor VC
report a warning.

Any ideas?

tia
-hg

// Code
#include <iostream>
#include <string>

struct Foo
{
Foo( const char* pch )
: str_ ( pch )
{
}
const std::string& str_;
};

int main()
{
Foo f = Foo( "Bar");
std::cout << f.str_ << std::endl;
}

Claudio Puviani

unread,
Jan 2, 2003, 10:36:49 AM1/2/03
to
"Holger Grund" <h.g...@ixtraclick.net> wrote

It's not the responsibility of the language specification or the compiler to
protect the programmer against errors in logic or stupidity (I'm not calling
you stupid, since you understand that this example is bad). It's entirely up to
the programmer to understand about the life cycle of the objects that are
created. For example, as ugly and discouraged as this is, you could create a
class who's only purpose is to do something upon construction and have no other
function whatsoever. In such a case, creating a temporary instance of that
class would just be a different way of invoking a function (the constructor).
Just because I'd personally shoot the programmer who did that, doesn't mean
that the programmer has no right to his or her own stylistic abominations, and
the language and compiler are not there to act as style police.

Claudio Puviani


Victor Bazarov

unread,
Jan 2, 2003, 10:41:23 AM1/2/03
to
"Holger Grund" <h.g...@ixtraclick.net> wrote...

> The following code should be well-formed according to the
> standard. I just don't seem to understand why it should be.

The temporary created to be bound to a const reference should
live as long as the reference.

> Why would you want to have a member reference that is
> valid during the constructor call only?

Why do you say that? A data member lives as long as the object
in which it's defined.

> In the example below
> you could easily make str_ a local variable of Foo::Foo.

Huh?

> I guess I'm missing something. Neither Comeau nor VC
> report a warning.
>
> Any ideas?

Well, stop missing it. The reference is part of the object
defined in the 'main' and tied to the name "f". The reference
lives as long as the object 'f', that is, until function 'main'
exits.

>
> tia
> -hg
>
> // Code
> #include <iostream>
> #include <string>
>
> struct Foo
> {
> Foo( const char* pch )
> : str_ ( pch )
> {
> }
> const std::string& str_;
> };
>
> int main()
> {
> Foo f = Foo( "Bar");
> std::cout << f.str_ << std::endl;
> }
>

Victor
--
Please remove capital A's from my address when replying by mail


Holger Grund

unread,
Jan 2, 2003, 11:21:29 AM1/2/03
to
"Victor Bazarov" <v.Aba...@attAbi.com> wrote
>
> > Why would you want to have a member reference that is
> > valid during the constructor call only?
>
> Why do you say that? A data member lives as long as the object
> in which it's defined.
>
IMHO 12.2.5 says that:
<snip>
A temporary bound to a reference member in constructor's
ctor-initializer (12.6.2) persists until the constructor exits
</snip>

> > Any ideas?
>
> Well, stop missing it. The reference is part of the object
> defined in the 'main' and tied to the name "f". The reference
> lives as long as the object 'f', that is, until function 'main'
> exits.
>

I don't think so. Foo's ctor does not take a std::string! So a
temporary is required to initialize str_. The temporary does
no longer exists after the ctor exits.

Where should it exist? And who does manage its lifetime?
Maybe you can find a solution for the example below but
Foo could be allocated by new a could also have a second
ctor taking a const std::string& to that the reference would
be bound.

Regards
-hg

Victor Bazarov

unread,
Jan 2, 2003, 11:30:17 AM1/2/03
to
"Holger Grund" <h.g...@ixtraclick.net> wrote...

> "Victor Bazarov" <v.Aba...@attAbi.com> wrote
> >
> > > Why would you want to have a member reference that is
> > > valid during the constructor call only?
> >
> > Why do you say that? A data member lives as long as the object
> > in which it's defined.
> >
> IMHO 12.2.5 says that:
> <snip>
> A temporary bound to a reference member in constructor's
> ctor-initializer (12.6.2) persists until the constructor exits
> </snip>

OK. Get it. Thanks.

Holger Grund

unread,
Jan 2, 2003, 11:54:36 AM1/2/03
to

"Claudio Puviani" <cla...@puviani.net> wrote

>
> It's not the responsibility of the language specification or the compiler
to
> protect the programmer against errors in logic or stupidity (I'm not
calling
> you stupid, since you understand that this example is bad). It's entirely
up to
> the programmer to understand about the life cycle of the objects that are
> created. For example, as ugly and discouraged as this is, you could create
a
> class who's only purpose is to do something upon construction and have no
other
> function whatsoever. In such a case, creating a temporary instance of that
> class would just be a different way of invoking a function (the
constructor).
> Just because I'd personally shoot the programmer who did that, doesn't
mean
> that the programmer has no right to his or her own stylistic abominations,
and
> the language and compiler are not there to act as style police.
>
I agree that programmer is responsible for his program. But I think the
language specification should at least try to protect the programmer as
much as possible from undefined behavior at runtime, o.c. without
restricting
him. I.e. if a feature is completely useless and potentially dangerous it
should
not be included in the language specification.

There are other features that are not allowed: e.g. initializing a reference
with a rvalue. Conversion sequence with more than one user-defined
conversion. etc.

I fail to see the unique advantages of member reference bound to
temporary brings. But I do see a problem:

I'd expect the temporary to exist as long as the references exists.
(O.c. if you think about it is not easily feasible to implement that)

Thanks
-hg

tom_usenet

unread,
Jan 2, 2003, 1:29:20 PM1/2/03
to

It isn't that it is included particularly, just that it isn't
disallowed. Disallowing every potential misuse of the features
provided by the specification would increase the size and complexity
of the standard considerably. "Special cases" are a bad thing, IMHO.

>
>There are other features that are not allowed: e.g. initializing a reference
>with a rvalue. Conversion sequence with more than one user-defined
>conversion. etc.
>
>I fail to see the unique advantages of member reference bound to
>temporary brings. But I do see a problem:

You might have a reference member that is only sometimes valid,
depending on how the object is constructed. Since you have to
initialise the reference even if you don't use it, you might want to
initialise it with a temporary since you don't have any non-temporary
handy. I'm not pretending that this is a likely situation, but it is a
possible one.

>
>I'd expect the temporary to exist as long as the references exists.
>(O.c. if you think about it is not easily feasible to implement that)

Well, I doubt that many people who are competent enough to use const
references would look at that code without being suspicious that there
is a dangling reference.

Tom

Holger Grund

unread,
Jan 2, 2003, 3:05:55 PM1/2/03
to
"tom_usenet" <tom_u...@hotmail.com> wrote

> >him. I.e. if a feature is completely useless and potentially dangerous it
> >should
> >not be included in the language specification.
>
> It isn't that it is included particularly, just that it isn't
> disallowed. Disallowing every potential misuse of the features
> provided by the specification would increase the size and complexity
> of the standard considerably. "Special cases" are a bad thing, IMHO.
>
That's a good point. But I don't think it's completely true. 12.2/5
explicitly describes the lifetime of the temporary to which the
reference member is bound (which is an exception from the general
rule where the temporary lives as long as the reference).
Instead the comittee could have explicitly disallow the binding of
reference members to temporaries.

BTW: I don't want to start a religion war about whether this feature
should be removed (never have been added, .. ). I just want to
ensure that I fully understand the feature.

> >
> >There are other features that are not allowed: e.g. initializing a
reference
> >with a rvalue. Conversion sequence with more than one user-defined
> >conversion. etc.
> >
> >I fail to see the unique advantages of member reference bound to
> >temporary brings. But I do see a problem:
>
> You might have a reference member that is only sometimes valid,
> depending on how the object is constructed. Since you have to
> initialise the reference even if you don't use it, you might want to
> initialise it with a temporary since you don't have any non-temporary
> handy. I'm not pretending that this is a likely situation, but it is a
> possible one.
>

But you should be able to use a reference as the function parameter.
In the example:
struct Foo
{
Foo( const std::string& s )
: str_(s) {}
};

The program would still yield undefined behavior. But the version
above does make sense as long as s is not bound to a temporary.
But if the latter is true, it's quite obvious that the temporary is
destroyed after the ctor call because s does not exist anymore.

> >
> >I'd expect the temporary to exist as long as the references exists.
> >(O.c. if you think about it is not easily feasible to implement that)
>
> Well, I doubt that many people who are competent enough to use const
> references would look at that code without being suspicious that there
> is a dangling reference.
>

I guess that's a personal decision. Wouldn't you want to get a warning
from the compiler if you're binding a reference member to a temporary.

Maybe you are right about the example and it is easy
to see that something is wrong. But the actual type could still be
"hidden" as a typedef in some template that may or may not be
a specialization... add what ever you can imagine

Thanks for sharing your thoughts
-hg

Luther Baker

unread,
Jan 2, 2003, 7:35:15 PM1/2/03
to
"Holger Grund" <h.g...@ixtraclick.net> wrote in message news:<av1kfn$7e3$02$1...@news.t-online.com>...

> The following code should be well-formed according to the
> standard. I just don't seem to understand why it should be.
>
> Why would you want to have a member reference that is
> valid during the constructor call only? In the example below
> you could easily make str_ a local variable of Foo::Foo.

Hi Holger,

I don't claim to have an answer here, but Andrei Alexandrescu has a
very good lead article on cuj right now "Generic<Programming>: Move
Constructors" that talks about a related topic - temporaries and
minimizing copying.

http://www.cuj.com/

or specifically

http://www.cuj.com/experts/2102/alexandr.htm

He _does not_ explicity address your question about ctors and
reference members, so in a way, my post might be completely off-base.
But he does talk about temps and what happens to them in the context
of a function call - and it might provide some insight as to potential
_use_ of the behaviour you're questioning.

HTH,

-Luther

Holger Grund

unread,
Jan 2, 2003, 9:10:28 PM1/2/03
to
"Luther Baker" <luthe...@yahoo.com> wrote

>
> Hi Holger,
>
> I don't claim to have an answer here, but Andrei Alexandrescu has a
> very good lead article on cuj right now "Generic<Programming>: Move
> Constructors" that talks about a related topic - temporaries and
> minimizing copying.
>
> http://www.cuj.com/
>
> or specifically
>
> http://www.cuj.com/experts/2102/alexandr.htm
>
> He _does not_ explicity address your question about ctors and
> reference members, so in a way, my post might be completely off-base.
> But he does talk about temps and what happens to them in the context
> of a function call - and it might provide some insight as to potential
> _use_ of the behaviour you're questioning.

Thanks, Luther.
I saw Andrei's postings regarding Mojo in c.s.c++.

I only posted my question to make sure that I don't miss any points
regarding
the initialization of reference members. The discussion cofirmed my
belief that the feature should be (nearly) never used and that compilers
should
issue a warning.
When you need to reference member you can initialize it with a reference
so that no temporary is required (or is created by the caller). If you need
the
reference only during the ctor call then simply create one in the ctor body.

Thanks anyway
-hg


Luther Baker

unread,
Jan 3, 2003, 10:27:08 AM1/3/03
to
"Holger Grund" <h.g...@ixtraclick.net> wrote in message news:<av2req$j3p$02$1...@news.t-online.com>...

> the initialization of reference members. The discussion cofirmed my
> belief that the feature should be (nearly) never used and that compilers
> should
> issue a warning.
> When you need to reference member you can initialize it with a reference
> so that no temporary is required (or is created by the caller). If you need
> the
> reference only during the ctor call then simply create one in the ctor body.

Gotcha.

I see your point that the _feature_ should (nearly) never be used -
but possibly - if you really wish to use a reference, you can _sense_
when you are passed a temporary - and define your internal reference a
little differently.

If you can "gravitate" the temporary object parameter to a different
ctor, then it could implicitly do something like ... dynamically
create said temp on the heap - reference it, and be sure to delete it
... Possibly making it safe to include such a member in your class?

I think you're correct, but wondering if there is a workaround.

-Luther

>
> Thanks anyway
> -hg

Thank YOU.

Holger Grund

unread,
Jan 3, 2003, 11:34:33 AM1/3/03
to

"Luther Baker" <luthe...@yahoo.com> wrote > >

>> When you need to reference member you can initialize it with a reference
> > so that no temporary is required (or is created by the caller). If you
need
> > the
> > reference only during the ctor call then simply create one in the ctor
body.
>
> Gotcha.
>
> I see your point that the _feature_ should (nearly) never be used -
> but possibly - if you really wish to use a reference, you can _sense_
> when you are passed a temporary - and define your internal reference a
> little differently.
>
> If you can "gravitate" the temporary object parameter to a different
> ctor, then it could implicitly do something like ... dynamically
> create said temp on the heap - reference it, and be sure to delete it
> ... Possibly making it safe to include such a member in your class?
>
> I think you're correct, but wondering if there is a workaround.
>
If you have something like
struct Foo
{
const SomeType& ref;
Foo( SomeOtherType temp )
: ref ( temp )
{}
};

Say SomeOtherType is a type that requires the implementation to
create a temporary (i.e. it's not a lvalue and not
reference-compatible with SomeType; could be missing sth here)

Given that you are out of luck. ref is bound to the temporary. The
temporary is destroyed when Foo::Foo exits and ref dangles.
Once it is initalized you cannot bind a reference to another object.

Oc, you could initialize ref by
: ref ( Copy ( temp ) )
or something
but then the reference member is not initialized with a
temporary (from the language spec point of view).

I reported that to Microsoft along with a bug (MSVC does not call
the dtor of the temporary). Let's see what they'll say.

Thanks again.
-hg

0 new messages