矩阵模板,内存泄漏

时间:2014-11-07 15:22:22

标签: c++ templates matrix valgrind

我编写一个简单的程序,将复杂函数(z,exp(z),...)应用于pgm图像并返回结果。该计划正在运作,并做它应该做的事情。但是,有11个内存泄漏,我无法解决。我的猜测是麻烦在于矩阵模板容器I代码及其构造函数和析构函数。 要调试我正在使用valgrind并且该程序是用c ++编写的。

运行valgrind的结果如下:

==7690== Memcheck, a memory error detector
==7690== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7690== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==7690== Command: ./tp0 -i f14.pgm -f z -o ff14.pgm
==7690== 
==7690== 
==7690== HEAP SUMMARY:
==7690==     in use at exit: 160 bytes in 11 blocks
==7690==   total heap usage: 45 allocs, 34 frees, 18,357 bytes allocated
==7690== 
==7690== 8 bytes in 1 blocks are still reachable in loss record 1 of 11
==7690==    at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690==    by 0x404871: Matrix<Pixel>::Matrix(unsigned int, unsigned int) (matrix.hpp:44)
==7690==    by 0x404471: PGMImage::PGMImage(unsigned int, unsigned int) (pgm_image.cpp:14)
==7690==    by 0x405475: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690==    by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690==    by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690==    by 0x404212: main (main.cpp:52)
==7690== 
==7690== 8 bytes in 1 blocks are still reachable in loss record 2 of 11
==7690==    at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690==    by 0x403703: Matrix<Complex>::Matrix(unsigned int, unsigned int) (matrix.hpp:44)
==7690==    by 0x4024A5: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:49)
==7690==    by 0x404240: main (main.cpp:55)
==7690== 
==7690== 8 bytes in 1 blocks are still reachable in loss record 3 of 11
==7690==    at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690==    by 0x4049C9: Matrix<Pixel>::Matrix(Matrix<Pixel> const&) (matrix.hpp:56)
==7690==    by 0x404579: PGMImage::PGMImage(PGMImage const&) (pgm_image.cpp:31)
==7690==    by 0x4024DD: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690==    by 0x404240: main (main.cpp:55)
==7690== 
==7690== 12 bytes in 1 blocks are still reachable in loss record 4 of 11
==7690==    at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690==    by 0x4048B4: Matrix<Pixel>::Matrix(unsigned int, unsigned int) (matrix.hpp:46)
==7690==    by 0x404471: PGMImage::PGMImage(unsigned int, unsigned int) (pgm_image.cpp:14)
==7690==    by 0x405475: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690==    by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690==    by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690==    by 0x404212: main (main.cpp:52)
==7690== 
==7690== 12 bytes in 1 blocks are still reachable in loss record 5 of 11
==7690==    at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690==    by 0x404A15: Matrix<Pixel>::Matrix(Matrix<Pixel> const&) (matrix.hpp:59)
==7690==    by 0x404579: PGMImage::PGMImage(PGMImage const&) (pgm_image.cpp:31)
==7690==    by 0x4024DD: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690==    by 0x404240: main (main.cpp:55)
==7690== 
==7690== 16 bytes in 1 blocks are still reachable in loss record 6 of 11
==7690==    at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690==    by 0x40445E: PGMImage::PGMImage(unsigned int, unsigned int) (pgm_image.cpp:14)
==7690==    by 0x405475: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690==    by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690==    by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690==    by 0x404212: main (main.cpp:52)
==7690== 
==7690== 16 bytes in 1 blocks are still reachable in loss record 7 of 11
==7690==    at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690==    by 0x40248A: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:49)
==7690==    by 0x404240: main (main.cpp:55)
==7690== 
==7690== 16 bytes in 1 blocks are still reachable in loss record 8 of 11
==7690==    at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690==    by 0x403740: Matrix<Complex>::Matrix(unsigned int, unsigned int) (matrix.hpp:46)
==7690==    by 0x4024A5: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:49)
==7690==    by 0x404240: main (main.cpp:55)
==7690== 
==7690== 16 bytes in 1 blocks are still reachable in loss record 9 of 11
==7690==    at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690==    by 0x404564: PGMImage::PGMImage(PGMImage const&) (pgm_image.cpp:31)
==7690==    by 0x4024DD: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690==    by 0x404240: main (main.cpp:55)
==7690== 
==7690== 24 bytes in 1 blocks are still reachable in loss record 10 of 11
==7690==    at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690==    by 0x405464: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690==    by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690==    by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690==    by 0x404212: main (main.cpp:52)
==7690== 
==7690== 24 bytes in 1 blocks are still reachable in loss record 11 of 11
==7690==    at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690==    by 0x4024CB: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690==    by 0x404240: main (main.cpp:55)
==7690== 
==7690== LEAK SUMMARY:
==7690==    definitely lost: 0 bytes in 0 blocks
==7690==    indirectly lost: 0 bytes in 0 blocks
==7690==      possibly lost: 0 bytes in 0 blocks
==7690==    still reachable: 160 bytes in 11 blocks
==7690==         suppressed: 0 bytes in 0 blocks
==7690== 
==7690== For counts of detected and suppressed errors, rerun with: -v
==7690== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

