简体   繁体   中英

memory leak in std::vector representing 2D data

I have written a simple templated Matrix class to use with my main application which is manipulating data matricies. The truncated Matrix code is:

template <typename T> 
class Matrix{
   private:
      std::vector<T> matrixRepresentation;
      bool transposed;
  public: 
  Matrix(int r, int c);
  int maxRows;
  int maxCols;
  void setMatrixValue(int row, int col, T val);
  T getMatrixValue(int row, int col);
};

template <typename T>
Matrix<T>::Matrix(int r, int c){
   maxRows = r;
   maxCols = c;
   matrixRepresentation.resize((r+1)*(c+1));
}   

template <typename T>
void Matrix<T>::setMatrixValue(int row, int col, T val){
   matrixRepresentation[row + col*maxCols] = val;
}

template <typename T>
T Matrix<T>::getMatrixValue(int row, int col){
   return matrixRepresentation[row + col*maxCols];
}

As you can see I am just representing a 2D matrix as a vector and giving wrapper methods to hide that fact. Even though I resize the stack variable matrixRepresentation to

(r+1)(c+1)

I end up with memory corruption problems later in the code and valgrind tells me the following:

==3753==    at 0x8049777: Matrix<int>::setMatrixValue(int, int, int) (in a.out)
==3753==    by 0x8049346: DataFile::readAllData() (ina.out)
==3753==    by 0x8049054: DataFile::DataFile(char const*) (in a.out)
==3753==    by 0x804C386: main (in a.out)
==3753==  Address 0x42cc970 is 0 bytes after a block of size 5,600 alloc'd
==3753==    at 0x4026351: operator new(unsigned int) (vg_replace_malloc.c:255)
==3753==    by 0x804A603: __gnu_cxx::new_allocator<int>::allocate(unsigned int, 
            void   const*) (in /a.out)
==3753==    by 0x8049F0D: std::_Vector_base<int, std::allocator<int> 
            >::_M_allocate(unsigned int) (in a.out)
==3753==    by 0x804A181: std::vector<int, std::allocator<int> 
            >::_M_fill_insert(__gnu_cxx::__normal_iterator<int*, std::vector<int, 
            std::allocator<int> > >, unsigned int, int const&) (in a.out)
==3753==    by 0x8049AEF: std::vector<int, std::allocator<int> 
            >::insert(__gnu_cxx::__normal_iterator<int*, std::vector<int, 
            std::allocator<int> > >, unsigned int, int const&) (in a.out)
==3753==    by 0x80499AB: std::vector<int, std::allocator<int> >::resize(unsigned int,
            int) (in a.out)
==3753==    by 0x8049709: Matrix<int>::Matrix(int, int) (in a.out)
==3753==    by 0x80492AD: DataFile::readAllData() (in a.out)
==3753==    by 0x8049054: DataFile::DataFile(char const*) (in a.out)
==3753==    by 0x804C386: main (in a.out)

The readAllData() method (the user of this matrix class) is simply reading from a text file and trying to populate the matrix

void DataFile::readAllData(){
   int currentValue;
   featureMatrix = new Matrix<int>((theHeader.totalNumSamples),
   (theHeader.numFeatures));

    if (infile.is_open()){
       if (!infile.eof()){
          for (int row=0; row < theHeader.totalNumSamples; row++){
            for (int col=0; col < theHeader.numFeatures; col++){
               infile >> currentValue;
               featureMatrix->setMatrixValue(row, col, currentValue);
             }
          }
       }
       else{
          cout << "EOF reached before we should have been done!  Closing file";
          infile.close();
       }
   }
   else cout << "File not open when attempting to read data";

   infile.close();
}

The header values are valid (eg theHeader.totalNumSamples = 15, theHeader.numFeatures = 100).

Please let me know if I can provide any more information, I could really use some help with this.

This snippet (which appears twice in your code):

 [row + col*maxCols]

Isn't correct. It should be [row * maxCols + col] or [col*maxRows + row]

And for that matter you don't need to allocate matrixRepresentation.resize((r+1)*(c+1)); you can allocate instead matrixRepresentation.resize(r*c);

You should do the math on the extreme cases (like access to element (maxRows-1,maxCols-1) to check this yourself for understanding purposes).

Does this solve your problem?

template <typename T>
Matrix<T>::Matrix(const int r, const int c) :
   maxRows(r),
   maxCols(c),
   matrixRepresentation((r+1)*(c+1))
{}

It might or might not solve it, but it is very much worth a try, if only to rule out trouble in the initialization of the Matrix .

Update: @ChrisA.'s answer is better. Try that first.

Not sure what Valgrind's specific issue is, but I found this:

maxRows = r;
maxCols = c;
matrixRepresentation.resize((r+1)*(c+1));

In your constructor then you are creating, say, a 3x3 matrix but are allocating 16 places, not 9. While this shouldn't be a problem necessarily, you're likely hiding other bugs by having this padding in place. My take would be to only allocate the space you need, and if you find yourself crashing or otherwise behaving badly, fix the issues therein instead of compensating for them in your Matrix implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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