I have some problems with destructor, in next code:
#include <stdlib.h>
#include <cstdio>
class Foo2
{
public:
Foo2() { printf("foo2 const\n"); }
~Foo2()
{
printf("foo2 dest\n"); // <--- wasn't called for bionic libc
}
};
static Foo2& GetFoo2()
{
static Foo2 foo2;
printf ("return foo2\n");
return foo2;
}
class Foo1
{
public:
Foo1() { printf("foo1 const\n"); }
~Foo1()
{
printf("foo1 dest\n");
GetFoo2();
}
};
int main( int argc, const char* argv[] )
{
printf("main 1 \n");
static Foo1 anotherFoo;
printf("main 2 \n");
}
Why destructor for foo2 wasn't called for bionic
and was for glibc
?
EDIT
Output for bionic:
main 1
foo1 const
main 2
foo1 dest
foo2 const
return foo2
Debug info:
(gdb) break 22
Breakpoint 1 at 0x8048858: file test.C, line 22.
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x08048858 in Foo2::~Foo2() at test.C:22
(gdb) cont
[ exited with code 0]
At the point at which the program returns from
main
,anotherFoo
has been initialised; butfoo2
hasn't, since it is not initialised until the first call toGetFoo2
during the destruction ofanotherFoo
. Therefore, a strict interpretation of the rules would imply that its destructor should not be called.static object will be destroyed when program exists. put a break point at
~Foo2()
, you will see it or write log to a file should help you diagnose it. If really not called then it's a compiler bug.And it's fun to upload a pic to answer a question.
I think your code has undefined behavior, although the standard isn't really clear about it (or I can't find it in the standard). Your code constructs a new static object in the destructor of a static object. The standard doesn't address this case, but:
It does say that destructors must be called in the reverse order of construction. In your case, this would imply that the static object in
GetFoo2
must be destructed before it was constructed, which is self-contradictory.The text in §3.6/3 describes the sequencing of destructors and functions registered with
atexit
. The requirements are such that the same registration mechanism must be used for each. And callingatexit
once you've calledexit
(or returned frommain
) is undefined behavior.There's also §3.6/2, which says that "If a function contains a block-scope object of static or thread storage duration that has been destroyed and the function is called during the destruction of an object with static or thread storage duration, the program has undefined behavior if the flow of control passes through the definition of the previously destroyed blockscope object." This sentence talks about alread destroyed objects, but it doesn't take much imagination to think that the absense of "not yet constructed" objects is just an oversight.
In the end, I'd say that my first point above is conclusive with regards to intent. In §1.3.24, there is a note (non normative, but indicative of intent) "Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data." In this case, the only description of the required behavior is impossible (since you cannot destruct an object before it was constructed), and the standard says nothing about how this should be resolved.
All the instances I see in this code are static.
By consequence their destructor is called at the end of the executable, after main is finished.
if the destructor wasn't called then it was a bug.