1

We had a problem today where my code was generating crazy prices. I eventually boiled it down to the fact that my message classes were the wrong size, even though I am packing on one byte and have unit tests in place to ensure this doesn't ever happen. (Turns out the unit tests were not run under Windows, but that's another problem.)

I've got a traits class template, which is empty except for some static consts and enums, and an implementation of a noncopyable class which is empty.

When I derive a class from both of the above, the resulting class is padded out by 1 byte, but only under Windows, and only if I derive from both classes. If I derive from one or the other, the class is not padded out.

I realize I am in platform-specific territory here with the #pragma, but it seems odd to me that only during multiple public inheritance does this not do what I was expecting it to do.

The question is: Why does MSVC pad out the class by 1 byte in the case of multiple public inheritance of empty classes?

Here is an SSCCE that issustrates the problem:

#include <cstdlib>
#include <string>
#include <iostream>
using namespace std;

#pragma pack (1)

template <size_t ExpectedSize>
class Traits
{
public:
    static const size_t mExpSize = ExpectedSize;
};

class noncopyable
{
public:
    noncopyable() {};
    ~noncopyable() {};
private:
    noncopyable& operator= (const noncopyable&);
    noncopyable (const noncopyable&);
};

class NotEmpty1
{
public:
    char mBuf [33];
};

class NotEmpty2
:
    public Traits <33>

{
public:
    char mBuf [33];
};

class NotEmpty3
:
    public noncopyable
{
public:
    char mBuf [33];
};

class NotEmpty4
:
    public Traits <33>,
    public noncopyable
{
public:
    char mBuf[33];
};

int main()
{
    cout << "Case 1: " << sizeof (NotEmpty1) << "\n"
        << "Case 2: " << sizeof (NotEmpty2) << "\n"
        << "Case 3: " << sizeof (NotEmpty3) << "\n"
        << "Case 4: " << sizeof (NotEmpty4) << "\n"
        ;
}

The idea here is for all the NotEmpty classes to be exactly 33 bytes. Under linux (using G++ 4.4.6.4) they are:

Case 1: 33
Case 2: 33
Case 3: 33
Case 4: 33

Under Windows (using MSVC 9 and 10) they are not:

Case 1: 33
Case 2: 33
Case 3: 33
Case 4: 34

Edit: When I use:

#pragma pack (show)

In a variety pf places, the compiler always says:

1>main.cpp(57): warning C4810: value of pragma pack(show) == 1

Edit: Showing the offset of mBuf wrt the beginning of the class using:

cout << "Offset: " << offsetof(NotEmpty4, mBuf) << "\n";

Reveals:

Offset: 1
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • Can Visual Studio show you the padding with `#pragma pack(show)`? – chrisaycock Jul 12 '13 at 16:57
  • @chrisaycock: Yes, no matter where I put that `#pragma`, the compiler says `1>main.cpp(57): warning C4810: value of pragma pack(show) == 1` – John Dibling Jul 12 '13 at 16:59
  • Hmm, any chance you can print the `offsetof(NotEmpty4, mBuf)`? I'm curious to see whether the extra byte is at the beginning or end of the class. – chrisaycock Jul 12 '13 at 17:07
  • Sure, result is `Offset: 1`. Will edit post. – John Dibling Jul 12 '13 at 17:08
  • I guess if the padding were at the end, my prices would not have been crazy and I would not have known about a problem until the server started chunking messages. – John Dibling Jul 12 '13 at 17:12
  • Well now I'm just stumped. I wonder if Visual Studio is including some sort of metadata at the start of a class in the event of multiple inheritance. – chrisaycock Jul 12 '13 at 17:19
  • @chrisaycock: Maybe. I was thinking it might actually be a bug in the compiler. It certianly doesn't seem like expected behavior to me. I'll email microsoft about it. – John Dibling Jul 12 '13 at 17:20
  • 1
    See http://stackoverflow.com/questions/12701469/why-empty-base-class-optimization-is-not-working where we learn it's a longstanding bug in the MS compiler. – Mark B Jul 12 '13 at 18:04
  • @MarkB: Aha! Thx for link. – John Dibling Jul 12 '13 at 19:42
  • @MarkB Thanks for the link. I'll upvote you if you convert that to an answer. I don't believe this question is a dupe because it's asking about padding and the original asked about empty base optimization. – chrisaycock Jul 13 '13 at 14:49

0 Answers0