C++中的拷贝构造函数和以传值方式传递对象参数

今天写一个小题:设11和12均为顺序表,编写一个函数,找出并输出他们的 最大子前级串,并比较剩余串的大小。在将对象作为参数传递给compare函数时,使用传引用的方式传递对象参数,编译可以通过,然而当我使用传值方式传递对象参数,编译器报错:

double free or corruption (fasttop)

以下是程序代码

const int defaultSize = 10;

class SeqList {
protected:
	int* data;
	int maxSize; //表最大可容纳项数
	int last; //当前表大小
public:
	SeqList(int sz = defaultSize);
	~SeqList();
	int Length() const; //计算表长度
	int getData(int i) const; //取第i歌表项的值,存放在x中
	void setData(int i, int x);
	bool Insert(int i, int x); //插入x在第i歌表项之后
	void Remove(int i);
	void output(); // 输出顺序表
};

SeqList::SeqList(int sz)
{
	if (sz > 0) {
		maxSize = sz;
		last = -1;
		data = new int[maxSize];
		if (data == NULL)
			exit(1);
	}
}

SeqList::~SeqList()
{
	delete[]data;
}

int SeqList::Length() const
{
	return last + 1;
}

int SeqList::getData(int i) const
{
	return data[i];
}

void SeqList::setData(int i, int x)
{
	data[i] = x;
}

bool SeqList::Insert(int i, int x)
{
	if (last == maxSize - 1)
		return false;
	if (i<0 || i>last + 1)
		return false;
	int j;
	for (j = last; j >= i; j--)
		data[j + 1] = data[j];
	data[i] = x;
	last++;
	return true;
}

void SeqList::Remove(int i)
{
	int j;
	for (j = i; j <= last - 1; j++)
		data[j] = data[j + 1];
	last--;
}

void SeqList::output()
{
	int i;
	for (i = 0; i <= last; i++)
		cout << data[i] << " ";
	cout << endl;
}
void compare(SeqList a, int n, SeqList b, int m)
{

	int i = 0;
	while (a.getData(i) == b.getData(i))
	{
		i++;
		if (i >= m || i >= n)
			break;
	}
	for (int j = 0; j < i; j++)
	{
		cout << a.getData(j) << ' ';
	}
	cout << endl;

	if (i  == m && i  == n)
		cout << '=' << endl;
	else if (i >= m || a.getData(i) > b.getData(i))
		cout << '>' << endl;
	else if (i >= n || a.getData(i) < b.getData(i))
		cout << '<' << endl;

}
	compare(l1, n, l2, m);

通过百度发现,double free or corruption (fasttop),是由二次delete同一个指针导致的。

使用传值方式传递对象参数时,会创建一个新的临时对象,创建该对象时会利用拷贝构造函数通过复制已有对象的值来创建。而如果我们没有显示的定义拷贝构造函数,c++将会提供一个缺省的拷贝构造函数(copy constructor)。而缺省的拷贝构造函数进行对象赋值时,采用的是“浅拷贝”(shallow copy),而不是“深拷贝”(deep copy)实现。即如果类的成员中存在指针,浅拷贝只会复制指针保存的地址值,而不是复制指针指向的内容。

对于本程序而言,即compare函数中创建的SeqList对象a,其指针成员 a.data ,与compare(l1, n, l2, m) 函数调用中传入的 l1的指针成员 l1.data 地址相同,在函数中对a.data的操作即对l1.data进行操作,因为在构建对象a时,浅拷贝仅实现了a.data  = l1.data,其复制的是data指针保存的地址值,而不是data指针指向的内容。

通过缺省拷贝构造函数创建的对象的数据域中存在指针,就会出现二次 delete 指针的错误。就该程序而言,在拷贝构造时,临时创建的对象在赋值完毕后,会调用析取函数,delete一次data数组,而由于是“浅拷贝”,所以在跳出compare函数,再次调用析取函数时,就会对data数组进行二次删除,程序出错。

要解决这个问题,需要我们自定义拷贝构造函数,实现“深拷贝”。

自定义的拷贝构造函数如下

SeqList::SeqList (SeqList& l)
{
	maxSize = l.maxSize;
	last = l.last;
	data = new int[l.maxSize];
	for (int i = 0; i <= l.last; i++)
	{
		data[i] = l.data[i];
	}
}

运行程序,可以顺利执行。

 

通过此次问题可以看出,虽然传值方式和传引用方式都是允许的,但在行得通的情况下,将对象通过引用传递给函数作参数更加有效,这样不但不需要额外的时间和内存空间,而且会更加直观。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值