4

Sample code:

class base {
  int val1;

public:
  base(int val): val1(val)
  {
  }

  virtual void basefunc()
  {
    std::cout << "I am in base func";
  }
  virtual ~base()
  {
    std::cout << "I am in base destructor";
  }
};

class derived: public base
{
  int val2;

public:
  derived(int val): base(100), val2(val)
  {
  }
  virtual void basefunc() {
      std::cout << "I am in derived func";
  }
  virtual ~derived()
  {
    std::cout << "I am in derived destructor";
  }
};

int main()
{
    base b = base(10);
    derived d = derived(2);

    base *ptr = &b;
    ptr->basefunc();
    ptr = &d;
    ptr->basefunc();
}

Then I tried to check the vtable of the classes and the output was:

(gdb) p b._vptr$base[0]
$77 = (int (*)(void)) 0x100006ee0 <base::basefunc()>
(gdb) p b._vptr$base[1]
$78 = (int (*)(void)) 0x100006b30 <base::~base()>
(gdb) p b._vptr$base[2]
$79 = (int (*)(void)) 0x100006f10 <base::~base()>
(gdb) p b._vptr$base[3]
$80 = (int (*)(void)) 0x7fff87fd7fe8
(gdb) p b._vptr$base[4]
$81 = (int (*)(void)) 0x10000eda8 <typeinfo name for base>
(gdb) p b._vptr$base[5]
$82 = (int (*)(void)) 0x0

(gdb) p d._vptr$base[0]
$88 = (int (*)(void)) 0x100006fb0 <derived::basefunc()>
(gdb) p d._vptr$base[1]
$89 = (int (*)(void)) 0x100006b00 <derived::~derived()>
(gdb) p d._vptr$base[2]
$90 = (int (*)(void)) 0x100006fe0 <derived::~derived()>
(gdb) p d._vptr$base[3]
$91 = (int (*)(void)) 0x7fff87fd8058
(gdb) p d._vptr$base[4]
$92 = (int (*)(void)) 0x10000edae <typeinfo name for derived>
(gdb) p d._vptr$base[5]
$93 = (int (*)(void)) 0x10000f248 <typeinfo for base>
(gdb) p d._vptr$base[6]
$94 = (int (*)(void)) 0x0

So the questions is:

Why both base and derived has 2 entries for destructors in vtable? and how they are different.

PS: I compiled using clang and with gdb debug symbols.

Ritesh
  • 1,809
  • 1
  • 14
  • 16
  • 4
    https://stackoverflow.com/questions/6613870/gnu-gcc-g-why-does-it-generate-multiple-dtors – bolov Feb 24 '19 at 17:54
  • [two destructors](https://stackoverflow.com/questions/17960917/why-there-are-two-virtual-destructor-in-the-virtual-table-and-where-is-address-o); [6]: obviously, your compiler handles vtables as null-terminated function pointer list. Null-termination is not required, though, vtable layout is implementation defined (actually, vtables themselves are, they are only a de-facto standard, but not enforced by C++ standard – so if a compiler vendor finds some clever alternative approach, they are free to do so...). – Aconcagua Feb 24 '19 at 17:54
  • 1
    One question per question please – Lightness Races in Orbit Feb 24 '19 at 17:56
  • 3
    @Aconcagua -- a bit technical, but vtable layout is not implementation defined. It's implementation specific. The language definition uses the term "implementation defined" for a specific purpose: it requires the implementation to document its behavior. – Pete Becker Feb 24 '19 at 18:02
  • @passerBy I will create 3 questions. The first question has already been answered. – Ritesh Feb 24 '19 at 18:03
  • @bolov thanks for the link. – Ritesh Feb 24 '19 at 18:03
  • @Ritesh Better don't change the question - the comments already posted on might get invalidated. Just remember the "one question per post" for the next time... – Aconcagua Feb 24 '19 at 18:12
  • These two entries are one of the compiler's ways to tell you it can optimise code in mysterious ways. Seriously, these two entries are the normal destructor and the `delete`ing destructor. Now how would you use this information? – n. m. could be an AI Feb 24 '19 at 18:18
  • Per bolov: possible duplicate of [GNU GCC (g++): Why does it generate multiple dtors?](https://stackoverflow.com/questions/6613870/gnu-gcc-g-why-does-it-generate-multiple-dtors) – Davis Herring Feb 25 '19 at 04:35

0 Answers0