 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
AB Guest
|
Posted: Fri Oct 03, 2003 11:42 am Post subject: Question on returning full copies on stack and their referen |
|
|
Hello,
I have already googled through this group but could not find any
response to the following scenario. While in a method, a const
reference is created for a full copy of an object that was returned on
the stack. Is this a valid thing to do or not?
Here is some sample code to illustrate the issue:
#include <iostream>
#include <string>
#include <vector>
class X
{
public:
vector<int> getList() { return(vecX); }
vector<int> &getList2() { return(vecX); }
private:
vector<int> vecX;
};
void fn1(X &xinst)
{
xinst.getList2().push_back(1);
xinst.getList2().push_back(2);
const vector<int> &x2=xinst.getList();
for (int i=0; i < x2.size(); ++i) {
cout << "x " << x2[i] << endl;
}
}
int main(void)
{
X *xinst=new X();
fn1(*xinst);
return 0;
}
The code seems to work fine but the question is, is the constant
reference "x2" pointing to anything valid after calling
xinst.getList() or is it just luck of the draw?
Regards,
AB.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ron Guest
|
Posted: Sat Oct 04, 2003 8:36 am Post subject: Re: Question on returning full copies on stack and their ref |
|
|
| Quote: | I have already googled through this group but could not find any
response to the following scenario. While in a method, a const
reference is created for a full copy of an object that was returned on
the stack. Is this a valid thing to do or not?
Here is some sample code to illustrate the issue:
#include <iostream
#include
#include
class X
{
public:
vector
vector<int> &getList2() { return(vecX); }
private:
vector<int> vecX;
};
void fn1(X &xinst)
{
xinst.getList2().push_back(1);
xinst.getList2().push_back(2);
const vector<int> &x2=xinst.getList();
for (int i=0; i < x2.size(); ++i) {
cout << "x " << x2[i] << endl;
}
}
...
The code seems to work fine but the question is, is the constant
reference "x2" pointing to anything valid after calling
xinst.getList() or is it just luck of the draw?
|
Your code is OK, but I wouldn't make a habit of it. Ordinarily,
temporaries are destroyed at the end of the full-expression that
creates them. s.12.2(3). However, when you bind a reference to a
temporary, the temporary's lifetime generally is extended to match the
reference's lifetime. s.12.2(5). This occurs when binding a reference
to a function's return value; s.12.2(5) says, "A temporary bound to
the returned value in a function return statement (6.6.3) persists
until the function exits." This is a little inartfully phrased, but
s.12.2(5)'s example clarifies it:
------
class C {
// ...
public:
C();
C(int);
friend C operator+(const C&, const C&);
~C();
};
C obj1;
const C& cr = C(16)+C(23);
C obj2;
....
The temporary T3 bound to the reference cr is destroyed at the end of
cr's lifetime, that is, at the end of the program.
------
-Ron
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Joshua Lehrer Guest
|
Posted: Sat Oct 04, 2003 8:38 am Post subject: Re: Question on returning full copies on stack and their ref |
|
|
[email]alb09439 (AT) hotmail (DOT) com[/email] (AB) wrote in message news:<ffcb4c91.0310021547.730dcb86 (AT) posting (DOT) google.com>...
| Quote: | Hello,
I have already googled through this group but could not find any
response to the following scenario. While in a method, a const
reference is created for a full copy of an object that was returned on
the stack. Is this a valid thing to do or not?
|
This initial value of a refernce to non-const must be an lvalue.
T func();
const T& obj(func()); //ok
const T& obj=func(); //ok, same as above
const T& obj=T(1,2,3); //ok
T& obj=func(); //not ok
T& obj=T(1,2,3); //not ok
Temporary objects returned, either from function calls or by calling
constructors directly, may be bound to const references, but not to
non-const references.
The lifetime of the temporary object is guaranteed to be longer than
the lifetime of the reference to which it is bound.
joshua lehrer
factset research systems
NYSE:FDS
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Le Chaud Lapin Guest
|
Posted: Sat Oct 04, 2003 8:39 am Post subject: Re: Question on returning full copies on stack and their ref |
|
|
[email]alb09439 (AT) hotmail (DOT) com[/email] (AB) wrote in message news:<ffcb4c91.0310021547.730dcb86 (AT) posting (DOT) google.com>...
| Quote: | class X
{
public:
vector<int> getList() { return(vecX); }
vector<int> &getList2() { return(vecX); }
private:
vector<int> vecX;
};
void fn1(X &xinst)
{
xinst.getList2().push_back(1);
xinst.getList2().push_back(2);
const vector<int> &x2=xinst.getList();
for (int i=0; i < x2.size(); ++i) {
cout << "x " << x2[i] << endl;
}
}
The code seems to work fine but the question is, is the constant
reference "x2" pointing to anything valid after calling
xinst.getList() or is it just luck of the draw?
|
Yes.
It is best to think of xinst.getList() "yielding" an object, and that
object getting slammed into another, "nameless" object of equal size
[sizeof(X)] occupying some space specifically reserved for it on the
stack. In this case, x2 happens to refer to that "nameless" stack
object.
-Chaud Lapin-
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Brian McKeever Guest
|
Posted: Sat Oct 04, 2003 1:53 pm Post subject: Re: Question on returning full copies on stack and their ref |
|
|
[email]alb09439 (AT) hotmail (DOT) com[/email] (AB) wrote in message news:<ffcb4c91.0310021547.730dcb86 (AT) posting (DOT) google.com>...
[snip]
| Quote: | const vector<int> &x2=xinst.getList();
for (int i=0; i < x2.size(); ++i) {
cout << "x " << x2[i] << endl;
}
[snip]
The code seems to work fine but the question is, is the constant
reference "x2" pointing to anything valid after calling
xinst.getList() or is it just luck of the draw?
|
Yes, the code is fine. getList() returns a copy of the member
variable. The temporary that is returned is bound to the reference,
which extends its lifetime. If you had just called getList() and not
done anything with the returned vector, the temporary would have been
destroyed immediately. It's a special case to make it work the way
you think it should.
Brian
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Sun Oct 05, 2003 12:40 am Post subject: Re: Question on returning full copies on stack and their ref |
|
|
In article <c668c1f8.0310030940.12390bb4 (AT) posting (DOT) google.com>, Ron
<rcrane (AT) ictv (DOT) com> writes
| Quote: | Your code is OK, but I wouldn't make a habit of it. Ordinarily,
temporaries are destroyed at the end of the full-expression that
creates them. s.12.2(3). However, when you bind a reference to a
temporary, the temporary's lifetime generally is extended to match the
reference's lifetime. s.12.2(5).
|
Note that you cannot bind a temporary to a reference but only to a const
reference.
--
Francis Glassborow ACCU
If you are not using up-to-date virus protection you should not be reading
this. Viruses do not just hurt the infected but the whole community.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Maciej Sobczak Guest
|
Posted: Mon Oct 06, 2003 12:50 pm Post subject: Re: Question on returning full copies on stack and their ref |
|
|
Hi,
Joshua Lehrer wrote:
| Quote: | The lifetime of the temporary object is guaranteed to be longer than
the lifetime of the reference to which it is bound.
|
Of course, we have to be aware of the following gotcha:
struct A {};
struct B
{
B(const A &a) : ref(a) {}
const A &ref;
};
A fun() { return A(); }
int main()
{
B b(fun());
// b.ref is dangling here
}
Here, the temporary object A() is bound to the const reference in the
B's constructor, *but no longer*. In other words, after the B's
constructor finishes, the temporary can be destroyed and from that time
the b's ref member is a dangling reference.
So - carefully with refs to temps.
--
Maciej Sobczak
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
AB Guest
|
Posted: Tue Oct 07, 2003 6:13 pm Post subject: Re: Question on returning full copies on stack and their ref |
|
|
Maciej Sobczak <maciej (AT) maciejsobczak (DOT) com> wrote
| Quote: | Hi,
Joshua Lehrer wrote:
The lifetime of the temporary object is guaranteed to be longer than
the lifetime of the reference to which it is bound.
Of course, we have to be aware of the following gotcha:
struct A {};
struct B
{
B(const A &a) : ref(a) {}
const A &ref;
};
A fun() { return A(); }
int main()
{
B b(fun());
// b.ref is dangling here
}
Here, the temporary object A() is bound to the const reference in the
B's constructor, *but no longer*. In other words, after the B's
constructor finishes, the temporary can be destroyed and from that time
the b's ref member is a dangling reference.
So - carefully with refs to temps.
|
Hello again,
How about the following example based on your example
above(which is where the original problem occurred):
class C
{
public:
C() { ax=new(fun()); }
A getA() { return(*ax); }
~C() { delete ax; }
private:
A *ax;
}; /* class C */
int main()
{
C *cx=new C();
B bx(cx->getA());
// do some stuff with bx here using its (const A& ref)
delete cx;
}
Does this also cause the dangling reference issue in B that you
mentioned in your previous example?
Regards,
AB.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ron Natalie Guest
|
Posted: Tue Oct 07, 2003 7:14 pm Post subject: Re: Question on returning full copies on stack and their ref |
|
|
"AB" <alb09439 (AT) hotmail (DOT) com> wrote
| Quote: | Does this also cause the dangling reference issue in B that you
mentioned in your previous example?
|
No, as long as the A object is still existant that's fine. Of course your code
is fraught with peril because bx lives longer than *cx. If you declared the
C variable locally it would make it safer:
int main() {
C cx;
B bx(cx->getA());
}
bx will be destructed before cx.
By the way, if you use the example code, make sure you implement the copy constructor
and copy-assignment operator for your C class, because if they ever get invoked, your
class will get trashed.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Glen Low Guest
|
Posted: Sat Nov 29, 2003 4:50 pm Post subject: Re: Question on returning full copies on stack and their ref |
|
|
| Quote: | Of course, we have to be aware of the following gotcha:
struct A {};
struct B
{
B(const A &a) : ref(a) {}
const A &ref;
};
A fun() { return A(); }
int main()
{
B b(fun());
// b.ref is dangling here
}
Here, the temporary object A() is bound to the const reference in the
B's constructor, *but no longer*. In other words, after the B's
constructor finishes, the temporary can be destroyed and from that time
the b's ref member is a dangling reference.
|
Minor pedantry: it should be "after the statement B b(fun());
completes, the temporary can be destroyed." In your case it is the
same as "after the constructor finishes", but you can also do:
B (fun()).something ();
and the temporary should last until the something completes.
According to 12.2/5, there are two possibilities:
"a temporary bound to a reference member in a constructor's
ctor-initializer (class.base.init) persists until the constructor
exits"
OR
"a temporary bound to a reference parameter in a function call
(expr.call) persists until the completion of the full expression
containing the call"
However in a previous thread discussing this, the consensus was the
first applies to temporaries created within a ctor-initializer, so the
first statement does not apply. Therefore the second must apply, since
a constructor is also a function call.
Some empirical tests on gcc seem to confirm this, but I have yet to
experiment in detail with other compilers.
Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|