This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Devirtualize virtual call hierarchy if just base dtor exists
- From: Jonathan Wakely <jwakely dot gcc at gmail dot com>
- To: Martin LiÅka <mliska at suse dot cz>
- Cc: "gcc at gcc dot gnu dot org" <gcc at gcc dot gnu dot org>
- Date: Wed, 22 Oct 2014 18:04:30 +0100
- Subject: Re: Devirtualize virtual call hierarchy if just base dtor exists
- Authentication-results: sourceware.org; auth=none
- References: <5447CA0D dot 7070704 at suse dot cz> <CAH6eHdQ6-+sY8RUc9tGUhcX8u496vNJmToZdQwLNEd+4Z-MtUw at mail dot gmail dot com> <5447D84F dot 50506 at suse dot cz>
On 22 October 2014 17:16, Martin LiÅka <mliska@suse.cz> wrote:
> On 10/22/2014 05:30 PM, Jonathan Wakely wrote:
>>
>> On 22 October 2014 16:15, Martin LiÅka wrote:
>>>
>>> Hello.
>>>
>>> I've been playing with following example:
>>>
>>> #include <stdlib.h>
>>>
>>> class Base
>>> {
>>> public:
>>> virtual ~Base() {}
>>> };
>>>
>>> class Derived: public Base
>>> {
>>> };
>>>
>>> #define N 1000
>>>
>>> int main()
>>> {
>>> Base **b = (Base **)malloc (sizeof(Base *) * N);
>>> for (unsigned i = 0; i < N; i++)
>>> b[i] = new Derived();
>>>
>>> for (unsigned i = 0; i < N; i++)
>>> delete b[i];
>>>
>>> return 0;
>>> }
>>>
>>> Where I would like to somehow give an advice to devirtualize machinery.
>>> My
>>> motivation is to inline destruction in 'delete b[i]'.
>>> 'final' keyword does not solve my problem:
>>>
>>> a.c:9:7: error: virtual function âvirtual Derived::~Derived()â
>>> class Derived: public Base
>>> ^
>>> a.c:6:11: error: overriding final function âvirtual Base::~Base()â
>>> virtual ~Base() final {}
>>
>>
>> Virtual destructors are special, derived classes *must* override them,
>> so you can't make it final in the base class.
>>
>>> If I enclose my classes to anonymous namespace:
>>>
>>> Procesing function int main()/172
>>> Targets of polymorphic call of type 0:struct Base token 2
>>> Contained in type:struct Base at offset 0
>>> This is a complete list. (derived types included)
>>> virtual {anonymous}::Base::~Base()/164 virtual
>>> {anonymous}::Derived::~Derived()/183
>>>
>>> More than one likely target
>>
>>
>> Presumably because the dynamic type of *b[i] could be Base or Derived,
>> and the compiler can't know until it checks it. Does it make any
>> difference if you make Base an abstract class? In that case the
>> compiler should know that the dynamic type of *b[i] cannot be Base, so
>> must be a Derived.
>
>
>
> Looks that addition of an abstract method to Base class really helps:
>
> for (unsigned i = 0; i < N; i++)
> delete b[i];
> 4006a0: 48 8b 3b mov (%rbx),%rdi
> 4006a3: 48 85 ff test %rdi,%rdi
> 4006a6: 74 05 je 4006ad <main+0x4d>
> public:
> virtual ~Base() {}
> virtual void Foo() = 0;
> };
>
> class Derived final: public Base
> 4006a8: e8 83 ff ff ff callq 400630 <_ZdlPv@plt>
> 4006ad: 48 83 c3 08 add $0x8,%rbx
Cool, that's what I expected.
However, if you have more than one type that inherits from Base and
either Derived or Derived2 has a non-trivial destructor then it
probably won't help, as the compiler still needs to do a check to see
which destructor to call.
And if you don't have more than derived type why are you using
polymorphism in the first place? i.e. I expect it will only help with
pointless examples, not real code.