之前寫拷貝構造函數的時候,以為參數為引用,不為值傳遞,僅僅是為了減少一次內存拷貝。然而今天看到一篇文章發現自己對拷貝構造的參數理解有誤。 參數為引用,不為值傳遞是為了防止拷貝構造函數的無限遞歸,最終導致棧溢出。
下面來看一個例子:
class test{public:test(){cout << "constructor with argument\n";}~test(){}test(test& t){cout << "copy constructor\n";}test&operator=(const test&e){cout << "assignment operator\n";return *this;}};int _tmain(int argc, _TCHAR* argv[]){test ort;test a(ort);test b = ort ;a = b;return 0;}
輸出:
如果這些知識你都能理解。下面就來解釋一下為什么值傳遞會無限遞歸!
如果復制構造函數是這樣的 :
test(test t);
我們調用
test ort;test a(ort); --> test.a(test t=ort)==test.a(test t(ort))-->test.a(test t(test t = ort))==test.a(test t(test t(ort)))-->test.a(test t(test t(test t=ort)))- ...
就這樣會一直無限遞歸下去。
到這里,我們也就明白了,為什么拷貝構造函數的參數一定要為引用,不能為值傳遞的原因了。
接下來,我們再測試一下賦值構造函數的參數,如果我們把它的參數也改為值傳遞,做一個測試。
class test{public:test(){cout << "constructor with argument\n";}~test(){}test(test& t){cout << "copy constructor\n";}test&operator=(test e){cout << "assignment operator\n";return *this;}};int _tmain(int argc, _TCHAR* argv[]){test ort;test a(ort);test b = ort ;a = b;return 0;}
輸出:
賦值構造函數如果為值傳遞,僅僅是多了一次拷貝,並不會無限遞歸。
總結:拷貝構造函數的參數必須為引用。賦值構造函數參數既可以為引用,也可以為值傳遞,值傳遞會多一次拷貝。因此建議賦值構造函數建議也寫為引用類型。(CKK看 剛才我的理解還是有偏差:左右值不是關鍵,減少拷貝次數提高賦值效率是重點)
