繁体   English   中英

操作员超载内存泄漏

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM