[英]Copy constructor not called when returning from overloaded + operator to overloaded = operator
[英]Why copy constructor is not called when returned value from overloaded operator is passed
考慮以下情形
class Integer
{
long long n;
public:
Integer(long long i):n(i){}
Integer(){cout<<"constructor";}
void print()
{
cout<<n<<endl;
}
Integer(const Integer &a){cout<<"copy constructor"<<" "<<a.n<<endl;}
Integer operator+(Integer b);
};
Integer Integer:: operator+(Integer b)
{
this->n = this->n + b.n;
return *this;
}
int main()
{
// your code goes here
Integer a(5);
Integer b(6);
Integer c(a+b);//line 1
return 0;
}
如果a+b
是臨時的,那么我知道不會調用復制構造函數。 但是a+b
不會返回臨時值。 我得到的輸出是
copy constructor 6 //this is because Integer object is passed as value to operator+
copy constructor -5232903157125162015 //this is when object is returned by value from operator+
我認為使用a+b
初始化c
時應該再有一個調用。 大多數相關問題都與返回值優化有關,但i
不能將RVO與之相關。
您說a+b
不返回臨時 。 錯誤。 a+b
(即使它改變了a
必將誤導的未來讀者...)返回的臨時副本a
,因為它被聲明為返回一個Integer
,而不是一個參考( Integer&
)。
所以這是發生了什么:
Integer a(5); // creates an integer from int 5
Integer b(6); // creates an integer from int 6
Integer c(a+b); /* first creates a temp using copy ctor from b
updates a
creates a temp copy of the result
should create an integer by copy of the result (elided)
destroys the temporary created from b
*/
return 0; // destroys c, b, a
順便說一句:您忘記了在副本ctor中初始化n
應該是:
Integer(const Integer &a):n(a.n) {cout<<"copy constructor"<<" "<<a.n<<endl;}
您正在見證構造函數的復制效果 。
當將無名稱的臨時對象(未綁定任何引用)移動或復制到相同類型的對象中(忽略頂級cv限定)時,將忽略復制/移動。 構造該臨時文件后,將直接在將其移動或復制到的存儲中直接構建它。 當無名臨時變量是return語句的參數時,復制省略的這種變體稱為RVO,即“返回值優化”。
要查看預期的輸出(不省略構造函數),請在gcc
使用-fno-elide-constructors
選項。
編輯
正如我對您的問題Integer:: operator+
評論中所提到的那樣。 此外,如其他答案中所述,您的副本構造函數不執行成員的初始化,因此會導致未定義的行為。
為了回答您的問題,復制構造函數從不復制任何內容,並且+
運算符未正確重載。 此外,默認構造函數將未初始化的成員留給Integer
類,這可能導致未定義的行為(不是該行為的100%),這可能會導致某些問題。
因此發生了什么事,因為復制構造函數實際上從未將值復制到*this
的n
成員中,因此會調用默認構造函數,並且std :: cout顯示'a.n'的n
位置處的任何內容; 如果未初始化,則可能是任何東西。
如果不完美,Caltech的這個網站是很好的參考,可供重載操作員使用。
嘗試這個。
#include <iostream>
using namespace std;
class Integer{
long long n;
public:
Integer(long long i):n(i){}
//Integer(){cout<<"cosntructor";} //This creates an unitialized instance of integer.
Integer(){// Do this instead.
n = 0;
cout << "Constructor" << endl;
}
void print(){
cout<<n<<endl;
}
//Integer(const Integer &a){cout<<"copy constructor"<<" "<<a.n<<endl;} // This isn't a copy contructor.
Integer(const Integer &a){ //This is a copy contructor.
this->n = a.n;
cout << "Copy constructor" << " " << a.n << endl;
}
Integer& operator+=(const Integer &);
Integer operator+(const Integer &);
};
Integer& Integer::operator+=(const Integer &b){ //Always overload incrementors/decrementors first, makes life easier.
this->n = this->n + b.n;
return *this;
}
Integer Integer:: operator+(const Integer &b){
return Integer(*this)+=b.n; //Notice the use of overloaded incrementor inside the '+' operator.
}
int main(){
// your code goes here
Integer a(5);
Integer b(6);
Integer c(a+b);//line 1
return 0;
}
它具有正確數量的復制ctor調用:
第一個是b
因為operator+(Integer b)
按值接受Integer
。
第二個是由operator+
結果創建的c
。
按照標准,可能會有第三個調用: return *this
可能創建了一個臨時文件,以后將其復制到c
。 但實際上,它總是被忽略。 您可以在gcc&clang中關閉此省略號,而不能在MSVC中將其關閉。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.