我已阅读有关CodeProject http://www.codeproject.com/Tips/103648/C-Tip-How-to-eliminate-Temporary-Objects的文章。
Complex y,z;
Complex x=y+z; /* initialization instead of assignment */
我很困惑,为什么第二个陈述不会创建临时对象?编译器如何工作?
答案 0 :(得分:2)
C ++中有一条规则,如果它们直接用于初始化,它允许编译器将临时值偏离。
无论如何,使用它的余地,编译器可以在没有这个规则的情况下优化示例,这具有相同的效果。
12.8复制和移动类对象§32
当满足某些条件时,允许实现省略类的复制/移动构造 对象,即使对象的复制/移动构造函数和/或析构函数具有副作用。在这种情况下, 该实现将省略的复制/移动操作的源和目标视为两个不同的 引用相同对象的方式,以及对象的破坏发生在时间的晚期 当两个物体在没有优化的情况下被摧毁时.123这种复制/移动的省略 在下列情况下允许称为复制省略的操作(可以合并为 消除多份副本):
- 在具有类返回类型的函数的return语句中,当表达式是a的名称时 具有相同cvunqualified的非易失性自动对象(函数或catch子句参数除外) 键入函数返回类型,可以通过构造省略复制/移动操作 自动对象直接进入函数的返回值
- 在throw-expression中,当操作数是非易失性自动对象的名称时(除了 函数或catch子句参数),其范围不会超出最内层的末尾 封闭try-block(如果有的话),从操作数到异常的复制/移动操作 通过将自动对象直接构造到异常对象
中,可以省略对象(15.1) - 当复制/移动未绑定到引用(12.2)的临时类对象时 对于具有相同cv-unqualified类型的类对象,可以省略复制/移动操作 将临时对象直接构造到省略的复制/移动的目标中 - 当异常处理程序的异常声明(第15节)声明一个相同类型的对象时 (除了cv-qualification)作为异常对象(15.1),可以省略复制/移动操作 通过将异常声明视为异常对象的别名(如果程序的含义) 除了为声明的对象执行构造函数和析构函数之外,它将保持不变 异常声明。
答案 1 :(得分:1)
在您提供的链接的第一个示例中,调用赋值运算符:
Complex x, y, z;
x=y+z;
在您提供的链接的第二个示例中,将调用构造函数:
Complex y,z;
Complex x=y+z;
但在这两种情况下,都会创建一个临时对象(包含值x+y
)。
所以我严重怀疑这个链接的正确性。
我很乐意阅读您的问题的任何答案,否则......
我们可以避免的临时对象通常是传递给函数或通过值而不是通过引用从函数返回的对象。
例如,在下面的Complex::operator+=
中,调用函数时会在堆栈上创建一个临时对象,并在函数返回时在堆栈上创建另一个临时对象:
Complex Complex::operator+=(Complex num)
{
this->real += num.real;
this->imag += num.imag;
return *this;
}
void func()
{
Complex a(1,2);
Complex b(3,4);
a += b;
...
}
为了消除这两个临时对象,您只需通过引用传递和返回:
Complex& Complex::operator+=(Complex& num)
{
...
}
请注意,通过引用传递参数在成员函数和全局函数中是可行的,但通过引用返回参数仅在成员函数中是可行的(除非你从全局函数返回一个全局变量,但在大多数情况下这是毫无意义的。)