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;
}
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
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
> > 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
OK. Get it. Thanks.
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
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
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
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.
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
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
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.
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