0

I have a class hierarchy that is using CRTP for "inheritance" across template specializations. This class represents a math matrix. When I instantiate this concrete class, sizeof(Matrix<int, 4, 4>) returns 4 more bytes than I'm expecting. Normally I'd attribute that extra memory to a vtable somewhere, but in that case I'd expect it to be 8 bytes (pointer), and I'd only expect that if I had any virtual functions, but I do not. On top of that, when I print out std::is_polymorphic<Matrix<float, 4, 4>>::value the result is false. It probably isn't an alignment packing issue because that should come out to a nice perfect 2^6. I'm either missing something key about the c++ standard, or the win32 c++ compiler is doing something fishy.

The hierarchy looks like so, (omitting non properties for brevity):

template<class T, uint32_t length, class CRTP>
struct BaseDimensional {
    // only functions, no virtuals
}

template<class T, uint32_t length, class CRTP>
struct IntegralNumberDimensional {
    // only functions, no virtuals
};

template<class T, uint32_t row, uint32_t col, class CRTP>
class BaseMatrix : public BaseDimensional<T, row * col, CRTP> {
protected:
    union {
        T mat[col][row]{};
        T arr[col * row];
    };
public:
    // functions, no virtuals
}

template<class T, uint32_t row, uint32_t col>
struct Matrix : public BaseMatrix<T, row, col, Matrix<T, row, col>>,
        public IntegralNumberDimensional<T, row * col, Matrix<T, row, col>> {
    // empty
}

I am using the compiler built into visual studio 2019, with flags /SUBSYSTEM:windows /ENTRY:mainCRTStartup /std:c++17 /EHsc /MDd /Zi if that matters. When printing out all the bytes in the object the extra bytes appear at the beginning. When debugging, the only values shown are the union. sizeof(Matrix<int, 4, 4>) comes out to 68. Not finding any other documentation that suggests this behavior. If anyone knows or has a suggestion to dig into this further, I'd greatly appreciate it.

FatalCatharsis
  • 3,407
  • 5
  • 44
  • 74
  • 1
    EBO applies to first vasr. `IntegralNumberDimensional` is taking up memory address space and is being packed for int alignment. – Yakk - Adam Nevraumont Sep 11 '21 at 00:52
  • Is this a proper [mre]? No chance that `IntegralNumberDimensional` is really inheriting from `BaseDimensional`? – StoryTeller - Unslander Monica Sep 11 '21 at 00:58
  • @Yakk-AdamNevraumont based on this article on EBO, I don't think it should apply. An instance of the base class is not being instantiated anywhere and the size of the resulting object would take up more than 0 bytes without a base class. Is there some specific rule I'm not understanding? – FatalCatharsis Sep 11 '21 at 02:27
  • @StoryTeller-UnslanderMonica I know I named it IntegralNumberDimensional, but it definately does not inherit that class. I just copied the classes to another file and deleted all the functions before pasting it here so the signatures are exact. I'll spend some time producing a minimal example this evening and see what comes up. If I get to the bottom of it, I'll post an answer. – FatalCatharsis Sep 11 '21 at 02:30
  • @fatal experiment? Like, remove 2nd empty base. – Yakk - Adam Nevraumont Sep 11 '21 at 03:00
  • 1
    Anyhow, gcc on phone makes it size 4 4 int. EBO is not a requirement. EBO is an ABI issue, so changing how it works is done carefully. Maybe MSVC is being compatible with an old ABI. There might be compiler flags. – Yakk - Adam Nevraumont Sep 11 '21 at 03:05
  • @Yakk-AdamNevraumont gotcha, I misunderstood your suggestion from the first comment. I did not know that EBO was not a requirement, this makes perfect sense now. Removing that base class and commenting out the code that it needed did remove the other 4 bytes, so it looks like MSVC in particular is not performing this optimization for whatever reason. Thanks for your assistance. – FatalCatharsis Sep 11 '21 at 03:11
  • @FatalCatharsis you can tell it to do that with [`__declspec(empty_bases)`](https://stackoverflow.com/a/55530422/995714) – phuclv Sep 25 '21 at 04:27

0 Answers0