By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,760 Members | 1,630 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,760 IT Pros & Developers. It's quick & easy.

Understanding branches within destructors

P: n/a
Hello,

Could anyone explain to me why the following class's destructor shows
up as having multiple branches? (At least as judged by gcov 4.1.2
when compiled with gcc 4.1.2 ):

struct blah
{
blah();
virtual ~blah();
};

blah::blah()
{
}

blah::~blah()
{
}

int main()
{
blah myBlah;

return 0;
}
The output from gcov showing these branches (with 1 not taken):

1: 11:blah::~blah()
-: 12:{
1: 13:}
branch 0 never executed
branch 1 never executed
call 2 never executed
branch 3 taken 0 (fallthrough)
branch 4 taken 1
call 5 never executed
branch 6 never executed
branch 7 never executed
call 8 never executed

Please note that if I make the destructor non-virtual, the branches go
away. Is what I'm seeing here a relic of the tool, or is there
something going on the language that causes this?
Oct 24 '08 #1
Share this Question
Share on Google+
6 Replies


P: n/a
On Oct 24, 1:46*pm, Jeff Newman <Jeffrey.M.New...@gmail.comwrote:
Hello,

Could anyone explain to me why the following class's destructor shows
up as having multiple branches? *(At least as judged by gcov 4.1.2
when compiled with gcc 4.1.2 ):

struct blah
{
* blah();
* virtual ~blah();

};

blah::blah()
{

}

blah::~blah()
{

}

int main()
{
* blah myBlah;

* return 0;

}

The output from gcov showing these branches (with 1 not taken):

* * * * 1: * 11:blah::~blah()
* * * * -: * 12:{
* * * * 1: * 13:}
branch *0 never executed
branch *1 never executed
call * *2 never executed
branch *3 taken 0 (fallthrough)
branch *4 taken 1
call * *5 never executed
branch *6 never executed
branch *7 never executed
call * *8 never executed

Please note that if I make the destructor non-virtual, the branches go
away. *Is what I'm seeing here a relic of the tool, or is there
something going on the language that causes this?
The branches are most likely part of the virtual function dispatch
code that gcc put in the destructor. My understanding is that
compilers may locate virtual function dispatch code wherever they
want, and gcc chooses to put in in the function itself, at least in
the case of a virtual destructor.
Oct 24 '08 #2

P: n/a
The branches are most likely part of the virtual function dispatch
code that gcc put in the destructor. My understanding is that
compilers may locate virtual function dispatch code wherever they
want, and gcc chooses to put in in the function itself, at least in
the case of a virtual destructor.
What style of call would then result in taking the other branches?
I've tried the following (which is all the cases I can think of), and
there are still unexecuted branches.

struct blah
{
blah() {};
virtual ~blah()
{
};
};
struct derived : blah
{
derived() {};

~derived() {};
};

int main()
{
blah myBlah;
blah* myDerived = new derived();
delete myDerived;

derived myDerived2;

return 0;
}

The (snipped) report:
3: 4: virtual ~blah()
3: 5: {
3: 6: };
branch 0 never executed
branch 1 never executed
call 2 never executed
branch 3 taken 0 (fallthrough)
branch 4 taken 2
call 5 never executed
branch 6 taken 0 (fallthrough)
branch 7 taken 1
call 8 never executed
-: 7:};

Oct 24 '08 #3

P: n/a
On Fri, 24 Oct 2008 12:12:18 -0700, Jeff Newman wrote:
>The branches are most likely part of the virtual function dispatch code
that gcc put in the destructor. My understanding is that compilers may
locate virtual function dispatch code wherever they want, and gcc
chooses to put in in the function itself, at least in the case of a
virtual destructor.

What style of call would then result in taking the other branches? I've
tried the following (which is all the cases I can think of), and there
are still unexecuted branches.
[snip]
>
The (snipped) report:
3: 4: virtual ~blah()
3: 5: {
3: 6: };
branch 0 never executed
branch 1 never executed
call 2 never executed
branch 3 taken 0 (fallthrough)
branch 4 taken 2
call 5 never executed
branch 6 taken 0 (fallthrough)
branch 7 taken 1
call 8 never executed
-: 7:};
It's implementation details. You're better off
asking the experts at the gcc mailing lists.

http://gcc.gnu.org/lists.html

--
OU
Remember 18th of June 2008, Democracy died that afternoon.
http://frapedia.se/wiki/Information_in_English
Oct 24 '08 #4

P: n/a
On Oct 24, 8:12*pm, Jeff Newman <Jeffrey.M.New...@gmail.comwrote:
The branches are most likely part of the virtual function dispatch
code that gcc put in the destructor. My understanding is that
compilers may locate virtual function dispatch code wherever they
want, and gcc chooses to put in in the function itself, at least in
the case of a virtual destructor.

What style of call would then result in taking the other branches?
I've tried the following (which is all the cases I can think of), and
there are still unexecuted branches.

struct blah
{
* blah() {};
* virtual ~blah()
* {
* };

};

struct derived : blah
{
* derived() {};

* ~derived() {};

};

int main()
{
* blah myBlah;
* blah* myDerived = new derived();
* delete myDerived;

* derived myDerived2;

* return 0;

}

The (snipped) report:
* * * * 3: * *4: *virtual ~blah()
* * * * 3: * *5: *{
* * * * 3: * *6: *};
branch *0 never executed
branch *1 never executed
call * *2 never executed
branch *3 taken 0 (fallthrough)
branch *4 taken 2
call * *5 never executed
branch *6 taken 0 (fallthrough)
branch *7 taken 1
call * *8 never executed
* * * * -: * *7:};
It's most likely (given that you're using GCC) that it instantiates
two destructors - one for if it is a non-virtual base class (which
means that it calls its parent destructors) and when it is (which
means that it does not call its parent destructors). Your virtual
function table contains two functions too.

If it's nonvirtual it should still generate both of them, but it might
notice that it has no base classes and that they are equal, and hence
merge them. It also might not generate one of them as nobody calls it.
In case of virtual functions, somebody outside of your scope of
compilation might call it anyway, so it has to generate it and put it
in the virtual function table - so it has to be made, and then has
uncalled code.

Could you try the test again using it as a virtual base in one
subclass?

Regards,
Peter
Oct 29 '08 #5

P: n/a
What style of call would then result in taking the other branches?
I've tried the following (which is all the cases I can think of), and
there are still unexecuted branches.

Don't forget about placement new:

http://www.parashift.com/c++-faq-lit...html#faq-11.10
Sean

Oct 29 '08 #6

P: n/a
On Oct 29, 8:52 pm, "dasca...@gmail.com" <dasca...@gmail.comwrote:
On Oct 24, 8:12 pm, Jeff Newman <Jeffrey.M.New...@gmail.comwrote:
[...concerning multiple entry points for destructors...]
The (snipped) report:
3: 4: virtual ~blah()
3: 5: {
3: 6: };
branch 0 never executed
branch 1 never executed
call 2 never executed
branch 3 taken 0 (fallthrough)
branch 4 taken 2
call 5 never executed
branch 6 taken 0 (fallthrough)
branch 7 taken 1
call 8 never executed
-: 7:};
It's most likely (given that you're using GCC) that it
instantiates two destructors - one for if it is a non-virtual
base class (which means that it calls its parent destructors)
and when it is (which means that it does not call its parent
destructors). Your virtual function table contains two
functions too.
Either I've misunderstood what you wrote, or you got it wrong.
The different entry points used depend on whether the destructor
is for the most derived class or not; roughly speaking, calls
from outside go to one, and calls from a derived class
destructor go to the other. The difference is that the calls
from a derived class destructor must not call the destructors of
any virtual base classes; those from the most derived class must
call the destructors of any virtual base classes *after* having
called the destructors of the non-virtual base classes. (I
think that the words "in charge" appear in output of nm -C for
the constructor called when the class is the most derived
class.)
If it's nonvirtual it should still generate both of them, but
it might notice that it has no base classes and that they are
equal, and hence merge them. It also might not generate one of
them as nobody calls it. In case of virtual functions,
somebody outside of your scope of compilation might call it
anyway, so it has to generate it and put it in the virtual
function table - so it has to be made, and then has uncalled
code.
The not most derived class case is never called using virtual
function resolution, so it needed appear in the vtable.
Could you try the test again using it as a virtual base in one
subclass?
I think the test would have to be:

class B {} ;
class D1 : public virtual B {} ;
class D2 : public D1 {} ;

, then call the destructor on an instance of D1 and on an
instance of D2. If I understand it corretly, this should call
both destructors of D1.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Oct 30 '08 #7

This discussion thread is closed

Replies have been disabled for this discussion.