当我运行下面的代码时,它崩溃了。如果我删除析构函数,它就会起作用。为什么?
#include <iostream>
#include <stdlib.h>
#include <stdarg.h>
using namespace std;
class vectmy {
public: int size;
int * a;
vectmy(int n, int val);
~vectmy() {
delete[] a; //IF I DELETE THIS PROGRAM WORKS
}
vectmy & operator = (const vectmy & );
};
vectmy::vectmy(int n, int val) {
size = n;
a = new int[n + 1];
for (int i = 0; i < n; ++i) {
*(a + i) = val;
}
}
vectmy & vectmy::operator = (const vectmy & param) {
for (int i = 0; i < 3; ++i) a[i] = param.a[i];
return * this;
}
vectmy operator + (vectmy left, vectmy right) {
vectmy result = left;
for (int i = 0; i < 3; ++i) result.a[i] = result.a[i] + right.a[i];
return result;
}
int main() {
int b1[3] = {
1,
2,
4
};
vectmy d(3, 2), b(3, 4), c(3, 0);
c = (b + d);
for (int j = 0; j < 3; ++j) cout << c.a[j] << ' ' << endl;
return 0;
}
当我运行时它崩溃了。如果我删除析构函数,它就会起作用。为什么会这样?
您的
operator +
在此处创建 left
的 副本:
vectmy result = left;
由于您没有显式定义复制构造函数,编译器将隐式生成一个执行成员明智复制的复制构造函数。
a
数据成员的无意义副本意味着a
指针最终将指向vectmy
的两个不同实例(result
和left
)的相同位置,两者都将
delete[]
销毁后。
这种双重删除会给你的程序带来未定义的行为,在你的情况下表现为崩溃。
这是三法则的要点:每次有用户定义的复制构造函数、赋值运算符或析构函数时,您可能应该定义它们的全部。
原因是,您通常会定义这些函数之一,因为您正在管理某些资源(在您的情况下是内存),并且您通常希望在复制、销毁或分配管理资源的对象时执行正确的操作。在这种特殊情况下,缺少适当的复制构造函数。您可以这样定义它:
vectmy::vectmy(vectmy const& v)
{
size=v.size;
a = new int[size];
*this = v;
}
此外,我建议您尽可能避免通过原始指针、
new
和
delete
(或它们的数组对应项)进行手动内存管理,并考虑使用
std::vector
来代替。
更新:
另请注意,您的operator +
正在按值接受其参数,这意味着每个参数都将被复制(即,将调用复制构造函数)。 由于这里并不需要副本,因此您可能希望通过引用获取参数(参见
const
):
vectmy operator + ( vectmy const& left, vectmy const& right)
// ^^^^^^ ^^^^^^