[ACCEPTED]-C++: returning by reference and copy constructors-return-by-reference
The best way to understand copying in C++ is 6 often NOT to try to produce an artificial 5 example and instrument it - the compiler 4 is allowed to both remove and add copy constructor 3 calls, more or less as it sees fit.
Bottom 2 line - if you need to return a value, return 1 a value and don't worry about any "expense".
Recommended reading: Effective C++ by Scott Meyers. You 34 find a very good explanation about this 33 topic (and a lot more) in there.
In brief, if 32 you return by value, the copy constructor 31 and the destructor will be involved by default 30 (unless the compiler optimizes them away 29 - that's what happens in some of your cases).
If 28 you return by reference (or pointer) a variable 27 which is local (constructed on the stack), you 26 invite trouble because the object is destructed 25 upon return, so you have a dangling reference 24 as a result.
The canonical way to construct 23 an object in a function and return it is 22 by value, like:
MyClass fun() {
return MyClass(a, b, c);
}
MyClass x = fun();
If you use this, you don't 21 need to worry about ownership issues, dangling 20 references etc. And the compiler will most 19 likely optimize out the extra copy constructor 18 / destructor calls for you, so you don't 17 need to worry about performance either.
It 16 is possible to return by reference an object 15 constructed by new
(i.e. on the heap) - this 14 object will not be destroyed upon returning 13 from the function. However, you have to 12 destroy it explicitly somewhere later by 11 calling delete
.
It is also technically possible 10 to store an object returned by value in 9 a reference, like:
MyClass& x = fun();
However, AFAIK there is 8 not much point in doing this. Especially 7 because one can easily pass on this reference 6 to other parts of the program which are 5 outside of the current scope; however, the 4 object referenced by x
is a local object 3 which will be destroyed as soon as you leave 2 the current scope. So this style can lead 1 to nasty bugs.
read about RVO and NRVO (in a word these two 5 stands for Return Value Optimization and 4 Named RVO, and are optimization techniques 3 used by the compiler to do what you're trying 2 to achieve)
you'll find a lot of subjects 1 here on stackoverflow
If you create an object like this:
MyClass foo(a, b, c);
then it 14 will be on the stack in the function's frame. When 13 that function ends, its frame is popped 12 off the stack and all the objects in that 11 frame are destructed. There is no way to avoid this.
So if you want to 10 return an object to a caller, you only options 9 are:
- Return by value - a copy constructor is required (but the call to the copy constructor may be optimised out).
- Return a pointer and make sure you either use smart pointers to deal with it or carefully delete it yourself when done with it.
Attempting to construct a local object 8 and then return a reference to that local 7 memory to a calling context is not coherent 6 - a calling scope can not access memory 5 that is local to the called scope. That 4 local memory is only valid for the duration 3 of the function that owns it - or, another 2 way, while execution remains in that scope. You 1 must understand this to program in C++.
About the only time it makes sense to return 49 a reference is if you're returning a reference 48 to a pre-existing object. For an obvious 47 example, nearly every iostream member function 46 returns a reference to the iostream. The 45 iostream itself exists before any of the 44 member functions is called, and continues 43 to exist after they're called.
The standard 42 allows "copy elision", which means the copy 41 constructor doesn't need to be called when 40 you return an object. This comes in two 39 forms: Name Return Value Optimization (NRVO) and 38 anonymous Return Value Optimization (usually 37 just RVO).
From what you're saying, your 36 compiler implements RVO but not NRVO -- which 35 means it's probably a somewhat older compiler. Most 34 current compilers implement both. The un-matched 33 dtor in this case means it's probably something 32 like gcc 3.4 or thereabouts -- though I 31 don't remember the version for sure, there 30 was a one around then that had a bug like 29 this. Of course, it's also possible that 28 your instrumentation isn't quite right, so 27 a ctor that you didn't instrument is being 26 used, and a matching dtor is being invoked 25 for that object.
In the end, you're stuck 24 with one simple fact though: if you need 23 to return an object, you need to return 22 an object. In particular, a reference can 21 only give access to a (possibly modified 20 version of) an existing object -- but that 19 object had to be constructed at some point 18 as well. If you can modify some existing 17 object without causing a problem, that's 16 fine and well, go ahead and do it. If you 15 need a new object different and separate 14 from those you already have, go ahead and 13 do that -- pre-creating the object and passing 12 in a reference to it may make the return 11 itself faster, but won't save any time overall. Creating 10 the object has about the same cost whether 9 done inside or outside the function. Any 8 reasonably modern compiler will include 7 RVO, so you won't pay any extra cost for 6 creating it in the function, then returning 5 it -- the compiler will just automate allocating 4 space for the object where it's going to 3 be returned, and have the function construct 2 it "in place", where it'll still be accessible 1 after the function returns.
Basically, returning a reference only makes 9 sense if the object still exists after leaving 8 the method. The compiler will warn you if 7 you return a reference to something that 6 is being destroyed.
Returning a reference 5 rather than an object by value saves copying 4 the object which might be significant.
References 3 are safer than pointers because they have 2 different symantics, but behind the scenes 1 they are pointers.
One potential solution, depending on your 15 use case, is to default-construct the object 14 outside of the function, take in a reference 13 to it, and initialize the referenced object 12 within the function, like so:
void initFoo(Foo& foo)
{
foo.setN(3);
foo.setBar("bar");
// ... etc ...
}
int main()
{
Foo foo;
initFoo(foo);
return 0;
}
Now this of 11 course does not work if it is not possible 10 (or does not make sense) to default-construct 9 a Foo
object and then initialize it later. If 8 that is the case, then your only real option 7 to avoid copy-construction is to return 6 a pointer to a heap-allocated object.
But 5 then think about why you are trying to avoid 4 copy-construction in the first place. Is 3 the "expense" of copy construction really 2 affecting your program, or is this a case 1 of premature optimization?
You are stucked with either:
1) returning 8 a pointer
MyClass* func(){ //some stuf return 7 new MyClass(a,b,c); }
2) returning a copy 6 of the object MyClass func(){ return MyClass(a,b,c); }
Returning 5 a reference is not valid because the object 4 is to be destroyed after exiting the func 3 scope, except if the function is a member 2 of the class and the reference is from a 1 variable that is member of the class.
Not a direct answer, but a viable suggestion: You 4 could also return a pointer, wrapped in 3 an auto_ptr or smart_ptr. Then you'll be 2 in control of what constructors and destructors 1 get called and when.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.