函数参数初始化
调试错误
#include <iostream>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
class CVector
{
int *_data;
int _n;
public:
CVector(int *arr, int n) : _n(n)
{
_data = new int[n];
for (int i = 0; i < n; i++)
{
_data[i] = arr[i];
}
}
CVector()
{
_n = 5;
_data = new int[_n];
for (int i = 0; i < 5; i++)
{
_data[i] = i;
}
}
~CVector()
{
delete[] _data;
}
friend CVector add(const CVector v1, const CVector v2);
void say()
{
for (int i = 0; i < _n - 1; i++)
{
cout << _data[i] << ' ';
}
cout << _data[_n - 1];
cout << endl;
}
};
// CVector add(const CVector v1, const CVector v2)
// {
// int *arr = new int[v1._n];
// for (int i = 0; i < v1._n; i++)
// {
// arr[i] = v1._data[i] + v2._data[i];
// }
// return CVector(arr,v1._n);
// }
CVector add(const CVector v1, const CVector v2)
{
int *arr = new int[v1._n];
for (int i = 0; i < v1._n; i++)
{
arr[i] = v1._data[i] + v2._data[i];
}
CVector res(arr, v1._n);
delete[] arr; // 手动释放 arr 所指向的内存
return res;
}
int main()
{
int T;int n;
cin >> T;
while (T--)
{
cin >> n;
int arr[2][n];
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < n; i++)
{
cin >> arr[j][i];
}
}
CVector v1(arr[0], n);
CVector v2(arr[1], n);
v1.say();
v2.say();
add(v1, v2).say();
}
}
tx说:“啊我构造函数写了啊,new、delete没搞错啊,为什么这样会段错误呢?”
首先,确定是是指针重复释放错误;
其次,gdb逐行调试发现问题在80行的时候会报段错误,那其实就是暗示上面定义的那两个CVector的变量里面的指针被重复释放了。
从79行的add()
函数进去每一步都单步进入,发现在出这个函数之前就调用了三次析构(cout<<"Destructor\n"
的方式);这是正常的因为参数表内的变量是局部变量,他们生命周期就是这么长;
但是我一开始没回忆起来之后就是马上就是段错误了;在离开add()
前再次单步进入,就顺利进入到main函数内部的两个CVector对象,然后在delete那一行seg fault。
为什么参数表上的东西释放了之后外面的东西也被释放了?
首先我们得知道
调用函数的时候,我们传入参数的过程:
等效于
swap(a,b);
swap(int m = a,int n = b);
因此
add(v1, v2).say();
就是
CVector add(const CVector v1=v1, const CVector v2=v2)
我们把这个过程叫做初始化,为什么叫初始化?变量在定义的时候、创建的时候赋值才叫初始化。我们调用函数的那一刻,这个函数被从代码段压栈的时候,他的参数才被从右往左一个一个定义,一个一个赋值,一个一个压栈。(然后按照定义时候的逆序一个一个释放)
还有一点:
default的对象初始化(无论写的是=还是()都是调用拷贝构造)浅拷贝
解决方案
传入引用,引用的本质是指针,指针变量在函数末尾会被释放但是指针的内容在函数末尾不会被影响到,因为那个东西根本就不在函数里,没有被压栈。
还有就是补一个拷贝构造。
后续
要求汇编代码知识以及操作系统知识。