C++ Eigen矩阵澄清

7

我最近才开始探索C++ Eigen库,对一些文档感到困惑。如果有人能澄清一下就太好了。

  1. 在常见陷阱(https://eigen.tuxfamily.org/dox-devel/TopicPitfalls.html)的对齐问题部分中,它说:“实际上,自C++17以来,C++对于显式数据对齐的支持不够好。”

    在如何消除对齐问题的页面(https://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html#getrid)上,文档说:“如果您只能使用较新的编译器(例如,GCC>=7,clang>=5,MSVC>=19.12)来针对[c++17],那么你很幸运:启用c++17应该足够了”。

    因此,如果我在使用gcc>=7.0的c++ 17,那么对Eigen矩阵而言,对齐是否不是问题?我的理解正确吗?并且宏EIGEN_MAKE_ALIGNED_OPERATOR_NEW将不再需要吗?如果这是正确的,那么c++14 / c++17之间有什么不同来解决对齐问题?

  2. 第二个问题涉及按值传递部分(https://eigen.tuxfamily.org/dox-devel/group__TopicPassingByValue.html)。文档声称按值传递可能是非法的,并且可能会导致程序崩溃。这让我很困惑。按值传递难道不只是调用复制构造函数吗?例如。

Eigen::Vector3f veca = ComputeVecA();
Eigen::Vector3f vecb = veca; //< If pass-by-value is unsafe, is this operation safe?
  1. 最后,我能否依赖于 RVO/NRVO 来使用 Eigen 固定大小矩阵类?我怀疑答案是肯定的。

1
就对齐而言,C++17有一个新版本的operator new,当对齐要求超过操作符默认使用的对齐时使用:https://en.cppreference.com/w/cpp/memory/new/operator_new,例如参见(3)。但是,是的,我同意你的观点,文档似乎自相矛盾(我不是母语人士,也许你比我更理解它)。 - CuriouslyRecurringThoughts
对于按值传递,这里有一个可能有用的讨论:https://dev59.com/vmkw5IYBdhLWcg3wQoWm - CuriouslyRecurringThoughts
@CuriouslyRecurringThoughts:这不是你的英语问题;我是以英语为母语的人,Eigen网站上的第一个引用很荒诞。使用“since”这个词意味着在C++17之前,有支持该功能,而这种支持已被移除。他们可能是想说“until”。 - Nicol Bolas
@NicolBolas 谢谢。至少我不是唯一感到困惑的人。 - CuriouslyRecurringThoughts
看 https://github.com/eigenteam/eigen-git-mirror/blob/master/Eigen/src/Core/util/Memory.h#L777,我认为在 c++17 中对齐不是问题。但是我仍然不清楚 (2)。 - cplusplusrat
2个回答

3
在常见陷阱(https://eigen.tuxfamily.org/dox-devel/TopicPitfalls.html)的对齐问题部分中,它说“实际上,自C++17以来,C++对于显式数据对齐没有足够好的支持。”这似乎是一个打字错误。它应该说“直到C++17”而不是“自C++17”,因为C++17实际上增加了对具有特殊对齐限制的分配的支持。 两个 评论 同意我的看法。
在如何解决对齐问题的页面(https://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html#getrid)中,文档表示:“如果你只能使用最新的编译器(例如GCC> = 7,Clang> = 5,MSVC> = 19.12)来针对[C ++ 17],那么你很幸运:启用C ++ 17应该就足够了。”因此,如果我在使用gcc> = 7.0的C ++ 17,则Eigen Matrix不会出现对齐问题,我的理解是正确的吗?而且宏EIGEN_MAKE_ALIGNED_OPERATOR_NEW也不需要吗?
是的。
如果这是正确的,那么C ++ 14 / C ++ 17之间有什么不同,可以解决对齐问题呢?
C++17支持动态内存分配超对齐数据。现在operator new使用align_val_t参数可以正确地分配超对齐内存。

第二个问题涉及传值方式(https://eigen.tuxfamily.org/dox-devel/group__TopicPassingByValue.html)。 文档声称传值方式可能是非法的,并且可能会导致程序崩溃,这让我很困惑。 难道传值方式不只是调用复制构造函数吗?

如果变量是局部变量(如您示例中的vecb),则编译器和库会确保vecb满足Eigen所需的特殊对齐限制。但是,如果变量是函数参数,则不会遵守此对齐限制,这意味着程序可能在不良对齐的内存上运行,从而崩溃。(这与复制构造函数无关。)

最后,我能依赖RVO/NRVO用于Eigen固定大小的矩阵类吗?我怀疑答案是肯定的。 对于Eigen类和其他类来说,答案基本相同:尝试并查看。通常答案是肯定的。

然而,如果变量是函数参数,则不会遵守此对齐限制。为什么?按值传递与本地变量的复制构造有何不同?为什么编译器在某些情况下会尊重对齐,而在其他情况下则不会? - cplusplusrat
@cplusplusrat 嗯,我其实从来没有想过那个问题;-)文档中实际上并没有提到。据我所知,Eigen使用编译器扩展来确保对齐限制,并且函数参数在某种程度上是特殊的,但我可能需要一位熟悉此问题的人来回答这个问题。 - L. F.
然而,如果变量是函数参数,则不遵守此对齐限制,这意味着程序可能在未对齐的内存上操作,从而导致崩溃。您能否提供C++规范中允许函数参数不按alignas要求对齐的部分?因为据我所知,如果您使用alignas类型,则该类型的每个实例(未动态分配)必须按照alignas规范指定的方式对齐。 - Nicol Bolas
@NicolBolas 问题在于Eigen没有使用alignas,而是使用特定于编译器的东西。 - L. F.
1
@L.F. Eigen在可用时确实使用alignas,这对于大多数用户来说应该是默认设置。 - ggael
@ ggael 哇,是这样啊。那么,我也不知道发生了什么 :( - L. F.

2
  • Q1: 如已评论,这是在更新C++17段落时的一个打字错误。这个问题已经被修复。

  • Q2: 我不记得所有细节,但与两个技术问题有关。

    1. 一些编译器未能正确对齐堆栈,在这种情况下,无法获得对齐的函数参数。
    2. 旧的ABI规范不允许函数参数超过对齐限制。 我期望自c++11以来,使用标准化的alignas关键字后,这不再是问题,但也许在某些奇特的编译器-操作系统组合上仍然存在问题。
  • Q3: 没有任何阻止RVO/NRVO的东西,而且从我的经验来看,它可以应用于适用的情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接