7
TestObject getObject(){
    TestObject a(5.0f);
    return a;
}

int main(){
    TestObject a = getObject();
}

Am I right in saying that in C++ a returned object will not have it's destructor called as it is returned. Is the memory that the object took up in the function call simply deleted without running the destructor?

Ok a specific example..

#include <iostream>

class Test{
public:
 Test(){};
 ~Test(){std::cout << "Goodbye cruel world\n";}
};


Test getAnObject(){
 Test a;
 return a;
}

int main(){
 Test a = getAnObject();
}

If I run this the destructor is run just once (not for the local object in getAnObject()). Can I assume this will always be the case?

#include <iostream>

class Test{
public:
 Test(){};
 ~Test(){std::cout << "Goodbye cruel world\n";}
};


Test getAnObject(){
 Test a;
 Test b;
 int i = 0;
 if (i){
  return a;
 }else{
  return b;
 }
}

int main(){
 Test a = getAnObject();
}

Following the RVO guide this test has the destructor run on both objects in getanobject() and in the main function. Is this a case where I should always implement rule of three to ensure consistent behaviour?

1
  • 5
    getObject is prototyped to return an int... not a TestObject. Commented Dec 9, 2010 at 15:53

7 Answers 7

9

If I run this the destructor is run just once (not for the local object in getAnObject()). Can I assume this will always be the case?

For correctness? No. For efficiency? Yes. -ish.

To elaborate: strictly speaking, the local object will be copied when returning from the function. The local storage will then be cleaned up by calling the local object’s destructor.

However, the compiler is free to generate different code that yields the same observable behaviour. In particular, the standard grants the compilers the right to elide the copying of the return value, and reuse the same storage location for both objects (the local object and the receiving object of the return value). In doing so, the compiler might not need to call the copy constructor, nor the destructor (since it’s reusing the same memory location).

However, this optimization (called “named return value optimization”, NRVO) is not guaranteed by the standard (and in fact it’s not possible to perform everywhere). You cannot assume that it will happen for correctness. In particular, your object still needs a well-defined copy constructor and destructor, otherwise the program is ill-formed.

On the other hand, you can reasonably expect all modern compilers to perform this optimization where ever it is possible. You can therefore (usually) rely on this optimization from a performance point of view.

Sign up to request clarification or add additional context in comments.

2 Comments

Wrong. The program is ill-formed, a diagnostic is required, and so the behaviour is, in fact, well defined.
@Yttrill: Thanks for the correction. I wasn’t sure whether a diagnostic was required.
5

It is implementation based. It is knows as Return Value Optimization technique. Check this out for more info:

http://en.wikipedia.org/wiki/Return_value_optimization

Comments

3

getObject() would return a copy of a. Here is what happens if the compiler does not do any optimization. A temporary copy of a will be created using the copy constructor of TestObject. Then the original a will be destroyed, and its destructor will be called, and then the temporary object will be copied into the local variable a in the main() function. The temporary will then also be destroyed, and its destructor will be called.

Since the return value of getObject() is immediately assigned to a variable in this particular case, a modern compiler will probably be able to optimize away at least one of the copy operations.

3 Comments

int getObject() must return int, I guess
not necessarily; it can be optimized out as other people have said with RVO.
@tenfour, I was not saying about optimization, I was pointing out to the fact that this function was returning int, not TestObject
0

getObject() would return a copy of a, and the original object created in getObject is destroyed on exiting the function, but there can be Return Value Optimization (depends on the compiler you're using).

Comments

0

Besides the mismatched return types in the example, you are probably looking for return value optimization, or more general, copy elision. If I remember correctly, the copy elision rules are even specified in the C++ standard, although somewhat vague.

Comments

0

Is the memory that the object took up in the function call simply deleted without running the destructor?

No. With optimizations disabled, the local object will be destructed (and the destructor invoked). If a copy-elision optimization takes place, the local object will really just be a "reference" (note the quotes) for the one in main - in that case the destructor will not be run within the function, but the memory will not be de-allocated either.

Comments

-1

In getObject, you are creating TestObject on the stack, so the return value is invalid. To create an object on the heap, use "new". I don't believe the destructor is called when the method's scope is exited, I think the memory on the stack is simply reclaimed.

4 Comments

@flatline: depends. Either way, this code is absolutely valid. Whether or not the copy constructor is invoked depends on whether the compiler will optimize the code.
The destructor of an object on the stack that goes out of scope is called automatically.
@Bill: What Konrad is eluding too is that the compiler may perform NRVO which removes the need for a copy and a destruction as the local variable is created in the return location. But yes you should look at this as 1) Construct Locale object. 2) Copy locale object out (to dest) 3) Destroy locale copy. NRVO is the elimination of steps (2) and (3)
@Martin: true, but I was actually commenting on the OP, who claimed "I don't believe the destructor is called when the method's scope is exited".

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.