1. 程式人生 > >c++中的匿名物件的去留問題和深拷貝淺拷貝

c++中的匿名物件的去留問題和深拷貝淺拷貝

匿名物件的去和留問題:

匿名物件的去和留主要取決於你用什麼去接收這個物件, 具體如下:
# include <iostream>

using namespace std;

class Test
{
private:
	int a;
public:
	Test()
	{
		cout << "我是無參建構函式" << endl;
	}
	Test(int x)
	{
		a = x;
		cout << "我是有參建構函式" << endl;
	}
	Test(Test & obj)
	{
		cout << "copy建構函式" << endl;
	}
	~Test()
	{
		cout << "解構函式" << endl;
	}
	void printA()
	{
		cout << " a = " << a << endl;
	}
};

Test display2()
{
	Test t1;
	return t1;					// 這裡會呼叫一個解構函式和copy建構函式
}
void display1()
{
	Test t2 = display2();		// 上一篇文章中已經講到過, 如果這裡不加 Test t2  , 
								// 那麼display2返回的匿名物件將會被析構掉,那麼現在呢?
	// 除錯發現進入display1函式之後 , 執行 Test t2 = display2(): 這行語句時並沒有再次進入建構函式,也沒進入解構函式
	// 也就是說這次沒有建立新的物件, 同時也沒有析構物件, 那麼 t2 是不是就是代表了原來的匿名物件, 只不過現在已經有名字了?
	// 加入如下程式碼試一次, 
	t2.printA();				// 輸出結果為: a = -858993460
	// 從上面的分析可知, Test t2 並沒有建立物件然而t2卻已經是一個物件了。 所以只可能是 原來的匿名物件被顯示成 t2 了。
	// 再繼續往下除錯, 進入 解構函式。 
	// 以上都是在windows vs2017 上面進行的
}
void display3()
{
	Test t3(2);
	t3.printA();
	t3 = display2();		// 如果是按照這種方式會發生什麼?
							// 在 t3 = display2(); 這一行會進入一次解構函式, 說明匿名物件在這一行被析構了
							// 但是是在等號之前解構函式等號之後析構? 換句話說, t3 還是不是原來定義的t3
	t3.printA();
// 在vs2017中輸出結果為:
//	我是有參建構函式
//		a = 2
//		我是無參建構函式
//		copy建構函式
//		解構函式
//		解構函式
//		a = -858993460
//		解構函式
//		請按任意鍵繼續. . .
	// 結論:由輸出結果可知, 匿名函式是在賦值給t3之後才會被析構。
	// 對輸出結果解釋:首先進入display3函式, 定義t3物件,並且呼叫其建構函式, 呼叫t3的printA()函式
	//				輸出“我是有參建構函式” 和 “a = 2”
	//					然後進入display2函式, 定義t1物件, 並且呼叫其建構函式,
	//				輸出:“我是無參建構函式”
	//					然後return t1; 這句話會返回一個匿名物件並且呼叫copy建構函式, 還會將t1物件析構掉
	//				輸出:“copy建構函式”“解構函式”
	//					在display3函式中, display1返回的匿名物件賦值給 t3 物件之後被析構掉
	//				輸出:“解構函式”
	//					然後由於 t3 物件的 a 已經是原來匿名物件的 a 了, 而且匿名物件又是沒有初始化的, 所以 a 是一個垃圾值
	//				輸出:“a = -858993460”
	//					然後display3執行完, t3 被析構掉
	//				輸出:“解構函式”
}
int main(void)
{
//	display1();
	display3();
	system("pause");
	return 0;
}

深拷貝與淺拷貝

# include <iostream>
# include <cstring>
using namespace std;

class Test
{
private:
	int len;
	char * p;
public:
	Test(const char * myp)
	{
		len = strlen(myp);
		p = (char *)malloc(sizeof(len + 1));
		strcpy(p, myp);
	}
	~Test()
	{
		if (NULL != p)
			free(p);
		p = NULL;
		len = 0;
	}

};
void display()
{
	Test t1("helloworld");
	Test t2 = t1;// error
}
int main(void)
{
	display();
	system("pause");
	
這個程式會發生錯誤; 解釋: 如上圖所示, 因為 Test t2 = t1; 這句程式碼呼叫的copy建構函式是一個淺拷貝, 所以只是將 t1 裡面屬性的值放在 t2 裡面, 也就是說 t1 和 t2 的 p 都指向堆記憶體裡面同一塊地址, 但是在解構函式裡面卻釋放了兩次, 所以Error。 解決辦法:
# include <iostream>
# include <cstring>
using namespace std;

class Test
{
private:
	int len;
	char * p;
public:
	Test(const char * myp)
	{
		len = strlen(myp);
		p = (char *)malloc(sizeof(len + 1));
		strcpy(p, myp);
	}
	// 深拷貝
	Test(const Test & obj1)
	{
		len = strlen(obj1.p);
		p = (char *)malloc(len + 1);
		strcpy(p, obj1.p);
	}
	~Test()
	{
		if (NULL != p)
			free(p);
		p = NULL;
		len = 0;
	}

};
void display()
{
	Test t1("helloworld");
	Test t2 = t1;
}
int main(void)
{
	display();
	system("pause");
	return 0;
}
這樣就ok了, 當然c++裡面不止copy建構函式是取淺拷貝, 其實還有很多地方都是。比如" = "等等。