包含特征向量的 class 的奇怪大小

Strange size of class containing Eigen vectors

包含两个特征向量的 C++ class 的大小很奇怪。我在这里有我的问题的 MWE:

#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;
}

我在系统(MacBook Pro,Xcode Clang++ 编译器)上得到的输出是:

64, 64, 48, 56, 24

class "test1" 有一些奇怪的额外填充 - 我本以为它的大小为 56。我不明白其中的原因,特别是考虑到 none其他 classes 有任何填充。谁能解释一下,或者这是一个错误?

填充要求不是由语言规定的,它们实际上是由您的处理器架构规定的。您的 class 正在填充,因此它的宽度为 64 字节。您当然可以覆盖它,但这样做是为了让结构整齐地放在内存中,并且可以有效地读取,与缓存行对齐。

在什么情况下填充结构是一个复杂的问题,但一般来说"memory is cheap, cycles are not"。现代计算机有大量内存,并且随着我们接近铜的极限,性能提升变得越来越难,因此通常以牺牲一些性能来换取性能是个好主意。

可以阅读一些额外的资料 here


跟进评论中的讨论,值得注意的是编译器不是你的上帝。并非每项优化都是好主意,即使对代码进行微不足道的更改也会对某些优化产生巨大影响。如果您不喜欢您的工具链产生的结果并认为您可以做得更好,那就去做吧!采用一些基准,进行更改,然后再次测量。当你做所有这些时,不要花多长时间,然后问问自己——你或你的雇主的时间是否得到了很好的利用? :)

发生这种情况是因为 Eigen 库的实现方式,与编译器技巧无关。 Eigen::Matrix<double, 4, 1> 的后备存储上有 EIGEN_ALIGN_TO_BOUNDARY(16) 标记,其中有 compiler-specific 定义要求类型在 16 字节边界上对齐。为了确保这一点,编译器必须在结构的末尾添加 8 个字节的填充,否则如果您有一个 test1.[= 数组,第一个矩阵字段将不会在 16 字节边界上对齐。 15=]

Eigen 根本不会尝试对 Eigen::Matrix<double, 7, 1> 的后备存储施加类似的要求。

这发生在 Eigen/src/Core/DenseStorage