Devirtualize virtual call hierarchy if just base dtor exists
Jonathan Wakely
jwakely.gcc@gmail.com
Wed Oct 22 17:04:00 GMT 2014
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.
More information about the Gcc
mailing list