user664303
user664303

Reputation: 2063

Strange size of class containing Eigen vectors

A C++ class containing two Eigen vectors has a strange size. I have a MWE of my problem here:

#include <iostream>
#include "Eigen/Core"

class test0 {
  Eigen::Matrix<double,4,1> R;
  Eigen::Matrix<double,4,1> T;
};

class test1 {
  Eigen::Matrix<double,4,1> R;
  Eigen::Matrix<double,3,1> T;
};

class test2 {
  Eigen::Matrix<double,4,1> R;
  Eigen::Matrix<double,2,1> T;
};

class test3 {
  Eigen::Matrix<double,7,1> T;
};

class test4 {
  Eigen::Matrix<double,3,1> T;
};

int main(int argc, char *argv[])
{
    std::cout << sizeof(test0) << ", " << sizeof(test1) << ", " << sizeof(test2) << ", " << sizeof(test3) << ", " << sizeof(test4) << std::endl;
    return 0;
}

The output I get on my system (MacBook Pro, Xcode Clang++ compiler) is:

64, 64, 48, 56, 24

The class "test1" has some bizarre extra padding - I would have expected it to have size 56. I don't understand the reason for it, especially given that none of the other classes have any padding. Can anyone explain, or is this an error?

Upvotes: 1

Views: 582

Answers (2)

zneak
zneak

Reputation: 138231

This happens because of how the Eigen library is implemented, and it is not related to compiler tricks. The backing storage for Eigen::Matrix<double, 4, 1> has the EIGEN_ALIGN_TO_BOUNDARY(16) tag on it, which has compiler-specific definitions that ask the type to be aligned on a 16-byte boundary. To ensure this, the compiler has to add 8 bytes of padding at the end of the structure, since otherwise the first matrix field would not be aligned on a 16-byte boundary if you had an array of test1.

Eigen simply does not try to impose similar requirements to the backing storage of Eigen::Matrix<double, 7, 1>.

This happens in Eigen/src/Core/DenseStorage.

Upvotes: 5

Liam M
Liam M

Reputation: 5432

Padding requirements aren't mandated by the language, they're actually mandated by your processor architecture. Your class is being padded so it's 64 bytes wide. You can override this of course, but it's done so that structures sit neatly in memory and can be read efficiently, aligning to cache lines.

In what circumstances a structure is padded is a complex question, but generally speaking "memory is cheap, cycles are not". Modern computers have loads of memory and since performance gains are becoming harder to find as we approach the limits of copper, so trading some off for performance is usually a good idea.

Some additional reading is available here.


Following up on the discussion in the comments, it's worth noting that the compiler isn't your god. Not every optimisation is a good idea, and even trivial changes to your code can have vast implications for some optimisations. If you don't like what your toolchain producing and think you can do better, then do it! Take some benchmarks, make your changes and then measure again. As you do all of that, take not how long you spend on it and then ask yourself - was that a good use of you or your employers time? :)

Upvotes: 0

Related Questions