#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
分配的内存。您的代码中有很多这样的情况。
你有两个选择:
- 仔细检查正在分配的内容,在构造函数中捕获异常,删除需要的内容并重新抛出异常。在这种情况下,一个有用的策略是首先将所有内容初始化为零,然后在异常处理程序中简单地对所有指针调用
delete
。 - (更可取)使用标准容器,例如
std::vector
,或者至少使用像std::unique_ptr
这样的智能指针,这将使您摆脱需要手动清理内存。
更新:我忘了指出对我来说显而易见的事情:如果从构造函数中抛出异常,则不会调用析构函数,因为未构造对象。即使调用了它,也要考虑它会给您的情况带来的灾难性后果。
关于c++ - 抛出异常c++后内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26466878/