天天看點

C++拷貝構造函數被調用的時機

拷貝構造函數調用的幾種情況:當用類的一個對象去初始化該類的另一個對象(或引用)時系統自動調用拷貝構造函數實作拷貝指派。若函數的形參為類對象,調用函數時,實參指派給形參,系統自動調用拷貝構造函數。當函數的傳回值是類對象時,系統自動調用拷貝構造函數。

拷貝構造函數調用的幾種情況:

  • 當用類的一個對象去初始化該類的另一個對象(或引用)時系統自動調用拷貝構造函數實作拷貝指派。
  • 若函數的形參為類對象,調用函數時,實參指派給形參,系統自動調用拷貝構造函數。(這裡可有可能被編譯器優化)
  • 當函數的傳回值是類對象時,系統自動調用拷貝構造函數。(注意會有編譯器可能會進行優化,而觀察不到拷貝的發生)

舉例說明:

#include<ctime>
#include<cstdlib>
#include<iterator>
#include<algorithm>
#include<iostream>
#include<numeric>
using namespace std;

class A {
public:
	A():data(0){}
	A(const A& a){
		data = a.data;
		cout << "拷貝構造函數調用\n";
	}
	A& operator=(const A&a){
		data = a.data;
		cout << "調用指派函數\n";
		return *this;
	}

	int data;
};

void fun1(A a) {
	return ;
}

A fun2() {
	A a;
	return a;
}

int main() {
	A a;
	A b(a);          //用類的一個對象a去初始化另一個對象b
	A c = a;         //用類的一個對象a去初始化另一個對象c,注意這裡是初始化,不是指派
	fun1(a);         //形參為類對象,實參初始化形參,調用拷貝構造函數。
	A d = fun2();    //函數傳回一個類對象時, 這裡可能會被編譯器優化,進而可能沒有調用拷貝構造
	d = a;           //d已經初始化過了,這裡是指派,調用指派函數

	return 0;
}
           

需要注意,在第三條:當函數的傳回值是類對象時,系統自動調用拷貝構造函數。這裡預設情況下一般會被編譯器優化,減少不必要的拷貝構造,是以,具體的傳回值可能會因編譯器及編譯選項的不同而不同。使用g++編譯器,關閉優化

g++ xxx.cpp -fno-elide-constructors

後執行結果如下:

拷貝構造函數調用
拷貝構造函數調用
拷貝構造函數調用
拷貝構造函數調用
拷貝構造函數調用
調用指派函數
           

預設情況下,優化後的結果如下:

拷貝構造函數調用
拷貝構造函數調用
拷貝構造函數調用
調用指派函數
           
編譯器具體是怎麼優化的,一般編譯器會先看支不支援拷貝優化,如果不支援,再看有沒有定義移動構造函數,如果都沒有,就調用拷貝構造函數。更具體的細節可以參考移動語義及拷貝優化的内容。