c++重载的+运算符没有返回一个临时对象,原因是什么
c++ overloaded + operator does not return a temporary object , why?
这是源代码:
#include<iostream>
using namespace std;
class cat{
private:
int a;
public:
cat():a(1){
cout << "const : " << this << endl;
}
~cat(){
cout << "dest : " << this << endl;
}
cat operator+(cat& rhs){
cout << "+" << endl;
cat x;
x.a=a+rhs.a;
return x;
}
cat operator=(const cat& rhs){
cout << "= : " <<this << endl;
a=rhs.a;
return (*this);
}
cat(const cat& rhs){
cout << "copy const : " << this << endl;
a=rhs.a;
}
};
int main(){
cat ob1;
cat ob2;
cat ob3;
ob1=ob2;
cout << "n 1----1 n" << endl;
ob3=(ob1+ob2);
cout << "n 2----2 n" << endl;
cat ob4=ob1+ob2;
cout << "n 3----3 n" << endl;
}
这是输出:
const : 0x22ff20 // ob1 created
const : 0x22ff1c // ob2 created
const : 0x22ff18 // ob3 created
= : 0x22ff20 // calling = operator
copy const : 0x22ff24 // return temporary object using copy constructor
dest : 0x22ff24 // temporary object is destroyed
1 ---- 1
+ // operator + is called
= : 0x22ff2c // it jums to = operator #### (why ?) ####
copy const : 0x22ff28 // = create a temporary object
dest : 0x22ff28 // temporary object created by = is destroyed
dest : 0x22ff2c // x inside + operator is destroyed
// ##################################################
// #### HERE #### copy constructor to create a temporory object
// like what happend in = operator and also destructor of this
// temporary object did not called
// ##################################################
2 ---- 2
+ // here + operator is called
const : 0x22ff14 // x is creted
//######################""
//#### HERE #### copy constructor ob4 that take ob1+ob2 as an
// argument did not get called, why ?
// and also + operator did not return a temporary object and then
// use it as an argument for the copy constructor
//#######################
3 ---- 3
dest : 0x22ff14 // x destroyed
dest : 0x22ff18 // ob3 destroyed
dest : 0x22ff1c // ob2 destroyed
dest : 0x22ff20 // ob1 destroyed
问题开始于1和2之间,也开始于2和3之间。
所以我的问题在输出中
在1和2之间:为什么+操作符没有返回一个teporary对象,然后像在=操作符中发生的那样销毁它
介于2和3之间:为什么+运算符没有返回一个临时对象,该对象将用作复制构造函数中的参数以创建ob4?
我知道这很长时间,但我真的很感激你的帮助。
允许编译器移除(elide)副本构造并就地构建(在最终目的地)。因此,它是完全有效的。
PS:这里的小错误:
cat operator=(const cat& rhs){
应为:
cat & operator=(const cat& rhs){
// ^^^
有了这个修正,我得到了:
1----1
+ // + called.
const : 0x7fff6b29e848 // Local object to + constructed.
// But the return value will be used as a const ref parameter
// to the assignment operator. So we can elide the actual copy
// if we create the temporary object at the destination and use that.
= : 0x7fff6b29e830 // Now we are in the assignment.
// Just copy the value from the temporary object we created as part
// of the optimizations.
dest : 0x7fff6b29e848 // All finished destroy the temporary.
// Note: I use the term temporary very loosely.
// And refer you to the as-is rule.
所以你的问题似乎是:
在+方法中,您创建了一个名为"x"的本地cat,并返回它。您希望有一个为此调用的构造函数,然后是一个创建匿名返回值的复制构造函数,再是一个x的析构函数,最后是一个返回值的析构函数。你想知道为什么没有发生这种事。(如果我错了,请纠正我)
简而言之,这个问题的答案几乎可以肯定是编译器优化。编译器看到你只是创建x,更改它的一个成员,然后返回它,所以它去掉了所有这些,只是在原地构造返回值。
编译器已经消除了从内部变量x
到返回值的副本,这是通过将两个对象放在同一内存位置并延长对象的生存期来完成的。临时的生存期将一直延长到完整表达式结束,直到您确定为x
的销毁点为止。我手头没有编译器,但我敢打赌,如果您在operator+
中打印x
的地址,并将参数的地址打印到operator=
,它们将是相同的。
至于优化是如何实现的,在我所知道的所有编译器中,按值返回的函数的调用约定规定调用方为返回值保留空间,并将指向未初始化内存的隐藏指针传递给函数。函数中的return语句将在该内存块上创建返回的对象。在这种情况下,在处理operator+
时,编译器意识到x
的全部目的是作为构造返回语句的蓝图,并决定将x
放置在返回值的地址传递中,避免创建两个单独的对象和复制。
进一步阅读:值语义:NRVO//值语义:复制省略
EDIT:NRVO在运算符+中的等价代码转换
调用约定使operator+
等效于:
void operator+( void* rtn, cat * const this, cat const &rhs ) {
cout << "+" << endl;
cat x;
x.a=this->a+rhs.a;
new (rtn) cat(x); // return x;
}
现在编译器看到它可以很容易地执行NRVO,并将其进一步转换为:
void operator+( void* rtn, cat * const this, cat const &rhs ) {
cout << "+" << endl;
new (rtn) cat; // cat x;
*static_cast<cat*>(rtn).a = this->a+rhs.a; // `x` is an alias to
// return x; unnecessary, the return object has been built in place already
}
- PyRun_String返回一个NoneType对象
- 当一个新对象被分配到它的地址时,对象是否必须被销毁
- 在不复制临时对象的情况下延长其生存期
- 为什么当我们有常量引用时创建临时对象?
- 程序如何'remember'临时对象?
- 返回对临时对象的引用
- 防止临时对象文件访问 MSVC 中的磁盘
- 如何创建一个共享对象与另一个.所以在Cmake
- 是否可以在C++中移动临时对象的属性?
- C++:如何创建一个临时对象,包含一个指针 - 常量或非常量,具体取决于上下文
- C 17:一个临时对象从未被摧毁
- 我应该创建一个临时对象来实例化C++中的成员变量吗
- 从C++函数返回一个使用寿命有限的非临时对象
- 可以创建一个临时流对象作为函数的参数
- c++重载的+运算符没有返回一个临时对象,原因是什么
- When是一个临时的,用作已销毁的命名对象的初始值设定项
- C++0x:当一个临时对象等于另一个临时对象时
- c++:当是一个被破坏的临时对象时
- 引用一个未命名的临时对象(生命周期)
- 构造一个临时对象并调用一个返回指针的方法——安全吗?