Stackoverflow ( https://stackoverflow.com/ ) 可能是这个问题的更好讨论论坛。但是,这是一个简短的答案。
我怀疑 C++ 编译器是否像你上面描述的那样为这个表达式生成代码。所有现代 C++ 编译器都实现了一种称为“返回值优化”(http://en.wikipedia.org/wiki/Return_value_optimization)的优化。通过返回值优化,结果evolutionMatrix*stateMatrix
直接存储在stateMatrix
; 没有复制。
在这个话题上显然存在相当大的混乱,这也是我建议 Stackoverflow 可能是一个更好的论坛的原因之一。那里有很多 C++“语言律师”,而我们这里的大多数人宁愿把时间花在 CSE 上。;-)
我根据 Bangerth 教授的帖子创建了以下简单示例:
#ifndef NDEBUG
#include <iostream>
using namespace std;
#endif
class ExpensiveObject {
public:
ExpensiveObject () {
#ifndef NDEBUG
cout << "ExpensiveObject constructor called." << endl;
#endif
v = 0;
}
ExpensiveObject (int i) {
#ifndef NDEBUG
cout << "ExpensiveObject constructor(int) called." << endl;
#endif
v = i;
}
ExpensiveObject (const ExpensiveObject &a) {
v = a.v;
#ifndef NDEBUG
cout << "ExpensiveObject copy constructor called." << endl;
#endif
}
~ExpensiveObject() {
#ifndef NDEBUG
cout << "ExpensiveObject destructor called." << endl;
#endif
}
ExpensiveObject operator=(const ExpensiveObject &a) {
#ifndef NDEBUG
cout << "ExpensiveObject assignment operator called." << endl;
#endif
if (this != &a) {
return ExpensiveObject (a);
}
}
void print() const {
#ifndef NDEBUG
cout << "v=" << v << endl;
#endif
}
int getV() const {
return v;
}
private:
int v;
};
ExpensiveObject operator+(const ExpensiveObject &a1, const ExpensiveObject &a2) {
#ifndef NDEBUG
cout << "ExpensiveObject operator+ called." << endl;
#endif
return ExpensiveObject (a1.getV() + a2.getV());
}
int main()
{
ExpensiveObject a(2), b(3);
ExpensiveObject c = a + b;
#ifndef NDEBUG
c.print();
#endif
}
它看起来比实际上更复杂,因为我想在优化模式下编译时完全删除所有用于打印输出的代码。当我运行使用调试选项编译的版本时,我得到以下输出:
ExpensiveObject constructor(int) called.
ExpensiveObject constructor(int) called.
ExpensiveObject operator+ called.
ExpensiveObject constructor(int) called.
v=5
ExpensiveObject destructor called.
ExpensiveObject destructor called.
ExpensiveObject destructor called.
首先要注意的是没有构建临时变量——只有 a、b 和 c。默认构造函数和赋值运算符永远不会被调用,因为在此示例中不需要它们。
Bangerth 教授提到了表达式模板。事实上,这种优化技术对于在矩阵类库中获得良好的性能非常重要。但仅当对象表达式比简单的 a + b 更复杂时才重要。例如,如果我的测试是:
ExpensiveObject a(2), b(3), c(9);
ExpensiveObject d = a + b + c;
我会得到以下输出:
ExpensiveObject constructor(int) called.
ExpensiveObject constructor(int) called.
ExpensiveObject constructor(int) called.
ExpensiveObject operator+ called.
ExpensiveObject constructor(int) called.
ExpensiveObject operator+ called.
ExpensiveObject constructor(int) called.
ExpensiveObject destructor called.
v=14
ExpensiveObject destructor called.
ExpensiveObject destructor called.
ExpensiveObject destructor called.
ExpensiveObject destructor called.
这种情况显示了临时构造的不良构造(对构造函数的 5 次调用和对运算符 + 的两次调用)。正确使用表达式模板(这个话题远远超出了本论坛的范围)可以暂时防止这种情况发生。(对于积极性高的人,可以在http://www.amazon.com/C-Templates-The-Complete-Guide/dp/0201734842的第 18 章中找到关于表达式模板的特别易读的讨论)。
最后,编译器实际在做什么的真正“证明”来自检查编译器输出的汇编代码。对于第一个示例,在优化模式下编译时,这段代码非常简单。所有函数调用都被优化掉了,汇编代码基本上将 2 加载到一个寄存器中,将 3 加载到第二个寄存器中,然后添加它们。