我有一个班级
class vlarray {
public:
double *p;
int size;
vlarray(int n) {
p = new double[n];
size = n;
for(int i = 0; i < n; i++)
p[i] = 0.01*i;
}
~vlarray() {
cout << "destruction" << endl;
delete [] p;
size = 0;
}
};
当我在主
中使用时int main() {
vlarray a(3);
{
vlarray b(3);
b.p[0] = 10;
for(int i = 0; i < 3; i++) {
cout << *(b.p+i) << endl;
}
a = b;
} // the magic happens here deallocation of b
for(int i = 0; i < 3; i++) {
cout << *(a.p+i) << endl;
return 0;
}
当b解除分配的smth发生时..问题是什么,为什么会出现这个问题以及如何避免这类问题?
答案 0 :(得分:5)
在这个问题的现有答案中似乎有些混淆,所以我我会跳进去。
您的主要问题是您尚未定义自己的副本分配运算符。相反,编译器会为您生成一个天真的编译器,因此当您运行a = b
时,b
内的指针将被复制到a
中。然后,当b
死亡并且其析构函数运行时,a
内的指针不再有效。另外,a
的原始指针已被泄露。
您自己的副本赋值运算符需要delete
现有数组,分配一个新数组并复制您正在复制的对象中的内容。
更进一步,您还需要定义一些其他内容。这个要求巧妙地总结为Rule of Three (C++03)或Rule of Five (C++11),并且在your favourite, peer-recommended C++ book网上有很多解释可以教你如何满足它。
更好的是,您可以开始使用std::vector
而不是手动分配所有内容,并避免整个混乱:
struct vlarray {
std::vector<double> p;
vlarray(int n) {
p.resize(n);
for(int i = 0; i < n; i++)
p[i] = 0.01*i;
}
};
答案 1 :(得分:4)
您需要遵循C ++ 03中的 Rule of Three 和C ++ 11中的 Rule of Five 。
这些规则的背景和基础:
每当您的类具有带动态内存分配的指针成员时,以及使用任何复制函数(复制构造函数和复制赋值运算符在c ++ 03 中除非你重载这两个成员指针的深层拷贝,否则新创建的对象将继续指向父对象的内存分配(浅拷贝)。当父对象被销毁时出现问题(例如:通过超出范围),它的析构函数被调用,这通常会释放分配给指针成员的内存,当发生这种情况时,具有此指针的浅副本的对象现在指向无效的内存区域,并成为悬空指针。访问这些悬空指针会导致未定义的行为,并且很可能会崩溃。
为了避免这种情况,你需要遵循C ++ 03中的三条规则和C ++ 11中的五条规则 C ++ 03和C ++ 11中规则的区别,因为控制类的复制行为的函数在C ++ 11中已经改变。
三条规则基本上说明:
为您的班级实施复制构造函数,复制赋值运算符和析构函数。
编辑:
如果您使用的是C ++ 11,那么三法则实际上变为 Rule of Five 。
答案 2 :(得分:0)
您未实施的内容称为:
简而言之,
三规则(也称为三巨头或三巨头的规则)是C ++中的经验法则,声称如果一个类定义了下面的一个,它应该明确地定义所有三个:
- 析构者
- 复制构造函数
- 复制分配操作员
醇>
由于您也标记了问题C++11
,因此您必须实现此目的:
答案 3 :(得分:0)
我认为问题在于你没有复制构造函数。编译器试图尽力而为,但并不总是成功。编写一个复制构造函数,然后重试。
答案 4 :(得分:0)
b
的销毁导致成员指针p
被删除。由于此指针已复制到a
,因此a
的成员指针指向已删除的内存。你有不确定的行为。
要避免这种情况,您需要在将一个对象复制到另一个对象的任何位置执行deep copy,通常是复制构造函数和赋值运算符。分配一个新数组并将所有元素从一个数组复制到另一个数组。您现在遵守Rule Of Three,因为您已经定义了析构函数。
解决此问题的最佳方法是完全避免使用原始指针,并将其替换为std::vector
。
答案 5 :(得分:-1)
实例之间的直接转移共享P
。创建一个复制构造函数。
答案 6 :(得分:-1)
将b分配给(a = b)时,编译器生成的复制构造函数会对数据成员执行浅层复制。我并不尊重这些指针。因此,它们共享相同的资源,当它们中的任何一个被销毁时,它们就会将它们的共享资源与它们一起使用
定义您自己的复制构造函数以执行深层复制,或使用像vector这样的数组抽象。
class vlarray {
public:
std::vector<double> p;
int size;
vlarray(int n) {
p.resize(n);
size = n;
for(int i = 0; i < n; i++) p[i] = 0.01*i;
}
~vlarray() {
cout << "destruction" << endl;
}
};