[英]operator overloading memory leak
最近我有一个用C ++要做的任务,用重载,交集等实现Set类作为重载运算符。 我在重载operator +()时遇到了问题。 我决定使用向量,并从某些算法的库函数中受益。 问题是我不得不向构造函数传递数组指针和数组大小。 这使这个任务有点复杂...我可以编译它,但是在执行“ z = a + b”操作时遇到了某种内存泄漏。 谁能解释我在做什么错?
class Set {
int number; // array size (can't be changed)
int *elems; // array pointer (same)
public:
Set();
Set(int, int*); // (can't be changed)
~Set();
friend Set operator+(const Set& X,const Set& Y){
std::vector<int> v(X.number+Y.number);
std::vector<int>::iterator it;
it=std::set_union (X.elems, X.elems+X.number, Y.elems, Y.elems+Y.number, v.begin());
v.resize(it-v.begin());
Set Z;
Z.number=v.size();
Z.elems=&v[0];
return Z;
}
};
Set::Set(){};
Set::Set(int n, int* array){
number=n;
elems = array = new int[number];
for(int i=0; i<number; i++) // creating Set
std::cin >> elems[i];
std::sort(elems, elems + number);
}
Set::~Set(){
delete[] elems;
}
int main(){
int* pointer;
Set z;
Set a = Set(5, pointer);
Set b = Set(2, pointer);
z=a+b;
}
我添加了拷贝构造函数和拷贝声明,按照NathanOliver的建议更改了operator +(),现在我将传递给构造函数静态数组。 仍然有内存泄漏,奇怪的是,即使在主目录中只有类变量初始化时,我还是得到了该内存泄漏,是否与参数无关...有什么建议吗? 我认为讲师是有效的。
Set::Set(int n, int* array){
number = n;
elems = array;
std::sort(elems, elems + number);
}
Set::Set(const Set& s){
number=s.number;
elems=s.elems;
}
Set& operator=(const Set& X){
if(this==&X)
return *this;
delete [] elems;
elems=X.elems;
number=X.number;
return *this;
我使用gcc(tdm64-2)4.8.1编译器。
在
friend Set operator+(const Set& X,const Set& Y){
std::vector<int> v(X.number+Y.number);
std::vector<int>::iterator it;
it=std::set_union (X.elems, X.elems+X.number, Y.elems, Y.elems+Y.number, v.begin());
v.resize(it-v.begin());
Set Z;
Z.number=v.size();
Z.elems=&v[0];
return Z;
}
创建一个矢量,对其进行修改,然后将elems
设置为指向该矢量包含的内容。 这样做的问题是,当向量在函数末尾被破坏时,该向量所保留的内存将被释放。 因此,您现在有了一个指向不再拥有的内存的指针。 尝试执行任何操作都是未定义的行为。 您可以做的是创建一个新数组,将vector
的元素复制到该数组中,然后将新数组分配给`elems
Set Z;
Z.number= v.size();
Z.elems= new int[z.number];
for (int i = 0; i < Z.number; i++)
Z.elems[i] = v[i];
return Z;
其次,您需要为类定义一个复制构造函数和赋值运算符。 为此,请参阅: 什么是“三法则”?
最好的解决方案(但是我不能告诉您是否被允许这样做)是在Set
内部使用vector
,并使用两次迭代器构造函数根据传入的指针和length对其进行分配。
现在,如果不可能,则需要适当地管理类的内存:
operator+
您无法创建本地向量,然后获取其内存地址,该内存将在操作员返回后立即消失。 当z=a+b
,将使用Set
类的赋值运算符 。 您没有定义此运算符的自定义版本,因此使用了默认的编译器生成的版本 。 这个由编译器生成的赋值operator=()
只是简单地执行成员复制 。
由于Set
类中拥有原始拥有的指针 ,因此无法正常工作:默认的编译器生成的operator=()
浅表复制指针,而应深度复制数据。
解决此问题的一种方法是定义您自己的operator=()
版本,并注意对源数据进行适当的深度复制 。
请注意,在这种情况下,您还应该定义一个复制构造函数 。
但是更好的选择是摆脱拥有的原始指针数据成员,而使用RAII构建块类,例如std::vector
。
因此,例如,代替这些数据成员:
int number; // array size (can't be changed) int *elems; // array pointer (same)
您可能只有一个:
std::vector<int> elems;
如果这样做,默认的编译器生成的operator=()
会很好地工作,因为它将复制std::vector
数据成员(而不是原始拥有的指针),并且std::vector
知道如何正确复制其内容不会泄漏资源。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.