【问题标题】:Member functions more efficient than binary operator overloads in C++?成员函数比 C++ 中的二元运算符重载更有效?
【发布时间】:2021-06-17 10:54:47
【问题描述】:

考虑两种实现类 Foo 变量加法的方法:

  1. 使用运算符重载:Foo operator+(const Foo& rhs)
  2. 使用成员函数:void addAndAssign(const Foo &lhs, const Foo& rhs)

现在考虑两个等价的表达式a = b + ca.addAndAssign(b,c)

选项 1 会将加法的结果放入一个新变量中,然后将其移动分配到目标 a。但选项 2 将直接对变量 a 执行加法,无需赋值。

请记住,移动赋值并不能真正避免在具有静态分配成员的类上复制数据。对于包含静态分配的成员变量和数组的类型,这不会使二元运算符总是比等效的成员函数效率低吗?有没有办法解决这个问题?

【问题讨论】:

  • 你知道Expression_templates吗?你如何实现addAndAssign
  • 记住,移动赋值并不能真正避免复制具有静态成员的类上的数据。静态成员与复制有什么关系?
  • 缺少一些const BTW。
  • 效率问题:profile、profile、profile。确定效率的唯一方法是在您的平台上使用优化的代码对其进行衡量。
  • @Yksisarvinen 抱歉,我的意思是静态分配的成员(而不是使用 new/delete 动态分配的)。即,常规变量float floatMember;.

标签: c++ operator-overloading


【解决方案1】:

所以我编写了一个非常简单的基准,它只是以不同的方式将两个 Vector3 相加。

方法一:

static Vector3 Add(Vector3 a, Vector3 b) {
    return Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
}

方法二:

Vector3 operator+(const Vector3& right) const {
    return Vector3(this->x + right.x, this->y + right.y, this->z + right.z);
}

方法三:

Vector3& AddTo(Vector3 other) {
    x += other.x, y += other.y, z += other.z;
    return *this;
}

方法四:

Vector3& operator+=(const Vector3 rhs) {
    this->x += rhs.x, this->y += rhs.y, this->z += rhs.z;
    return *this;
}

测试集是两个 Vector3 数组,都是 10Mio 条目,在 -10k 到 10k 的范围内随机初始化。 IDE 是 VS 2019 和默认(ISO C++ 14 标准)在 Ryzen 3700x CPU、24GB 2800mhz CL16 RAM 上

结果是:

方法一:432毫秒

方法 2:438 毫秒

方法 3:227 毫秒

方法 4:227 毫秒

我重新运行了几次,结果似乎几乎是固定的(这里或那里多或少 1 - 2 毫秒)

但这是有道理的,它实际上不会改变性能。重载和函数在内部都是相同的代码,如果将其编译下来,运算符重载基本上就是一个函数。然而,简单的 Add 函数始终要好几毫秒。但它确实只显示连续添加 30Mio 次。

【讨论】:

  • 您可能想检查void addAndAssign(Vector3& lhs, Vector3& rhs) {x = lhs.x + rhs.x; y = lhs.y + rhs.y; z = lhs.z + rhs.z; } 的输出。这是 Vector3 的成员函数,您可以这样称呼它:a.addAndAssign(b,c);
  • 好吧,是的,我把它改成了 void 类型,但它仍然没有改变结果。一样的
  • 是的,谢谢。我也刚量了一下。没有编译器优化会有很大的不同,但是有了编译器优化,几乎没有。
猜你喜欢
  • 2021-04-21
  • 1970-01-01
  • 2011-06-05
  • 2021-06-14
  • 2021-10-22
  • 2012-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多