vector复杂对象传参与拷贝构造和赋值函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haimianjie2012/article/details/81277320

为什么在自定义类时,需要重写拷贝赋值函数和拷贝构造函数?

1.理解这个问题前,先要弄明白深拷贝和浅拷贝两个概念:

如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝。

反之,没有重新分配资源,只是对对象中的数据成员进行简单的赋值,就是浅拷贝。默认拷贝构造函数执行的是浅拷贝。

有了浅拷贝为什么还需要浅拷贝?

在某些状况下,类内成员变量需要动态开辟堆内存,如果实行浅拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,错误就来了。

class Test{
public:
  Test(const char *str = "");//构造函数
  Test(const Test& copy);       //拷贝构造函数
  Test& operator = (const Test& assign);       //拷贝构造函数
  ~Test();      //析构函数
private:
  size_t m_size; //字符串的长度
  char *m_data;  //字符串指针
} ;

以类Test的两个对象a、b为例,假设a.m_data的内容为“hi”,a.m_data的内容为“hello”。
i、将a赋值给b,即b.m_data = a.m_data。这就会造成错误,如下图所示:

1、b.m_data 原有内存没有释放,造成内存泄露。

2、b.m_data 和 a.m_data指向了同一块内存,任何一方变动都会影响另一方。

3、对象析构时,m_data析构了两次。

ii、拷贝构造也是同样的道理

两个成员变量指针也指向同一块内存。当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。

2.C++在以下三种情况下,需要调用拷贝构造函数:

一个对象以值传递的方式传入函数体 
一个对象以值传递的方式从函数返回 
一个对象需要通过另外一个对象进行初始化。

注:

    A a(a1);//一个对象需要通过另外一个对象进行初始化,调用拷贝构造函数

    a3=a2;//把一个对象赋值给另外一个已经存在的对象,调用拷贝赋值函数

拷贝构造函数与拷贝赋值函数的区别和具体实现方式参见下面代码:

#pragma once
#include<vector>
using namespace std;

class MyPoint
{
public:
	MyPoint();
	~MyPoint();
	MyPoint(const MyPoint& copy);       //拷贝构造函数
	MyPoint& operator = (const MyPoint& assign);       //拷贝构造函数

public:
	int mindex;
	POINT* lineData;
	int width;
};

class MyImg
{
public:
	MyImg();
	~MyImg();
	MyImg(const MyImg& copy);       //拷贝构造函数
	MyImg& operator = (const MyImg& assign);       //拷贝构造函数
public:
	int mNum;
	int width;
	int height;
	int** mimg;
	vector<MyPoint> mvLine;

};
#include "stdafx.h"
#include "MyPoint.h"
MyPoint::MyPoint()
{
	lineData = NULL;
}

MyPoint::~MyPoint()
{
	if (lineData!=NULL)
	{
		delete[] lineData;
	}
}
//拷贝构造函数
MyPoint::MyPoint (const MyPoint& copy)
{
	mindex = copy.mindex;
	width = copy.width;
	lineData = new POINT[width];
	for (int i = 0; i < width; i++)
	{
		lineData[i].x = copy.lineData[i].x;
		lineData[i].y= copy.lineData[i].y;
	}


}
//拷贝构造函数
MyPoint& MyPoint::operator = (const MyPoint& assign)
{
	if (this != &assign)
	{
		mindex = assign.mindex;
		width = assign.width;
		POINT* tm = new POINT[width];
		for (int i = 0; i < width; i++)
		{
			tm[i].x = assign.lineData[i].x;
			tm[i].y = assign.lineData[i].y;
		}
		delete [] lineData;
		lineData = tm;
	}
	return *this;
}

MyImg::MyImg()
{
	mNum = 0;
	mimg = NULL;
}
MyImg::~MyImg()
{
	if (mimg != NULL)
	{
		delete[] mimg;
		mimg = NULL;
	}

	mvLine.clear();
	
}
//拷贝构造函数
MyImg::MyImg(const MyImg& copy)
{
	mNum = copy.mNum;
	width = copy.width;
	height = copy.height;
	mimg = new int*[width];
	for (int i = 0; i < width; i++)
	{
		mimg[i] = new int[height];
		for (int j = 0; j < height; j++)
		{
			mimg[i][j] = copy.mimg[i][j];
		}
	}

	mvLine.clear();
	for (int i = 0; i < copy.mvLine.size(); i++)
	{
		MyPoint mPoint;
		mPoint.mindex = copy.mvLine[i].mindex;
		mPoint.width = copy.mvLine[i].width;
		mPoint.lineData = new POINT[width];
		for (int j = 0; j < width; j++)
		{
			mPoint.lineData[j].x = copy.mvLine[i].lineData[j].x;
			mPoint.lineData[j].y = copy.mvLine[i].lineData[j].y;
		}
		mvLine.push_back(mPoint);

	}

}
//拷贝构造函数
MyImg& MyImg::operator = (const MyImg& assign)
{
	if (this != &assign)
	{
		mNum=assign.mNum;
		width = assign.width;
		height = assign.height;
		int** tmimg=new int*[width];
		for (int i = 0; i < width; i++)
		{
			tmimg[i] = new int[height];
			for (int j = 0; j < height; j++)
			{
				tmimg[i][j] = assign.mimg[i][j];
			}
		}
		for (int i = 0; i < width; i++)
		{
			delete[] mimg[i];
		}
		delete[] mimg;
		mimg = tmimg;

		mvLine.clear();
		for (int i = 0; i < assign.mvLine.size(); i++)
		{
			MyPoint mPoint ;
			mPoint.mindex = assign.mvLine[i].mindex;
			mPoint.width = assign.mvLine[i].width;
			mPoint.lineData = new POINT[width];
			for (int j = 0; j < width; j++)
			{
				mPoint.lineData[i].x = assign.mvLine[i].lineData[j].x;
				mPoint.lineData[i].y = assign.mvLine[i].lineData[j].y;
			}
			mvLine.push_back(mPoint);

		}
	}
	return *this;
}

