C ++矩阵类 - 如何解释这个valgrind问题

时间:2017-01-06 15:01:43

标签: c++ matrix reference valgrind

我很困惑,因为我现在花了3天时间解决这个问题,试图弄清楚我做错了什么,但我真的不知道,所以任何提示或建议都不仅仅是值得赞赏的。基本上,我必须使用引用计数做矩阵类,并且程序运行良好,但在测试它时我意识到出现了问题。例如,我在main中写道:

matrix a(5,5,4); // - 5x5 matrix filled with 4
matrix b(3,3,2); //   3x3 matrix filled with 3
matrix c=b;      // copy constructor used here
a=b;

现在当我更改矩阵c中的值时,例如:

c(2,2)=1;

我预计矩阵b的参考计数器将减少1,程序将创建矩阵c 3x3,填充2但位置为1(2,2)。 我不知道为什么但程序会在所有矩阵中更改此值,并且因为我在valgrind中有一些内存泄漏。伙计们,你能告诉我,我做错了吗?

下面我附上所有重要的声明和valgrind错误。

#ifndef __CREFMATIRX_H__
#define __CREFMATRIX_H__
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

class matrix
{
  private:
    class rcmatrix;
    rcmatrix *data;

  public:
    class Cref;
    class Size_Check{};
    matrix();
    ~matrix();
    matrix(const matrix &m);
    matrix(const int rows, const int cols, const double num);
    matrix(const int rows, const int cols, double **arg_mat);
    void check(const int i, const int j)const;
    double read(int i, int j)const;
    void write(const int i, const int j, const double num);
    matrix & operator =(const matrix &m);
    Cref operator ()(const int i, const int j);
    friend ostream& operator<<(ostream &s, const matrix &m);
};

class matrix::rcmatrix
{
  private:
    rcmatrix(const rcmatrix&);
    rcmatrix &operator =(const rcmatrix&);

  public:
    int rows; //number of rows
    int cols; // number of columns
    double **mat; //pointer to matrix
    int n; //reference counter

  ~rcmatrix()
  {
     for(int i=0;i<rows;i++)
     delete []mat[i];
     delete []mat;
  }

  rcmatrix(const int r, const int c, const double num)
  {
     n=1;
     rows=r;
     cols=c;
     mat= new double *[rows];
     for(int i=0;i<rows;i++)
      mat[i]=new double[cols];           

     for(int k=0;k<rows;k++)
     {
       for(int j=0;j<cols;j++)
         mat[k][j]=num;
     }
  }

  rcmatrix(const int r, const int c, double **arg_mat)
  {
     n=1;
     rows=r;
     cols=c;

     mat=new double *[rows];
     for(int i=0; i<rows; i++)
        mat[i]=new double [cols];

     for(int j=0;j<rows;j++)
     {  
       for(int k=0;k<cols;k++)              
         mat[j][k]=arg_mat[j][k];
     }
      mat=arg_mat;   
   }

  rcmatrix* detach() //checking value of reference counter
   {
     if(n==1)
       return this;

     rcmatrix *t= new rcmatrix(rows,cols,mat);
     n--;
     return t;
   }
};

class matrix::Cref
{
  friend class matrix;
  matrix &m;
  int i,j;
  Cref(matrix &mm, const int ii, const int jj): m(mm),i(ii),j(jj){};

  public:
    operator double()const
    {
       return m.read(i,j);
    }
    matrix::Cref& operator = (double c)
    {
       m.write(i,j,c);
       return *this;
    }
    matrix::Cref& operator = (const Cref& ref)
    {
      return operator= ((double)ref);
    }   
};

matrix::matrix()
{
  data=new rcmatrix(0,0,0.0);
}

matrix::matrix(const matrix &m)
{
  m.data->n++;
  data=m.data;
}

matrix::~matrix()
{
  if(--data->n==0) //line 138
    delete data;
}

matrix::matrix(const int r, const int c, const double n)
{
   data=new rcmatrix(r,c,n);
}

matrix::matrix(const int r, const int c, double **arg_mat)
{
   data= new rcmatrix(r,c,arg_mat);
}

matrix& matrix::operator =(const matrix &m)
{
   m.data->n++;
   if(--data->n==0)
     delete data;
   data=m.data;
   return *this;
}

inline void matrix::check(const int i, const int j)const
{
   if(data->rows<i||data->cols<j)
      throw Size_Check();
}

inline double matrix::read( int i,  int j)const
{
   return data->mat[i][j];
}

inline void matrix::write( int i,  int j,const double num)
{   
   data=data->detach();
   data->mat[i][j]=num;
}

matrix::Cref matrix::operator ()(const int i, const int j)
{
   check(i,j);
   return Cref(*this,i,j);
}

ostream & operator <<(ostream &s, const matrix &m)
{
   for(int r=0; r<m.data->rows;r++)
   {
      for(int c=0; c<m.data->cols;c++)
          s<<m.data->mat[r][c]<<" ";
      s<<endl;
   }
 return s;
}

#endif /* __RCMATRIX__H__ */

Valgrind错误:

==2393== Invalid read of size 4
==2393==    at 0x8048E31: matrix::rcmatrix::~rcmatrix() (rcmatrix.h:50)
==2393==    by 0x8048A20: matrix::~matrix() (rcmatrix.h:138)
==2393==    by 0x8048D4E: main (crefmatrix.cpp:14)
==2393==  Address 0x43f6cd8 is 0 bytes inside a block of size 12 free'd
==2393==    at 0x402ECB8: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048E71: matrix::rcmatrix::~rcmatrix() (rcmatrix.h:51)
==2393==    by 0x8048A20: matrix::~matrix() (rcmatrix.h:138)
==2393==    by 0x8048D30: main (crefmatrix.cpp:16)
==2393==  Block was alloc'd at
==2393==    at 0x402DDAC: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048EC4: matrix::rcmatrix::rcmatrix(int, int, double) (rcmatrix.h:60)
==2393==    by 0x8048A6D: matrix::matrix(int, int, double) (rcmatrix.h:143)
==2393==    by 0x8048C6C: main (crefmatrix.cpp:15)
==2393== 
==2393== Invalid read of size 4
==2393==    at 0x8048E45: matrix::rcmatrix::~rcmatrix() (rcmatrix.h:50)
==2393==    by 0x8048A20: matrix::~matrix() (rcmatrix.h:138)
==2393==    by 0x8048D4E: main (crefmatrix.cpp:14)
==2393==  Address 0x43f6cd8 is 0 bytes inside a block of size 12 free'd
==2393==    at 0x402ECB8: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048E71: matrix::rcmatrix::~rcmatrix() (rcmatrix.h:51)
==2393==    by 0x8048A20: matrix::~matrix() (rcmatrix.h:138)
==2393==    by 0x8048D30: main (crefmatrix.cpp:16)
==2393==  Block was alloc'd at
==2393==    at 0x402DDAC: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048EC4: matrix::rcmatrix::rcmatrix(int, int, double) (rcmatrix.h:60)
==2393==    by 0x8048A6D: matrix::matrix(int, int, double) (rcmatrix.h:143)
==2393==    by 0x8048C6C: main (crefmatrix.cpp:15)
==2393== 
==2393== Invalid free() / delete / delete[] / realloc()
==2393==    at 0x402ECB8: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048E4F: matrix::rcmatrix::~rcmatrix() (rcmatrix.h:50)
==2393==    by 0x8048A20: matrix::~matrix() (rcmatrix.h:138)
==2393==    by 0x8048D4E: main (crefmatrix.cpp:14)
==2393==  Address 0x43f6d18 is 0 bytes inside a block of size 24 free'd
==2393==    at 0x402ECB8: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048E4F: matrix::rcmatrix::~rcmatrix() (rcmatrix.h:50)
==2393==    by 0x8048A20: matrix::~matrix() (rcmatrix.h:138)
==2393==    by 0x8048D30: main (crefmatrix.cpp:16)
==2393==  Block was alloc'd at
==2393==    at 0x402DDAC: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048F0F: matrix::rcmatrix::rcmatrix(int, int, double) (rcmatrix.h:62)
==2393==    by 0x8048A6D: matrix::matrix(int, int, double) (rcmatrix.h:143)
==2393==    by 0x8048C6C: main (crefmatrix.cpp:15)
==2393== 
==2393== Invalid free() / delete / delete[] / realloc()
==2393==    at 0x402ECB8: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048E71: matrix::rcmatrix::~rcmatrix() (rcmatrix.h:51)
==2393==    by 0x8048A20: matrix::~matrix() (rcmatrix.h:138)
==2393==    by 0x8048D4E: main (crefmatrix.cpp:14)
==2393==  Address 0x43f6cd8 is 0 bytes inside a block of size 12 free'd
==2393==    at 0x402ECB8: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048E71: matrix::rcmatrix::~rcmatrix() (rcmatrix.h:51)
==2393==    by 0x8048A20: matrix::~matrix() (rcmatrix.h:138)
==2393==    by 0x8048D30: main (crefmatrix.cpp:16)
==2393==  Block was alloc'd at
==2393==    at 0x402DDAC: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2393==    by 0x8048EC4: matrix::rcmatrix::rcmatrix(int, int, double) (rcmatrix.h:60)
==2393==    by 0x8048A6D: matrix::matrix(int, int, double) (rcmatrix.h:143)
==2393==    by 0x8048C6C: main (crefmatrix.cpp:15)
==2393== 
==2393== 
==2393== HEAP SUMMARY:
==2393==     in use at exit: 19,028 bytes in 5 blocks
==2393==   total heap usage: 19 allocs, 18 frees, 20,404 bytes allocated
==2393== 
==2393== LEAK SUMMARY:
==2393==    definitely lost: 12 bytes in 1 blocks
==2393==    indirectly lost: 72 bytes in 3 blocks
==2393==      possibly lost: 0 bytes in 0 blocks
==2393==    still reachable: 18,944 bytes in 1 blocks
==2393==         suppressed: 0 bytes in 0 blocks

1 个答案:

答案 0 :(得分:0)

一个明显的问题是rcmatrix的构造函数,如果引用计数不完全为1,则detach()函数中使用该构造函数。

 rcmatrix(const int r, const int c, double **arg_mat)
 {
     n=1;
     rows=r;
     cols=c;

     mat=new double *[rows];
     for(int i=0; i<rows; i++)
     mat[i]=new double [cols];

     for(int j=0;j<rows;j++)
     {  
         for(int k=0;k<cols;k++)              
         mat[j][k]=arg_mat[j][k];
     }
     mat=arg_mat;   
 }

此构造函数创建由另一个arg_mat管理的现有rcmatrix的新独立副本。但是,在最后一行中指定

mat=arg_mat;

这实质上导致了两个问题。

  1. arg_mat现在与新rcmatrix共享(您观察到分配给c(2,2)的值会写入所有矩阵)。
  2. 行中所述构造函数中分配的内存

     mat=new double *[rows];
     for(int i=0; i<rows; i++)
     mat[i]=new double [cols];
    

    失去了(valgrind)。

  3. 我不知道这些是您代码中的唯一问题。我想把支票留给你。