我认为代码部分崩溃的矩阵模板如下:

template<typename T>
class Matrix
{
    private:
        T** matrix_;
        unsigned int rows_;
        unsigned int cols_;

    public:
        Matrix();
        Matrix(unsigned int, unsigned int);
        Matrix(Matrix const &);
        ~Matrix();
        Matrix const &operator=(Matrix const &);

//more methods...
};

template<typename T>
Matrix<T>::Matrix()
: matrix_(0), rows_(0), cols_(0) {}

template<typename T>
Matrix<T>::Matrix(unsigned int rows, unsigned int cols)
{
    matrix_ = new T*[rows];
    for(unsigned int i=0; i < rows; i++)
        matrix_[i] = new T[cols];
    rows_ = rows;
    cols_ = cols;
}

template<typename T>
Matrix<T>::Matrix(Matrix<T> const & m_orig)
{
    rows_ = m_orig.rows_;
    cols_ = m_orig.cols_;
    matrix_ = new T*[rows_];
    for(unsigned int i=0; i < rows_; i++)
    {
        matrix_[i] = new T[cols_];
        for(unsigned int j=0; j < cols_; j++)
            matrix_[i][j]=m_orig.matrix_[i][j];
    }
}

template<typename T>
Matrix<T>::~Matrix()
{
    for(unsigned int i=0; i < rows_; i++)
        delete matrix_[i];
    delete []matrix_;
    rows_ = 0;
    cols_ = 0;
}

template<typename T>
Matrix<T> const & Matrix<T>::operator=(Matrix const & m_orig)
{
    if(this != &m_orig)
    {
            for(unsigned int k=0; k < rows_; k++)
                delete matrix_[k];
            delete matrix_;
        rows_ = m_orig.rows_;
        cols_ = m_orig.cols_;
        matrix_ = new T*[rows_];
        for(unsigned int i=0; i < rows_; i++)
        {
            matrix_[i] = new T[cols_];
            for(unsigned int j=0; j < cols_; j++)
                matrix_[i][j]=m_orig.matrix_[i][j];
        }
    }
    return *this;
}

还有其他类可能会失败,但valgrind几乎会跟踪每个到矩阵容器的泄漏。 非常感谢您的帮助!

2 个答案:

答案 0 :(得分:4)

你应该遵循相同的&#34;模式&#34;使用delete进行取消分配与使用new分配进行

for(unsigned int i=0; i < rows_; i++)
        delete [] matrix_[i];
            // ~~   notice []
delete []matrix_;

答案 1 :(得分:3)

您的赋值运算符不是异常安全的,并且无法使用正确版本的delete:它使用delete matrix_而不是delete[] matrix_释放内存。鉴于目前的实施情况,您最好 更好地替换此版本:

template <typename T>
Matrix<T> const& Matrix<T>::operator= (Matrix<T> orig) {
    this->swap(orig);
    return *this;
}
template <typename T>
void Matrix<T>::swap(Matrix<T>& other) {
    using std::swap;
    swap(this->matrix_, other.matrix_);
}

除了解决上面提到的内存问题之外,它还使得实现强大的异常安全。当然,这样做假定复制构造函数,析构函数和swap()正确实现,因为它们被用来实现这个赋值运算符:

  1. 原创的副本用于创建参数(可以省略:因为无论如何都要通过值而不是const&来获取副本可以减少副本数量。)
  2. 交换左侧的参数,使左侧与原始参数相同,而参数现在包含准备释放的原始左侧状态。
  3. 论证被破坏,释放了原来的左手边状态。
  4. 析构函数也不正确:它使用delete matrix_[k]而不是delete[] matrix_[k]。传统上,对象以相反的构造顺序被破坏,而您的代码以相反的顺序销毁对象。我建议使用std::vector<std::vector<T>>来维护Matrix<T>内的数据。