Search code examples
c++eigenunions

union with eigen data types


I have been testing Eigen library datatypes with union for type punning. My intent is to have a single memory of double array that can be accessed as an eigen data type and vice versa.

example:

union BigBox{
    double X[13];
    struct
    {
        Eigen::Vector3d p;
        Eigen::Vector3d v;
        Eigen::Vector3d w;
        Eigen::Vector4d q;
    } data;

};

When I test the

sizeof(BigBox)/sizeof(double) = 14
sizeof(Eigen::Vector3d)/sizeof(double) = 3
sizeof(Eigen::Vector4d)/sizeof(double) = 4

The size of the struct does not add up. How does the extra +1 get allotted? I believe it could be because of the compiler trying to exploit the SMID features but is there any way for me to use type punning in these situations? What is the correct approach for what I am trying to achieve?


Solution

  • By default, Eigen::Vector4d is 16 byte aligned (or 32 byte aligned when compiled with AVX, to be more precise it will be aligned to EIGEN_MAX_STATIC_ALIGN_BYTES). That means after 3 vectors of 3*8 bytes each (=72 bytes), there will be 8 padding bytes. You can work-around it by either putting the most aligned element at the start, or by locally disabling alignment.

    None of this is really safe, since in C++ unions should not be used for type-punning -- although it often works in practice.

    To be a bit more safe, you can do something like this:

    struct BigBox{
        Eigen::Matrix<double,13,1> X;
    
        Eigen::Ref<Eigen::Vector3d      > p()       { return X.segment<3>(0); }
        Eigen::Ref<Eigen::Vector3d const> p() const { return X.segment<3>(0); }
        Eigen::Ref<Eigen::Vector3d      > v()       { return X.segment<3>(3); }
        Eigen::Ref<Eigen::Vector3d const> v() const { return X.segment<3>(3); }
        Eigen::Ref<Eigen::Vector3d      > w()       { return X.segment<3>(6); }
        Eigen::Ref<Eigen::Vector3d const> w() const { return X.segment<3>(6); }
        Eigen::Ref<Eigen::Vector4d      > q()       { return X.segment<4>(9); }
        Eigen::Ref<Eigen::Vector4d const> q() const { return X.segment<4>(9); }
    

    };