运算符重载内存泄漏

时间:2015-11-10 18:25:20

标签: c++ vector operator-overloading

最近我有一个在C ++中要做的任务,用union,intersection等实现一个Set类作为重载运算符。我遇到了重载运算符+()的问题。我决定使用向量并获得一些算法库函数的优势。问题是我必须向构造函数传递一个数组指针和数组大小。这有点复杂了这个任务......我可以编译它但是在" 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;
}

我添加了复制构造函数和复制assingment,更改了运算符+(),因为NathanOliver建议,现在我传递给构造函数静态数组。还有内存泄漏和奇怪的事情是,即使在主要只有类变量初始化时,我得到了这个内存泄漏,如果有参数与否也没关系...有什么建议吗?我认为cunstructor是有效的。

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编译器。

3 个答案:

答案 0 :(得分: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;

其次,您需要为您的类定义复制构造函数和赋值运算符。要做到这一点:What is The Rule of Three?

答案 1 :(得分:0)

最佳解决方案(但我无法告知您是否允许特别执行此操作)是在vector内部使用Set并从传入的内容中分配使用双迭代器构造函数的指针和长度。

现在如果不可能,您需要正确管理班级的记忆:

  • 您需要一个复制构造函数和复制赋值运算符。
  • operator+中,您无法创建本地向量,然后获取其内存地址,操作员返回后该内存将立即消失。
  • 可能还有其他我没有抓到的东西。

答案 2 :(得分:0)

如果您有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知道如何在不泄漏资源的情况下正确复制其内容。