简体   繁体   English

复制构造函数 memory 泄漏

[英]Copy constructor memory leaks

I am trying to learn the basics of writing my custom constructors but I cannot figure out what I'm doing wrong.我正在尝试学习编写自定义构造函数的基础知识,但我无法弄清楚我做错了什么。 I know that for my purposes it would be enough to let the compiler do its' job, but I'm curious how I could fix my definitions.我知道就我的目的而言,让编译器完成它的工作就足够了,但我很好奇如何修复我的定义。

#include <iostream>
#include <stdexcept>

class Matrix {
    public:
      Matrix(int rows, int cols);    //my custom constructor
     ~Matrix();                      //my custom destructor
      Matrix(const Matrix& m);       //my custom copy constructor
      Matrix& operator= (const Matrix& m);  //my custom assignment operator
    private:
      int rows_, cols_;
      double* data_;
    };


Matrix::Matrix(int rows, int cols): rows_ (rows), cols_ (cols){  
if (rows == 0 || cols == 0)
    throw std::out_of_range("Matrix constructor has 0 size");
data_ = new double[rows * cols];     
}
 
 
Matrix::~Matrix()       
{
    delete[] data_;
}


Matrix::Matrix(const Matrix& m) : rows_(m.rows_), cols_(m.cols_)
{
data_ = new double[rows_ * cols_];
data_=m.data_;
} 


Matrix& Matrix::operator=(const Matrix& m){     
if(this != &m){
        double* newdata_=new double[m.cols_*m.rows_];
        *newdata_=*data_;
        delete[] data_;
        data_=newdata_;
        rows_=m.rows_;
        cols_=m.cols_;
        }   
return *this;

}
    

Then in the main part of the program:然后在程序的主要部分:

int main(){

Matrix m1(2,2);//creating a matrix of size 2x2


Matrix m2=m1;  //this doesn't work
Matrix m3(m1); //nor this




return 0;
}

The error upon running the executable is: free(): double free detected in tcache 2运行可执行文件时的错误是:free(): double free detected in tcache 2

Am I correct in thinking that neither the copy constructor nor the assignment operator lead to the destructor being called?我认为复制构造函数和赋值运算符都不会导致调用析构函数是否正确? Why is that?这是为什么?

The basic problem is that you are not copying the data after you've allocated the memory in the copy constructor.基本问题是在复制构造函数中分配 memory 后,您没有复制数据

Matrix::Matrix(const Matrix& m) : rows_(m.rows_), cols_(m.cols_)
{
    data_ = new double[rows_ * cols_];
    data_ = m.data_;  // <-- This is wrong
} 

The line with the // <-- This is wrong comment not only wipes away the preceding line (where the memory is allocated), it doesn't copy any of the actual data.带有// <-- This is wrong注释的行不仅擦除了前一行(memory 被分配的位置),它不会复制任何实际数据。 All it does is copy the pointer value.它所做的只是复制指针值。 So you now have data_ and m.data_ pointing to the same memory, thus the memory leak and double-delete errors.所以你现在有data_m.data_指向同一个 memory,因此 memory 泄漏和双重删除错误。

The fix is to actually copy the data to the newly allocated memory.修复方法是将数据实际复制到新分配的 memory。

The other potential error, which is not easy to spot, is that you failed to initialize all of the data.另一个不容易发现的潜在错误是您未能初始化所有数据。 Even if we fixed this to do the copy, you are running into undefined behavior.即使我们修复了此问题以进行复制,您也会遇到未定义的行为。

Here is the fix to both of these problems:这是解决这两个问题的方法:

#include <algorithm>
//...
Matrix::Matrix(int rows, int cols): rows_ (rows), cols_ (cols)
{  
    if (rows == 0 || cols == 0)
        throw std::out_of_range("Matrix constructor has 0 size");
    data_ = new double[rows * cols](); // <-- Note the () to zero-initialize the data    
}

Matrix::Matrix(const Matrix& m) : rows_(m.rows_), cols_(m.cols_)
{
    data_ = new double[rows_ * cols_];
    std::copy_n(m.data_, m.rows_ * m.cols_, data_);
} 

There is one more error, and that is in the assignment operator.还有一个错误,那就是赋值运算符。 You are making the same mistake of erroneously using = to do copying, instead of the requisite function to do the copying of data between two buffers.您犯了同样的错误,即错误地使用=进行复制,而不是使用 function 在两个缓冲区之间复制数据。

Matrix& Matrix::operator=(const Matrix& m)
{     
    if(this != &m)
    {
        double* newdata_=new double[m.cols_*m.rows_];
        *newdata_=*data_; // <-- This does not copy the data
        //

The fix is similar to the fix that was done in the copy constructor using std::copy_n .该修复类似于使用std::copy_n在复制构造函数中完成的修复。 But it is so similar, that you can actually use the copy constructor to do all of this work instead of having duplicate code.但它是如此相似,以至于您实际上可以使用复制构造函数来完成所有这些工作,而不是使用重复的代码。 This technique of using the copy constructor within the assignment operator is called the copy / swap idiom .这种在赋值运算符中使用复制构造函数的技术称为复制/交换习惯用法

Matrix& Matrix::operator=(const Matrix& m)
{     
  if(this != &m)
  {
     Matrix temp(m);  // <-- Copy is made
     std::swap(temp.data_, data_);
     std::swap(temp.rows_, rows_);
     std::swap(temp.cols_, cols_);
  }      
  return *this;
}

Basically a copy is made, and then we just swap out the current object's data with the copy's data.基本上制作了一个副本,然后我们只需将当前对象的数据与副本的数据交换。 Then the copy dies off with the old data.然后副本与旧数据一起消失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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