Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Difference in class size during Virtual inheritance
Forum Updated to NodeBB v4.3 + New Features

Difference in class size during Virtual inheritance

Scheduled Pinned Locked Moved Unsolved C++ Gurus
10 Posts 5 Posters 1.4k Views 5 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • V Offline
    V Offline
    Vinoth Rajendran4
    wrote on 27 Aug 2019, 14:11 last edited by Vinoth Rajendran4
    #1

    I am using 32 bit GCC compiler.

    Case 1:

    class Base
    {
    };
    
    class Derived : virtual public Base
    {
    };
    

    size of Derived class is 4.

    Case 2:

    class Base
    {
    virtual void hello();
    };
    
    class Derived : virtual public Base
    {
    };
    

    size of Derived class is still 4.

    Case 3:

    class Base
    {
    int a;
    virtual void hello();
    };
    
    class Derived : virtual public Base
    {
    };
    

    size of Derived class is 12.

    Can anyone please help understand the memory layout concept here.

    In case 2, can some one please explain me why sizeof(Derived) is 4.

    ( my half-baked understanding is that base class has 4 bytes(virtual function) and derived class inherits that 4 bytes + size for virtual base pointer, hence the total should be 8.)

    J 1 Reply Last reply 27 Aug 2019, 21:51
    0
    • V Vinoth Rajendran4
      27 Aug 2019, 14:11

      I am using 32 bit GCC compiler.

      Case 1:

      class Base
      {
      };
      
      class Derived : virtual public Base
      {
      };
      

      size of Derived class is 4.

      Case 2:

      class Base
      {
      virtual void hello();
      };
      
      class Derived : virtual public Base
      {
      };
      

      size of Derived class is still 4.

      Case 3:

      class Base
      {
      int a;
      virtual void hello();
      };
      
      class Derived : virtual public Base
      {
      };
      

      size of Derived class is 12.

      Can anyone please help understand the memory layout concept here.

      In case 2, can some one please explain me why sizeof(Derived) is 4.

      ( my half-baked understanding is that base class has 4 bytes(virtual function) and derived class inherits that 4 bytes + size for virtual base pointer, hence the total should be 8.)

      J Offline
      J Offline
      JKSH
      Moderators
      wrote on 27 Aug 2019, 21:51 last edited by
      #2

      @vinoth-rajendran4 said in Difference in class size during Virtual inheritance:

      Can anyone please help understand the memory layout concept here.

      In case 2, can some one please explain me why sizeof(Derived) is 4.

      ( my half-baked understanding is that base class has 4 bytes(virtual function) and derived class inherits that 4 bytes + size for virtual base pointer, hence the total should be 8.)

      I don't know the exact answer (perhaps @kshegunov does?), but I do believe the size of a class's vtable is separate from the size of a class's instance.

      I will also point out that the memory layout is implementation-specific. You'll find that with MSVC 2017 32-bit, sizeof(Derived) in case 2 is 8, but it drops to 4 if you change to non-virtual inheritance. With GCC, the size is 4 with both virtual and non-virtual inheritance.

      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

      K K 2 Replies Last reply 27 Aug 2019, 22:09
      0
      • J JKSH
        27 Aug 2019, 21:51

        @vinoth-rajendran4 said in Difference in class size during Virtual inheritance:

        Can anyone please help understand the memory layout concept here.

        In case 2, can some one please explain me why sizeof(Derived) is 4.

        ( my half-baked understanding is that base class has 4 bytes(virtual function) and derived class inherits that 4 bytes + size for virtual base pointer, hence the total should be 8.)

        I don't know the exact answer (perhaps @kshegunov does?), but I do believe the size of a class's vtable is separate from the size of a class's instance.

        I will also point out that the memory layout is implementation-specific. You'll find that with MSVC 2017 32-bit, sizeof(Derived) in case 2 is 8, but it drops to 4 if you change to non-virtual inheritance. With GCC, the size is 4 with both virtual and non-virtual inheritance.

        K Offline
        K Offline
        kshegunov
        Moderators
        wrote on 27 Aug 2019, 22:09 last edited by kshegunov
        #3

        I have been summoned.

        @jksh said in Difference in class size during Virtual inheritance:

        I don't know the exact answer (perhaps @kshegunov does?), but I do believe the size of a class's vtable is separate from the size of a class's instance.

        Correct, the vtable is part of the .text section, so its size has no bearing on the objects. There's one single vptr that's added to the object in the beginning of the object's data block which points to the class' vtable. When a polymorphic call is required the vptr is used to do the indirection at runtime. The vptr is initialized in the class' constructor after the parent's constructor's run, but before the constructor's initializer list. The implication is that from the point of view of Base::Base() the object is of type Base no matter where the constructor call originated, meaning that if you override a method in Derived, but call it in Base::Base() then Base's implementation is going to be called, that is - you can't have polymorphic calls proper in constructors. Thus if Base's virtual method is pure virtual and you call it in the constructor, you're going to segfault.

        Theory aside. In the above example:
        Case 1 and 2:
        sizeof(Derived) == sizeof(void *) which is the size of the vptr.
        Case 3:
        sizeof(Derived) == sizeof(void *) + sizeof(int) - you have one vptr and one integer member derived from Base. I assume you're running a 64bit show, so sizeof(void *) == 8 in this case. The int is 4 bytes, so you get a total of 12.

        Edit: Missed that you're compiling for 32 bits.
        In that case sizeof(void *) == 4, however padding applies to data members and alignment applies to data blocks. Depending on how the compiler does it (I think by default it pads to the hardware word size) it may differ, but in this case I'm pretty sure the additional 4 bytes you see is the member padding.

        Read and abide by the Qt Code of Conduct

        1 Reply Last reply
        5
        • Chris KawaC Online
          Chris KawaC Online
          Chris Kawa
          Lifetime Qt Champion
          wrote on 27 Aug 2019, 23:08 last edited by Chris Kawa
          #4

          I think it's a bit more complicated than just padding. If you use "-fdump-class-hierarchy" switch you can see some info about how the classes are structured. If you look at the vtable offsets you can see GCC has some clever trickery that allow it to use the same vtable offset for both base and derived classes in some cases, and thus shrink the size of the class by one pointer. An interesting thing is that for case 2 you will get size of derived class 4 whether you use virtual or normal inheritance, but for case 3 it will vary depending on the type of inheritance and be either 12 (for virtual) or 8 (for normal).

          I think it does some sort of vtable merge so that the class object only holds one pointer, but I won't try to pretend to know how it works exactly. There's probably some beefy document somewhere out there describing the trickery in excruciating detail, but the point is that it's a vendor specific compiler optimization of some sort (MSVC doesn't seem to behave like that).

          1 Reply Last reply
          1
          • J JKSH
            27 Aug 2019, 21:51

            @vinoth-rajendran4 said in Difference in class size during Virtual inheritance:

            Can anyone please help understand the memory layout concept here.

            In case 2, can some one please explain me why sizeof(Derived) is 4.

            ( my half-baked understanding is that base class has 4 bytes(virtual function) and derived class inherits that 4 bytes + size for virtual base pointer, hence the total should be 8.)

            I don't know the exact answer (perhaps @kshegunov does?), but I do believe the size of a class's vtable is separate from the size of a class's instance.

            I will also point out that the memory layout is implementation-specific. You'll find that with MSVC 2017 32-bit, sizeof(Derived) in case 2 is 8, but it drops to 4 if you change to non-virtual inheritance. With GCC, the size is 4 with both virtual and non-virtual inheritance.

            K Offline
            K Offline
            Kent-Dorfman
            wrote on 6 Oct 2019, 05:36 last edited by
            #5

            @JKSH said in Difference in class size during Virtual inheritance:

            I will also point out that the memory layout is implementation-specific.

            This is the main thing to remember in this discussion. The language specification makes no rules about implementation, just behaviour. being concerned about vtables is usually indicative of a system design error.

            Chris KawaC 1 Reply Last reply 6 Oct 2019, 09:24
            0
            • K Kent-Dorfman
              6 Oct 2019, 05:36

              @JKSH said in Difference in class size during Virtual inheritance:

              I will also point out that the memory layout is implementation-specific.

              This is the main thing to remember in this discussion. The language specification makes no rules about implementation, just behaviour. being concerned about vtables is usually indicative of a system design error.

              Chris KawaC Online
              Chris KawaC Online
              Chris Kawa
              Lifetime Qt Champion
              wrote on 6 Oct 2019, 09:24 last edited by
              #6

              @Kent-Dorfman said in Difference in class size during Virtual inheritance:

              being concerned about vtables is usually indicative of a system design error.

              Or working on a low level optimization. In my line of work for example this is nothing unusual. Vtables do have measurable impact on performance and memory consumption. It's just that there are cases where it doesn't matter that much and then there are cases where it does, a lot.

              Relying on class layout, sizes and alignment is futile in generic code as you never know what they are in all possible configs, but sometimes you get to work on a specific locked hardware and toolchain combination (e.g. game consoles or medical equipment) and in those cases it's very much desirable to get the most out of that setup, down to the layout and vtable specific bytes.

              K 1 Reply Last reply 6 Oct 2019, 09:50
              0
              • Chris KawaC Chris Kawa
                6 Oct 2019, 09:24

                @Kent-Dorfman said in Difference in class size during Virtual inheritance:

                being concerned about vtables is usually indicative of a system design error.

                Or working on a low level optimization. In my line of work for example this is nothing unusual. Vtables do have measurable impact on performance and memory consumption. It's just that there are cases where it doesn't matter that much and then there are cases where it does, a lot.

                Relying on class layout, sizes and alignment is futile in generic code as you never know what they are in all possible configs, but sometimes you get to work on a specific locked hardware and toolchain combination (e.g. game consoles or medical equipment) and in those cases it's very much desirable to get the most out of that setup, down to the layout and vtable specific bytes.

                K Offline
                K Offline
                kshegunov
                Moderators
                wrote on 6 Oct 2019, 09:50 last edited by
                #7

                @Chris-Kawa said in Difference in class size during Virtual inheritance:

                Vtables do have measurable impact on performance and memory consumption.

                I think they (HW guys) introduced a vtable prefetcher specifically to mitigate that, didn't they?

                Read and abide by the Qt Code of Conduct

                Chris KawaC 1 Reply Last reply 6 Oct 2019, 09:56
                0
                • K kshegunov
                  6 Oct 2019, 09:50

                  @Chris-Kawa said in Difference in class size during Virtual inheritance:

                  Vtables do have measurable impact on performance and memory consumption.

                  I think they (HW guys) introduced a vtable prefetcher specifically to mitigate that, didn't they?

                  Chris KawaC Online
                  Chris KawaC Online
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 6 Oct 2019, 09:56 last edited by
                  #8

                  @kshegunov said in Difference in class size during Virtual inheritance:

                  I think they (HW guys) introduced a vtable prefetcher specifically to mitigate that, didn't they?

                  It's like with branch predictors, caching and such. They mitigate problems but don't eliminate them. In some cases you still need to help them to help you.

                  K 1 Reply Last reply 6 Oct 2019, 09:58
                  0
                  • Chris KawaC Chris Kawa
                    6 Oct 2019, 09:56

                    @kshegunov said in Difference in class size during Virtual inheritance:

                    I think they (HW guys) introduced a vtable prefetcher specifically to mitigate that, didn't they?

                    It's like with branch predictors, caching and such. They mitigate problems but don't eliminate them. In some cases you still need to help them to help you.

                    K Offline
                    K Offline
                    kshegunov
                    Moderators
                    wrote on 6 Oct 2019, 09:58 last edited by kshegunov 10 Jun 2019, 18:21
                    #9

                    @Chris-Kawa said in Difference in class size during Virtual inheritance:

                    It's like with branch predictors, caching and such. They mitigate problems but don't eliminate them. In some cases you still need to help them to help you.

                    No argument there. I was just left with the impression that in modern machines there was a dedicated polymorphic prefetcher (with a branch predictor) specifically to make most of the weight of the virtual indirection go away. I was just wondering if you knew that to be a fact, or I'm just imagining things.

                    Read and abide by the Qt Code of Conduct

                    1 Reply Last reply
                    1
                    • Chris KawaC Online
                      Chris KawaC Online
                      Chris Kawa
                      Lifetime Qt Champion
                      wrote on 6 Oct 2019, 10:06 last edited by
                      #10

                      @kshegunov I'm not an expert on that but I do see boost when optimizing for reduced vtable usage, so either my hardware doesn't do that good of a job or something else is going on. Thanks for a nudge, I guess it's something worth looking into.

                      1 Reply Last reply
                      1

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved