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

标签 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 进行内存检查。

最佳答案

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

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

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

你有两个选择:

  1. 仔细检查正在分配的内容,在构造函数中捕获异常,删除需要的内容并重新抛出异常。在这种情况下,一个有用的策略是首先将所有内容初始化为零,然后在异常处理程序中简单地对所有指针调用 delete
  2. (更可取)使用标准容器,例如 std::vector,或者至少使用像 std::unique_ptr 这样的智能指针,这将使您摆脱需要手动清理内存。

更新:我忘了指出对我来说显而易见的事情:如果从构造函数中抛出异常,则不会调用析构函数,因为未构造对象。即使调用了它,也要考虑它会给您的情况带来的灾难性后果。

关于c++ - 抛出异常c++后内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26466878/

相关文章:

c++ - 内存泄漏——每个程序员的恐惧?

c++ - 无法启用 Vulkan 时间线信号量扩展

c++ - 你如何设置 istream_iterator 不忽略空行

c# - 抛出的异常未在 UnitTest try/catch 中捕获

C# .net 对象引用未设置为静态类上的对象实例

c++ - 通过 C++ 异常保留函数时进入调试器?

c++ - 为什么这个 move 构造函数不起作用

c++ - 针对特定后端的 Boost.Locale 测试

Android - 出于测试目的将堆大小限制为 16MB?

无法解决此c程序中的内存管理(valgrind)