【发布时间】:2013-04-26 10:32:21
【问题描述】:
我遇到了一种情况,我确实需要在复制构造函数/赋值运算符中执行重要的代码。算法的正确性取决于它。
虽然我可以使用编译器开关禁用返回值优化,但这似乎是一种浪费,因为它只是我需要禁用它的一种类型,那么为什么整个应用程序的性能会受到影响呢? (更不用说我的公司不允许我添加开关)。
struct A {
explicit A(double val) : m_val(val) {}
A(const A& other) : m_val(other.m_val) {
// Do something really important here
}
A& operator=(const A& other) {
if (&other != this) {
m_val = other.m_val;
// Do something really important here
}
return *this;
}
double m_val;
};
A operator+(const A& a1, const A& a2) {
A retVal(a1.m_val + a2.m_val);
// Do something else important
return retVal;
}
// Implement other operators like *,+,-,/ etc.
这个类会被这样使用:
A a1(3), a2(4), a3(5);
A a4 = (a1 + a2) * a3 / a1;
返回值优化意味着不会用复制构造函数创建a4,“真正重要的事情”不会发生!
我知道我可以破解一个解决方案,其中 operator+ 返回一个不同的类型(比如 B)并有一个将 B 作为输入的 A 构造函数。但随后需要实现的操作符数量激增:
B operator+(const A& a1, const A& a2);
B operator+(const B& a1, const A& a2);
B operator+(const A& a1, const B& a2);
B operator+(const B& a1, const B& a2);
必须有更好的解决方案。我怎样才能破解它,以便我的类型不会发生 RVO?我只能更改 A 类代码和运算符。我无法更改呼叫站点代码;即我不能这样做:
A a1(3), a2(4), a3(5);
A a4;
a4 = (a1 + a2) * a3 / a1;
我考虑过尝试的一件事是尝试使用 C++11 移动构造函数,但我不确定这是否可行,而且我不喜欢它在 C++03 中无效。
有什么想法吗?
编辑:请接受这是我可以做我需要做的事情的唯一方法。我不能只是“改变设计”。调用代码是固定的,我必须在数学运算符和复制构造函数和赋值运算符中实现我的策略。这个想法是,在“a4 = (a1+a2)*a3/a1”等式中计算的中间值不能在程序的其他任何地方引用 - 但 a4 可以。我知道这很模糊,但你只能忍受它。
【问题讨论】:
-
你能解释一下你为什么需要它吗?我认为我们会更好地说服您不要这样做。
-
最好的办法似乎是改变算法,使其不依赖于对象被复制的次数。
-
Move 构造函数不会参与其中。如果省略了副本,则没有移动的余地。我会说你最好重新设计代码。
-
这看起来像an XY problem,在这里您询问的是您尝试的解决方案,而不是真正的问题。为什么记录实际上从未执行过的复制操作“非常重要”?
-
@BoPersson +1 用于制定关键问题。
标签: c++ return-value-optimization copy-elision