抛出异常c ++后的内存泄漏

时间:2014-10-20 13:30:36

标签: c++ exception memory-leaks valgrind

#include <iostream>
#include <fstream>
#include <initializer_list>
#include <memory>

class OutOfMem { };
class IndexOutOfRange { };
class NoFile { };
class InvalidFileFormat { };
class WrongDim { };

class Array {
public:
    Array(double * arr, const unsigned c) : array(arr), columns(c) { }
    double &operator [] (const unsigned i) 
    { 
        if(i >= columns)
            throw IndexOutOfRange();
        return array[i];
    }
private:
    double * array = nullptr;
    unsigned columns;
};

class 2DArray {

public:
    2DArray(std::fstream &is)
    {
        if(!is)
            throw NoFile();
        if(!(is >> rows >> columns))
            throw InvalidFileFormat();
        matrix = new (std::nothrow) double *[rows];
        if(!matrix)
            throw OutOfMem();
        use = new (std::nothrow) std::size_t(1);
        if(!use)
            throw OutOfMem();
        for(unsigned i = 0; i < rows; i++)
        {
            matrix[i] = new(std::nothrow) double[columns];
            if(!matrix[i])
                throw OutOfMem();
        }
        for(unsigned i = 0; i < rows; i++)
            for(unsigned j = 0; j < columns; j++)
            {
                double temp;
                if(!(is >> temp))
                    throw WrongDim();
                matrix[i][j] = temp;
            }

    }
    ~2DArray() 
    {
        if(--*use == 0)
        {
            for(unsigned i = 0; i < rows; i++)
                delete [] matrix[i];
            delete [] matrix;
            delete use;
        }
    }
    Array operator [] (const unsigned i)
    {
        if(i >= rows)
            throw IndexOutOfRange();
        if(*use == 1)
            return Array(matrix[i], columns);
        else
        {
            double ** copy;
            copy = new (std::nothrow) double *[rows];
            for(unsigned i = 0 ; i < rows; i++)
            {
                copy[i] = new (std::nothrow) double[columns]();
                if(!copy[i])
                    throw OutOfMem();
                for(unsigned j = 0 ; j < columns; j++)
                    copy[i][j] = matrix[i][j];
            }
            --*use;
            matrix = copy;
            use = new std::size_t(1);
            return Array(matrix[i], columns);
        }
    }
private:
    unsigned rows;
    unsigned columns;
    double ** matrix = nullptr;
    std::size_t * use;
};

我遇到了用于从文件中读取矩阵的程序的问题,但在重新格式化文件时添加了错误的值,导致内存泄漏。应该调用析构函数,但不知何故,几个对象在抛出后仍然存在。有小费吗??  我使用valgrind进行内存检查。

2 个答案:

答案 0 :(得分:3)

想象一下,如果此行失败,2DArray(std::fstream &is)会发生什么:

use = new (std::nothrow) std::size_t(1);

您抛出OutOfMem异常,但不删除上面几行matrix分配的内存。你的代码中有很多这样的情况。

您有两种选择:

  1. 仔细检查正在分配的内容,捕获构造函数中的异常,删除所需内容并重新抛出异常。在这种情况下,一个有用的策略是首先将所有内容初始化为零,在异常处理程序中只需在所有指针上调用delete
  2. (更为可取)使用标准容器(例如std::vector)或至少智能指针(例如std::unique_ptr),这样可以免除手动清理内存的需要。
  3. 更新:我忘了指出对我来说显而易见的事情:如果构造函数抛出异常,则不会调用析构函数,因为没有构造对象。即使它被召唤,也要想想它会给你带来的灾难性后果。

答案 1 :(得分:3)

没有调用析构函数的原因很简单,因为如果在构造函数中抛出异常,则该对象被认为是未构造

感谢您的阅读。