Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate struct padding in c++11 during compile time?

Tags:

c++

c++11

sizeof

PROBLEM

I have a std::vector of a gazillion Foo's

struct Foo
{
  int   m_i;
  char  m_c;
  char  m_padding[3];   // want to replace this
};

I can fwrite this chunk of contiguous Foo's quickly in binary form all in one shot.

My problem is, if I don't put in that m_padding explicitly, calculate it, and clear it myself, valgrind will complain about uninitialized writes.

QUESTION

Is it possible to write a template class in C++11 which will calculate that padding for me during compile time?

If so, I could just add it at the end of all my Foo's and auto-initialize/clear them without complaint from valgrind.

I can do it manually by calculating sizeof( padding ) = sizeof( Foo ) - sum( sizeof( parts )), but it would be nice to create some kind of class for this calculation since all information is available at compile-time.

For simplicity, assume that Foo has trivial layout (type_traits is an important, but tangent issue). Also, ignore ordering issues/cross-platform issues.

Possible Approach

This doesn't answer my original question directly, but hvd's suggestion implies a simpler approach that seems to work for some simple test cases that I tried:

template<typename T>
struct BZero
{
  BZero() { std::memset( this, 0, sizeof( T )); }
};

struct Foo : public BZero<Foo>
{
  int   m_i;
  char  m_c;
};
like image 235
kfmfe04 Avatar asked Feb 23 '14 14:02

kfmfe04


1 Answers

Well, I can see two ways:

  1. Use a union of your class and an array of char as big as the class
  2. Use a templated class and meta-programming to figure out all the paddings

Needless to say the former seems much easier, so here you go:

template <typename T>
class ZeroedClass {
public:
    template <typename... Args>
    ZeroedClass(Args&&... args) {
        new (&_.t) T(std::forward<Args>(args)...);
    }

    // Need other special members as well

    ~ZeroedClass() { _.t.~T(); }

    // Accessors
    T& access() { return _.t; }
    T const& get() const { return _.t; }

private:
    union U {
        U() { memset(this, 0, sizeof(T)); }

        char buffer[sizeof(T)];
        T t;
    } _;
}; // class ZeroedClass
like image 143
Matthieu M. Avatar answered Nov 15 '22 01:11

Matthieu M.