#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进行内存检查。
答案 0 :(得分:3)
想象一下,如果此行失败,2DArray(std::fstream &is)
会发生什么:
use = new (std::nothrow) std::size_t(1);
您抛出OutOfMem
异常,但不删除上面几行matrix
分配的内存。你的代码中有很多这样的情况。
您有两种选择:
delete
。std::vector
)或至少智能指针(例如std::unique_ptr
),这样可以免除手动清理内存的需要。更新:我忘了指出对我来说显而易见的事情:如果构造函数抛出异常,则不会调用析构函数,因为没有构造对象。即使它被召唤,也要想想它会给你带来的灾难性后果。
答案 1 :(得分:3)
没有调用析构函数的原因很简单,因为如果在构造函数中抛出异常,则该对象被认为是未构造。
感谢您的阅读。