【问题标题】:Performance implications of C++ unionsC++ 联合的性能影响
【发布时间】:2017-07-23 17:49:24
【问题描述】:

Agner Fog's "Optimizing software in C++" 中指出,union 强制将变量存储在内存中,即使在本来可以存储在寄存器中的情况下,这可能会影响性能。 (例如第 148 页)

我经常看到这样的代码:

struct Vector {
    union {
        struct {
            float x, y, z, w;
        };
        float v[4];
    }
};

这可能很方便,但现在我想知道是否可能会影响性能。 我写了一个小基准,比较了有无联合的 Vector 实现,以及没有联合的 Vector 显然表现更好的情况,尽管我不知道我的基准有多值得信赖。 (我比较了三种实现:union;x、y、z、w;v[4]。例如,v[4] 在按值传递时似乎更慢,尽管结构都具有相同的大小。)

我现在的问题是,人们在编写实际生产代码时是否会考虑这一点?您是否知道专门为此原因决定反对工会的案例?

【问题讨论】:

  • 我不会考虑它,除非我遇到了严重的性能问题,分析了我的代码,纠正了其他所有问题,最后通过检查我的编译器生成的程序集确定了这个非常具体的点。跨度>
  • 除了编译器不擅长优化之外,没有理由不能将union 存储在寄存器中,但这种情况很少发生在这种微不足道的情况下。如果不调用 UB,您所显示的联合也是无用的。我会考虑换一个book
  • 来自cppreferene.com : “从最近未编写的联合成员中读取是未定义的行为。许多编译器作为非标准语言扩展实现了该能力读取工会的非活动成员。”
  • 在 Agner Fog 的“Optimizing software in C++”中,提到的内容不是在第 148 页而是在第 153 页。也许他更新了这本书?

标签: c++ unions cpu-registers


【解决方案1】:

似乎目标是为向量类型的元素提供友好的名称,而union 并不是最好的方法。评论已经指出了未定义的行为,即使它起作用,它也是一种限制优化机会的别名形式。

相反,避免整个混乱,只需添加命名元素的访问器。

struct quaternion
{
    float vec[4];
    float &x() { return vec[0]; }
    float &y() { return vec[1]; }
    float &z() { return vec[2]; }
    float &w() { return vec[3]; }
    const float &x() const { return vec[0]; }
    const float &y() const { return vec[1]; }
    const float &z() const { return vec[2]; }
    const float &w() const { return vec[3]; }
}

事实上,就像 Eigen 的四元数实现一样: https://eigen.tuxfamily.org/dox/Quaternion_8h_source.html

【讨论】:

  • 它真的限制了优化机会,还是只是像 nwp 建议的那样混淆了“坏”编译器?
  • 那些voids 让我困惑了一阵子。
  • 那些void 不应该在那里。这是 C 表示没有参数的函数的方式(与任意数量的参数相反)。在 C++ 中,这种语法是有效的,但多余且不寻常。带有空参数列表的函数声明意味着:没有参数。另外我强烈建议添加 const 限定的重载。正如const quaternion 的便利访问器一样。
  • 修复旧的 C 语法并添加 const 重载,如 cmets 中所建议的那样。
【解决方案2】:

我现在的问题是,人们在编写实际生产代码时是否会考虑这一点?

没有。那是过早的优化(union 结构本身也是如此)。一旦以某种干净和可靠的方式编写代码,就可以对其进行分析并解决真正的瓶颈问题。无需在union 之上推理 5 分钟来猜测它是否会影响未来某处的性能。它要么会,要么不会,只有分析才能知道。

【讨论】:

  • 为什么你认为联合结构是过早的优化?我一直认为 x、y、z 访问很方便。
  • @B_old 取决于您如何看待它。如果 x,y,z 方便,那么为什么不保留它呢?但是有时有一个数组很方便?但是你可以有引用/指针的本地临时数组......但这会很慢(如果它会编译成真正的临时数组并且一切都会被间接,实际上编译器可能会解决它),所以你直接放置数组定义为 union = 优化(对我个人而言,v[0] 比 x,y,z 更方便,因为我从石器时代到没有名字的记忆,只是偏移量)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
  • 2019-12-12
  • 2013-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多