问题:
我在写一个简单的顺序表合并的函数:
serList* serList::mergeList(serList other)//归并另外一个线性表(已经排完序),返回值为另外一个线性表
{
serList* arr2 = new serList(length + other.getLength());
int p1 = 0;
int p2 = 0;
int sum = this->p + other.getP();
while(p1 < this->p && p2 < other.getP()){
if (arr[p1] <= other.At(p2)) {
arr2->AddOne(arr[p1]);
p1++;
}
else {
arr2->AddOne(other.At(p2));
p2++;
}
}
sum = sum - p1 - p2;
if (p1 == this->p) {
for (int i = 0; i < sum; i++) {
arr2->AddOne(other.At(p2));
p2++;
}
}
else {
for (int i = 0; i < sum; i++) {
arr2->AddOne(arr[p1]);
p1++;
}
}
return arr2;
}
main:
int main() {
serList a;
a.AddOne(1);
a.AddOne(5);
a.AddOne(5);
a.AddOne(5);
a.AddOne(3);
a.AddOne(9);
a.AddOne(9);
a.AddOne(10);
a.AddOne(-1);
a.AddOne(-1);
a.AddOne(11);
serList a2;
a2.AddOne(1);
a2.AddOne(3);
a2.AddOne(7);
a2.AddOne(58);
a2.AddOne(33);
a2.AddOne(97);
a2.AddOne(9);
a.mergeList(a2)->Print();
return 0;
}
然后再main函数执行的时候出现:
代码的输出都正常,只是跳出这个窗口
解决过程:
首先这个类如下:
class serList {
private:
int length;
int p;
TYPE* arr;
public:
serList();//若不加以限定,则length默认为100
serList(int length);//申请动态内存
~serList();//析构函数释放申请的动态内存
int getLength();//获取最大容量Length
int getP();//获取当前线性表的有效元素个数
TYPE At(int k);//获取第k个元素的值,超出错误
bool isEmpty();//判断是否为空
//添加x,返回添加x后的线性表本身
serList& AddOne(TYPE x);
//删除x,x为从头找到的第一个值为x的元素,没有就不动,返回线性表本身
serList& Delete(TYPE x);
void DeleteByIndex(int index);//删除下标为index的元素,没有就不动
//删除重复元素,前提是已经排好序,返回线性表本身
serList& DeleteRe();
serList& Sort();//排序,采用快排,返回本身
void Quick(int l, int r);//辅助Sort()
void swap(TYPE* a, TYPE* b);//交换ab
serList& Revers();//”逆置“线性表
serList& moveL(int k);//向左循环左移k位
serList& moveR(int k);//向右循环右移k位
serList* mergeList(serList other);//归并另外一个线性表
void Print();//打印serList
};
析构函数:
serList::~serList() {
delete(arr);
}
这个类里面有个arr变量为一个指针(导致后面的问题)
此函数是对象作为参数,在c++中,类作为形参和普通变量是不一样的,类多了一个拷贝构造函数并且在函数执行结束后还会调用析构函数,而此例子中main函数中以a2作为参数,那么在调用该函数时就会产生一个临时的形参对象,该对象的初始化就是用了拷贝构造函数,会把arr的值也赋值给形参,此时a2和other(形参)有一样的arr值,有一样的地址,而在函数结束后,作为形参的other会调用析构函数,会释放arr对应的地址,这个过程也把main函数中的a2的arr对应地址释放了,a2作为一个main函数中的对象,在main函数执行结束后也会调用a2的析构函数,会释放那个已经释放的内存,就会出现开始时的那个页面。
解决方案
serList* mergeList(serList& other);//归并另外一个线性表
将参数换成引用类型,问题解决!
因为用了引用类型,函数结束时就不会调用析构函数,就不会出现释放两次的情况。
也提醒我们,以类作为函数参数时,要注意析构函数对传进对象的元素的影响,一定情况下可以用引用类型避免析构函数的调用。