vector传参的问题:

1.vector的几种传参方式测试

//引用和指针都可传回来值
void AddTestVector::ReturnVector(vector<MyPoint> vPoint, vector<MyPoint> & mvPoint, vector<MyPoint*> pvPoint)
{
	for (int i = 0; i < vPoint.size(); i++)
	{
		for (int j = 0; j < vPoint[i].width; j++)
		{
			vPoint[i].lineData[j].x = 5;
			vPoint[i].lineData[j].y = 2;
		}
		
	}
	for (int i = 0; i < mvPoint.size(); i++)
	{
		for (int j = 0; j < mvPoint[i].width; j++)
		{
			mvPoint[i].lineData[j].x = 5;
			mvPoint[i].lineData[j].y = 2;
		}

	}
	for (int i = 0; i < pvPoint.size(); i++)
	{
		for (int j = 0; j < pvPoint[i]->width; j++)
		{
			pvPoint[i]->lineData[j].x = 5;
			pvPoint[i]->lineData[j].y = 2;
		}

	}
}
void AddTestVector::TestVectorOne()
{
	vector<MyPoint> vPoint;
	vector<MyPoint>   mvPoint;
	vector<MyPoint*> pvPoint;
	MyPoint myPnt;
	myPnt.width = 5;
	myPnt.mindex = 1;
	myPnt.lineData = new POINT[myPnt.width];
	for (int i = 0; i < myPnt.width; i++)
	{
		myPnt.lineData[i].x = 1;
		myPnt.lineData[i].y = 1;
	}
	vPoint.push_back(myPnt);
	mvPoint.push_back(myPnt);
	pvPoint.push_back(&myPnt);
	ReturnVector(vPoint, mvPoint, pvPoint);
	int wid1 = vPoint[0].width;
	int index = vPoint[0].mindex;
	for (int i = 0; i < wid1; i++)
	{
		int vpx = vPoint[0].lineData[i].x;//x=1,并没有改变值
		int vpy = vPoint[0].lineData[i].y;//y=1,

		int mvpx = mvPoint[0].lineData[i].x;//x=5
		int mvpy = mvPoint[0].lineData[i].y;//y=2

		int pvx = pvPoint[0]->lineData[i].x;//x=5
		int pvy = pvPoint[0]->lineData[i].y;//y=2
	}
}

2.vecotor包含对象中包含vector时如何将改变的值传出来

void  AddTestVector::process_mul_layer_line(vector<MyImg> &curImg)
{
	vector<MyImg> tmImg=curImg;//调用MyImg的拷贝构造函数,tmImg,curImg指向两个不同地址
	curImg.clear();//此时,curImg的size为0,tmImg的size没有改变
	for (int i = 0; i < tmImg.size(); i++)
	{
		MyImg tm = tmImg[i];
		for (int  k = 0; k < tm.mvLine.size(); k++)
		{
			for (int j = 0; j < tm.width; j++)
			{
				tm.mvLine[k].lineData[j].x =5;
				tm.mvLine[k].lineData[j].y = 3;
			}
		}
		curImg.push_back(tm);
	}
	
}
void AddTestVector::TestImg()
{
	MyImg curImg;
	curImg.mNum = 1;
	curImg.width = 3;
	curImg.height =4;
	curImg.mimg = new int*[curImg.width];
	for (int i = 0; i < curImg.width; i++)
	{
		curImg.mimg[i] = new int[curImg.height];
		for (int j = 0; j < curImg.height; j++)
		{
			curImg.mimg[i][j] = 1;
		}

	}

	MyPoint myPnt;
	myPnt.width = 5;
	myPnt.mindex = 1;
	myPnt.lineData = new POINT[myPnt.width];
	for (int i = 0; i < myPnt.width; i++)
	{
		myPnt.lineData[i].x = 1;
		myPnt.lineData[i].y = 1;
	}
	curImg.mvLine.push_back(myPnt);
	vector<MyImg> curImgs;
	curImgs.push_back(curImg);
	process_mul_layer_line(curImgs);
	for (int i = 0; i < curImgs.size(); i++)
	{
		MyImg tm = curImgs[i];
		for (int k = 0; k < tm.mvLine.size(); k++)
		{
			for (int j = 0; j < tm.width; j++)
			{
				//x,y的值已经改变,x=5,y=3
				printf("第一个 x:%d,y:%d", tm.mvLine[k].lineData[j].x,tm.mvLine[k].lineData[j].y);
			}
		}

	}
	
}

猜你喜欢

转载自blog.csdn.net/haimianjie2012/article/details/81277320