See the program below. The program should print 1 as 1 counter object still exists, but when compiled with GCC, it prints 0. Why is that? Is this a compiler bug? This only occurs when returning from a different scope. Removing the if completely fixes it on all compilers.
#include <iostream>
int counter = 0;
class Counter {
public:
Counter() {
counter ;
}
~Counter() {
counter--;
}
};
Counter test() {
if (true) { // REMOVING THIS FIXES IT
Counter c;
return c;
} else {
throw std::logic_error("Impossible!");
}
}
int main() {
Counter c = test();
std::cout << counter << std::endl; // 0 on GCC (incorrect), 1 on clang (correct)
return 0;
}
CodePudding user response:
In C returning an object from a function copy-constructs the object in the caller's context, then destroys the copied-from object, in the function being returned from. In some circumstances this copy can be elided.
Counter c;
return c;
This is named return value optimization and it is not mandatory in this case. Copy elision here is allowed, but it's optional. One of the compilers you used elides this copy, the other does not.
Without copy elision the compiler copy-constructs the returned object in the caller's context.
This Counter
lacks a copy constructor, so the shown code fails to log an instance of the copy-constructed object.
Simply add a copy constructor:
class Counter {
public:
Counter() {
counter ;
}
Counter(const Counter &) {
counter ;
}
~Counter() {
counter--;
}
};
Now, you'll get the expected result, with or without copy elision.
If you set a breakpoint in the copy-constructor you'll see the breakpoint hit when returning from the function (when using the compiler that does not elide the copy).
CodePudding user response:
The destructor
is called at the end of the scope that has had objects in.
- When the first line - in
main
- excited, it will calltest()
. - As you have put the condition true, it will create an object, which
will increase
counter
by one. - It will
return c
, but on the other hand, it's the end of the scope, which means that thedestructor
will be called, thuscounter--
.
To be honest, I am not sure about my answer, but I think that what it is.