我在理解C++中返回值背後真正做了些什麼困難。返回值(引用,指針和對象)
讓我們下面的代碼:
class MyClass {
public:
int id;
MyClass(int id) {
this->id = id;
cout << "[" << id << "] MyClass::ctor\n";
}
MyClass(const MyClass& other) {
cout << "[" << id << "] MyClass::ctor&\n";
}
~MyClass() {
cout << "[" << id << "] MyClass::dtor\n";
}
MyClass& operator=(const MyClass& r) {
cout << "[" << id << "] MyClass::operator=\n";
return *this;
}
};
MyClass foo() {
MyClass c(111);
return c;
}
MyClass& bar() {
MyClass c(222);
return c;
}
MyClass* baz() {
MyClass* c = new MyClass(333);
return c;
}
我使用gcc 4.7.3。
案例1
當我打電話:
MyClass c1 = foo();
cout << c1.id << endl;
輸出是:
[111] MyClass::ctor
111
[111] MyClass::dtor
我的理解是,在foo
對象是在棧上創建,然後在銷燬返回語句,因爲它是範圍的結尾。返回是通過對象複製(複製構造函數)完成的,稍後將其分配給主(賦值運算符)中的c1
。如果我是正確的,爲什麼沒有複製構造函數或賦值運算符的輸出?這是因爲RVO嗎?
案例2
當我打電話:
MyClass c2 = bar();
cout << c2.id << endl;
輸出是:
[222] MyClass::ctor
[222] MyClass::dtor
[4197488] MyClass::ctor&
4197488
[4197488] MyClass::dtor
這到底是怎麼回事?我創建變量然後返回它,變量被銷燬,因爲它是一個範圍的結束。編譯器試圖通過拷貝構造函數拷貝該變量,但它已經被銷燬,這就是爲什麼我有隨機值?那麼主要在c2
究竟是什麼?
案例3
當我打電話:
MyClass* c3 = baz();
cout << c3->id << endl;
輸出是:
[333] MyClass::ctor
333
這是最簡單的情況?我返回一個動態創建的指針,位於堆上,所以memmory被分配,而不是自動釋放。當析構函數沒有被調用並且我有內存泄漏時,就是這種情況。我對嗎?
是否還有其他不明顯的情況或事情,我應該知道要充分掌握C++中的返回值? ;)從函數返回一個對象的建議方法是什麼(如果有的話) - 對此的任何經驗規則?
'MyClass c1 = foo();'不是一個賦值。這是一個*複製初始化*。 – dyp
嗯,我的錯。所以在所有這些情況下'operator ='不會被調用? – jesper
確實。經驗法則:除非你想暴露內部(像'std :: vector :: operator []'返回一個引用),否則不要返回擁有的原始指針(即一個必須被刪除的),不要返回一個const對象(因爲它禁止了移動語義)。 – dyp