建構函式,拷貝賦值函式的N種呼叫情況

audience_fzn發表於2018-08-06

一、 

class Date
{
public:
	Date()//建構函式
	{
		cout << "Date()" << endl;
	}
	Date(const Date& d)//拷貝構造
	{
		cout << "Date(const Date& d)" << endl;
	}
	Date& operator=(const Date& d)//賦值運算子過載
	{
		cout << "Date& operator=(const Date& d)" << endl;
		return *this;
	}
	~Date()//解構函式
	{
		cout << "~Date()" << endl;
	}
};

1.場景一

void fun1(Date d)
{}

int main()
{
	Date d1;
	fun1(d1);
	system("pause");
	return 0;
}
  • Date d1;呼叫建構函式
  • fun1(d1);d1值傳遞,要生成一個臨時變數,拷貝構造(傳值是拷貝構造
  • 倆次析構

2.場景二

void fun2(Date& d)
{}

int main()
{
	Date d1;
	fun2(d1);
	system("pause");
	return 0;
}
  • Date d1;呼叫建構函式
  • fun2(d1);傳的是d1的引用,引用相當於別名,不建立臨時變數,所以這裡宣告當不呼叫
  • 一次析構

3.場景三

Date fun3()
{
	Date d;
	return d;
}

int main()
{
	Date d2=fun3();
	system("pause");
	return 0;
}
  • 呼叫fun3(),Date d;呼叫一次建構函式
  • Date d2 = fun3();return d;返回一個臨時變數,這時也要進行一次拷貝構造
  • Date d2 = fun3();呼叫一次拷貝構造
  • 編譯器會自動優化,將上述倆次拷貝構造合併成一次(在同一表示式中)
  • 倆次析構

所以一共是,一次構造,一次拷貝構造,倆次析構

4.場景四:

Date& fun4()
{
	Date d;
	return d;
}

int main()
{
	Date d2=fun4();
	system("pause");
	return 0;
}
  • Date d;構造
  • Date d2=fun4();析構,fun4()形參一個匿名物件,匿名物件只在這行用以下,馬上析構
  • 拷貝構造d2
  • 析構

5.場景五:

Date fun5()
{
	return Date();
}

int main()
{
	Date d3;
	d3 = fun5();
	system("pause");
	return 0;
}
  • Date d3:構造
  • fun5():函式內進行一次構造
  • d3 = fun5:賦值運算子過載
  • 倆次析構

6.場景六:

Date& fun6()
{
	return Date();
}

int main()
{
	Date d3;
	d3 = fun6();
	system("pause");
	return 0;
}

  • Date d3:構造
  • fun6():函式內進行一次構造
  • fun6()函式返回值是引用,構造了一個匿名引數,立馬析構,呼叫一次析構
  • d3 = fun6():賦值運算子過載
  • 析構d3

二、

class AA
{
public:
	AA()//建構函式
	{
		cout << "AA()" << endl;
	}
	AA(const AA& d)//拷貝構造
	{
		cout << "AA(const AA& d)" << endl;
	}
	AA& operator=(const AA& d)//賦值運算子過載
	{
		cout << "AA& operator=(const AA& d)" << endl;
		return *this;
	}
	~AA()//解構函式
	{
		cout << "~AA()" << endl;
	}

};
AA f(AA a)
{
	return a;
}

1.場景一

void Test1()
{
	AA a1;
	a1 = f(a1);
}
  • AA a1:構造
  • f(a1):拷貝構造;傳值:拷貝構造,傳值過程不能優化
  • return a;返回一個臨時變數拷貝構造
  • a出了作用域即被銷燬,析構
  • a1 = f(a1)賦值運算子過載
  • 倆次析構

2.場景二:

void Test2()
{
	AA a1;
	AA a2 = f(a1);
}
  • AA a1:構造
  • f(a1):值傳遞,拷貝構造
  • AA  a2 = f(a1)拷貝構造,與函式AA的返回臨時變數(return a)拷貝構造,倆次合併成一次,在用一個表單式中,編譯器優化
  • 三次析構

3.場景三:

void Test3()
{
	AA a1;
	AA a2 = f(f(a1));
}
  •  AA a1:構造
  • f(a1):拷貝構造
  • f(f(a1)):拷貝構造 ;與f(a1)的返回值一起優化為一次
  • 一次析構
  • a2 = f(f(a1)):拷貝構造,與f(f(a1))的返回值一起優化為一次
  • 三次析構

相關文章