Implementação básica da matriz inteira
Eu preciso escrever uma CustomBasicMatriximplementação de classe para a faculdade. Isso inclui operações básicas como adição inte CustomBasicMatrixsubtração, transposição e iterações/constituições .
Gostaria de saber se existem convenções de codificação ou, mais importante, possibilidades de vazamento de memória / falhas de segmentação .
Contexto:
- A implementação deve ser agrupada em um namespace "sys".
- O único arquivo externo em uso é "Auxiliaries.h", que contém: struct "Dimensão", contém apenas 'largura' e 'altura', com funções auxiliares adicionais para imprimir uma matriz.
- Em vez de transpor uma função invertendo as dimensões, salvei um valor booleano que indica se a matriz é transposta, portanto, ao buscar o valor, usamos o dito booleano para determinar se buscamos (i,j) ou (j,i). Isso é para economizar memória e sobrecarga.
Desde já, obrigado!
CustomBasicMatrix .h:
#include <ostream>
#include "Auxiliaries.h"
namespace sys{
class CustomBasicMatrix{
private:
int rows;
int cols;
int** data;
bool trans = false;
public:
explicit CustomBasicMatrix(Dimensions dim, int initValue = 0);
CustomBasicMatrix(const CustomBasicMatrix& other);
virtual ~CustomBasicMatrix();
CustomBasicMatrix& operator=(const CustomBasicMatrix& other);
static CustomBasicMatrix Identity(int dims);
int height() const;
int width() const;
int size() const;
CustomBasicMatrix transpose() const;
CustomBasicMatrix operator-() const;
CustomBasicMatrix& operator+=(int scalar);
CustomBasicMatrix& operator+=(const CustomBasicMatrix& rhs);
int &operator()(int row, int col);
int &operator()(int row, int col) const;
class iterator{
private:
CustomBasicMatrix* matrix;
int row;
int col;
public:
iterator(CustomBasicMatrix* matrix, int row=0, int col=0);
virtual ~iterator() = default;
iterator& operator=(const iterator& other);
int& operator*();
iterator& operator++();
const iterator operator++(int);
bool operator==(const iterator& other) const;
bool operator!=(const iterator& other) const;
};
iterator begin();
iterator end();
class const_iterator{
private:
const CustomBasicMatrix* matrix;
int row;
int col;
public:
const_iterator(const CustomBasicMatrix *matrix, int row = 0, int col = 0);
virtual ~const_iterator() = default;
const_iterator& operator=(const const_iterator& other);
const int& operator*() const;
const_iterator operator++();
const const_iterator operator++(int);
bool operator==(const const_iterator& other) const;
bool operator!=(const const_iterator& other) const;
};
const_iterator begin() const;
const_iterator end() const;
};
bool any(const CustomBasicMatrix& mat);
bool all(const CustomBasicMatrix& mat);
CustomBasicMatrix operator+(const CustomBasicMatrix& lhs, const CustomBasicMatrix& rhs);
CustomBasicMatrix operator+(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator+(int scalar, const CustomBasicMatrix& matrix);
CustomBasicMatrix operator-(const CustomBasicMatrix &lhs, const CustomBasicMatrix &rhs);
CustomBasicMatrix operator<(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator<=(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator>(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator>=(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator!=(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator==(const CustomBasicMatrix& lhs, int scalar);
std::ostream &operator<<(std::ostream &os, const CustomBasicMatrix &matrix);
}
CustomBasicMatrix .cpp:
#include "CustomBasicMatrix.h"
#include "Auxiliaries.h"
#define CBM sys::CustomBasicMatrix
CBM::CustomBasicMatrix(sys::Dimensions dim, int initValue)
{
this->rows = dim.getRow();
this->cols = dim.getCol();
this->data = new int*[this->rows];
int i;
try{
for (i = 0; i < this->rows; ++i){
this->data[i] = new int[this->cols];
}
} catch(const std::exception& e){
for (int j = 0; j < i; ++j){
delete[] this->data[j];
}
delete[] this->data;
throw e;
}
for(int i=0; i< this->rows ; i++){
for (int j = 0; j < this->cols; ++j){
this->data[i][j] = initValue;
}
}
}
CBM::CustomBasicMatrix(const CBM &other)
{
this->rows = other.rows;
this->cols = other.cols;
this->trans = other.trans;
this->data = new int*[this->rows];
int i;
try{
for (i = 0; i < this->rows; ++i){
this->data[i] = new int[this->cols];
}
} catch(const std::exception& e){
for (int j = 0; j < i; ++j){
delete[] this->data[j];
}
delete[] this->data;
throw e;
}
for(int i=0; i< this->rows ; i++){
for (int j = 0; j < this->cols; ++j){
this->data[i][j] = other.data[i][j];
}
}
}
CBM::~CustomBasicMatrix()
{
for (int i = 0; i < this->rows; ++i){
delete[] this->data[i];
}
delete[] this->data;
}
CBM &CBM::operator=(const CBM &other)
{
if(this == &other) return *this;
for (int i = 0; i < this->rows; ++i){
delete[] this->data[i];
}
delete[] this->data;
this->rows = other.rows;
this->cols = other.cols;
this->trans = other.trans;
this->data = new int*[this->rows];
int i;
try{
for (i = 0; i < this->rows; ++i){
this->data[i] = new int[this->cols];
}
} catch(const std::exception& e){
for (int j = 0; j < i; ++j){
delete[] this->data[j];
}
delete[] this->data;
throw e;
}
for(int i=0; i< this->rows ; i++){
for (int j = 0; j < this->cols; ++j){
this->data[i][j] = other.data[i][j];
}
}
return *this;
}
CBM CBM::Identity(int dims)
{
Dimensions dim = Dimensions(dims, dims);
CustomBasicMatrix ret(dim, 0);
for (int i = 0; i < dims; ++i){
ret.data[i][i] = 1;
}
return ret;
}
int CBM::height() const
{
return this->trans ? this->cols : this->rows;
}
int CBM::width() const
{
return this->trans ? this->rows : this->cols;
}
int CBM::size() const
{
return this->rows * this->cols;
}
CBM CBM::transpose() const
{
CustomBasicMatrix ret(*this);
ret.trans = !ret.trans;
return ret;
}
CBM& CBM::operator+=(int scalar)
{
for (int i = 0; i < this->rows ; ++i){
for (int j = 0; j < this->cols ; ++j){
this->data[i][j] += scalar;
}
}
return *this;
}
CBM &CBM::operator+=(const CBM &rhs)
{
for (int i = 0; i < this->rows ; ++i){
for (int j = 0; j < this->cols ; ++j){
this->data[i][j] += rhs.data[i][j];
}
}
return *this;
}
CBM CBM::operator-() const
{
CustomBasicMatrix reg(*this);
for (int i = 0; i < reg.rows ; ++i){
for (int j = 0; j < reg.cols; ++j){
reg.data[i][j] = -reg.data[i][j];
}
}
return reg;
}
int &CBM::operator()(int row, int col)
{
if(this->trans)
return this->data[col][row];
else
return this->data[row][col];
}
int &CBM::operator()(int row, int col) const
{
if(this->trans)
return this->data[col][row];
else
return this->data[row][col];
}
CBM sys::operator+(const CBM &lhs, const CBM &rhs)
{
CBM temp(lhs);
return (temp += rhs);
}
CBM sys::operator+(const CBM &lhs, int scalar)
{
CBM temp = lhs;
return (temp += scalar);
}
CBM sys::operator-(const CBM &lhs, const CBM &rhs)
{
CBM temp = lhs;
return (temp += -rhs);
}
CBM sys::operator<(const CBM& lhs, int scalar)
{
CBM res(lhs);
for (int i = 0; i < res.height() ; ++i){
for (int j = 0; j < res.width(); ++j){
res(i,j) = res(i,j) < scalar;
}
}
return res;
}
CBM sys::operator<=(const CBM& lhs, int scalar)
{
CBM res1 = lhs == scalar;
CBM res2 = lhs < scalar;
return (res1 += res2);
}
CBM sys::operator>(const CBM& lhs, int scalar)
{
CBM res(lhs);
for (int i = 0; i < res.height() ; ++i){
for (int j = 0; j < res.width(); ++j){
res(i,j) = res(i,j) > scalar;
}
}
return res;
}
CBM sys::operator>=(const CBM& lhs, int scalar)
{
CBM res1 = lhs == scalar;
CBM res2 = lhs > scalar;
return res1 += res2;
}
CBM sys::operator!=(const CBM& lhs, int scalar)
{
CBM res1 = lhs > scalar;
CBM res2 = lhs < scalar;
return res1 += res2;
}
CBM sys::operator==(const CBM& lhs, int scalar)
{
CBM res(lhs);
for (int i = 0; i < res.height() ; ++i){
for (int j = 0; j < res.width(); ++j){
res(i,j) = res(i,j) == scalar;
}
} return res;
}
CBM sys::operator+(int scalar, const CBM &matrix)
{
return matrix + scalar;
}
CBM::iterator CBM::begin()
{
return iterator (this);
}
CBM::iterator CBM::end()
{
return iterator(this, this->rows, this->cols);
}
bool sys::any(const CBM &mat)
{
for (CBM::const_iterator it = mat.begin() ; it != mat.end() ; it++){
if((*it) != 0) return true;
}
return false;
}
bool sys::all(const CBM &mat)
{
for (CBM::const_iterator it = mat.begin() ; it != mat.end() ; it++){
if((*it) == 0) return false;
}
return true;
}
CBM::const_iterator CBM::begin() const
{
return const_iterator(this);
}
CBM::const_iterator CBM::end() const
{
return const_iterator(this, this->rows, this->cols);
}
std::ostream &sys::operator<<(std::ostream &os, const CBM &matrix)
{
int *vals = new int[matrix.size()];
for (int i = 0; i < matrix.height(); ++i){
for (int j = 0; j < matrix.width(); ++j){
vals[i * matrix.width() + j] = matrix(i,j);
}
}
Dimensions dim(matrix.height(), matrix.width());
std::string res = printMatrix(vals, dim);
delete[] vals;
return os << res;
}
/************************************/
CBM::iterator::iterator(CBM *matrix, int row, int col) : matrix(matrix), row(row), col(col){}
CBM::iterator &CBM::iterator::operator=(const iterator& other)
{
if(this == &other) return *this;
this->matrix = other.matrix;
this->row = other.row;
this->col = other.col;
return *this;
}
int &CBM::iterator::operator*()
{
return this->matrix->operator()(this->row, this->col);
}
CBM::iterator &CBM::iterator::operator++()
{
this->col++;
this->row += this->col / this->matrix->cols;
this->col = this->col % this->matrix->cols;
if(this->row == this->matrix->rows || this->col == this->matrix->cols){
this->row = this->matrix->rows;
this->col = this->matrix->cols;
}
return *this;
}
const CBM::iterator CBM::iterator::operator++(int)
{
iterator i = (*this);
++(*this);
return i;
}
bool CBM::iterator::operator==(const CBM::iterator &other) const
{
bool matrixEquals = (this->matrix) == (other.matrix);
bool colsEquals = this->col == other.col;
bool rowsEquals = this->row == other.row;
return matrixEquals && colsEquals && rowsEquals;
}
bool CBM::iterator::operator!=(const CBM::iterator &other) const
{
return !this->operator==(other);
}
/************************************/
CBM::const_iterator::const_iterator(const CustomBasicMatrix *matrix, int row, int col) : matrix(matrix), row(row), col(col){}
CBM::const_iterator &CBM::const_iterator::operator=(const CBM::const_iterator &other)
{
if(this == &other) return *this;
this->matrix = other.matrix;
this->row = other.row;
this->col = other.col;
return *this;
}
const int &CBM::const_iterator::operator*() const
{
return this->matrix->operator()(this->row, this->col);
}
CBM::const_iterator CBM::const_iterator::operator++()
{
this->col++;
this->row += this->col / this->matrix->cols;
this->col = this->col % this->matrix->cols;
if(this->row == this->matrix->rows || this->col == this->matrix->cols){
this->row = this->matrix->rows;
this->col = this->matrix->cols;
}
return *this;
}
const CBM::const_iterator CBM::const_iterator::operator++(int)
{
const_iterator i = (*this);
++(*this);
return i;
}
bool CBM::const_iterator::operator==(const CBM::const_iterator &other) const
{
bool matrixEquals = (this->matrix) == (other.matrix);
bool colsEquals = this->col == other.col;
bool rowsEquals = this->row == other.row;
return matrixEquals && colsEquals && rowsEquals;
}
bool CBM::const_iterator::operator!=(const CBM::const_iterator &other) const
{
return !this->operator==(other);
}
Editar: Adicionado arquivo de cabeçalho Auxiliaries. É fornecido para que o arquivo cpp não esteja disponível e você pode ignorá-lo na revisão
Auxiliares.h:
#include <iostream>
#include <string>
#include <cmath>
namespace sys {
typedef int units_t;
class Dimensions {
int row, col;
public:
Dimensions( int row_t, int col_t);
std::string toString() const;
bool operator==(const Dimensions& other) const;
bool operator!=(const Dimensions& other) const;
int getRow() const ;
int getCol() const ;
};
std::string printMatrix(const int* matrix,const Dimensions& dim);
template<class ITERATOR_T>
std::ostream& printMatrix(std::ostream& os,ITERATOR_T begin,
ITERATOR_T end, unsigned int width){
unsigned int row_counter=0;
for (ITERATOR_T it= begin; it !=end; ++it) {
if(row_counter==width){
row_counter=0;
os<< std::endl;
}
os <<*it<<" ";
row_counter++;
}
os<< std::endl;
return os;
}
}
Respostas
-
Em vez de transpor uma função invertendo as dimensões, salvei um valor booleano que indica se a matriz é transposta, portanto, ao buscar o valor, usamos o dito booleano para determinar se buscamos (i,j) ou (j,i). Isso é para economizar memória e sobrecarga.
Infelizmente, isso só aumenta a sobrecarga. Desta forma, você tem uma ramificação desnecessária sempre que alguém simplesmente deseja acessar um elemento da matriz, tornando o código mais lento e, além disso, certamente resultará em um acesso ruim à memória, tornando o código ainda mais lento.
Além disso, a implementação de operações como +=ignora se as matrizes são transpostas. E a única maneira de transpor uma matriz é chamar o transpose()que faz uma cópia de qualquer maneira.
-
int** data;
Isso não é bom. Você faz uma alocação para cada elemento da coluna da matriz - contribuindo para a fragmentação da memória. É preferível armazenar toda a matriz de dados como uma parte contígua de dados, ou seja, int* data;você descobre onde as colunas começam e terminam por meio do tamanho de row. Ou melhor, envolva um ponteiro inteligente livre de sobrecarga existente std::unique_ptr<int[]> data;e, como um aparte, você não precisará escrever todos os try/catchpara desalocação.
Por que nenhum construtor padrão? Pelo menos habilite. Também não há absolutamente nenhuma necessidade aqui de tornar o destruidor virtual - é desnecessário para esta classe. Torne os destruidores virtuais para classes que possuem métodos polimórficos.
-
int &operator()(int row, int col);int &operator()(int row, int col) const;
Eu acredito que você queria que a constversão retornasse intou const int&não int&.
A classe deve ter move construtor e mover operador de atribuição. Isso é crucial para fins de memória.
O que o
iteratorfaz na matriz? Sobre o que ele itera e em que ordem? Não está claro no cabeçalho. Além disso,iteratordeve-se iterar sobre linhas em vez de elementos da matriz.
CustomBasicMatrix operator<(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator<=(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator>(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator>=(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator!=(const CustomBasicMatrix& lhs, int scalar);
CustomBasicMatrix operator==(const CustomBasicMatrix& lhs, int scalar);
É realmente assim que você deseja usar a matriz? Parece estranho para mim. Eu poderia entender se você quisesse algo assim para uma imagem ... opencv usa isso cv::Matpara matrizes e imagens, mas não acho uma boa escolha de design agrupar tudo por meio de uma classe.
Todas as suas implementações de função estão no arquivo cpp. Isso não é bom. As funções não podem ser incorporadas se sua definição estiver oculta. Você deve mover todas as definições de funções pequenas para o cabeçalho.
Acredito que as operações primárias de uma matriz de intervalo dinâmico devem ser a multiplicação por vetor e o cálculo de seu inverso. Ambos estão faltando. Porém, não é surpreendente, considerando que você escreveu uma
intmatriz de tipos em vez de tipos mais adequados para uma matriz comofloatedouble.Tenho certeza de que você poderia escrever algumas funções simples como
reserveouresizee apenas usá-las em vez de copiar e colar o procedimento de alocação. Além disso, a atribuição de cópia excluirá todos os dados desnecessariamente, mesmo que as dimensões correspondam.Como parte do design geral agora em C++, os visualizadores são bastante populares e recomendados - classes que não possuem memória (não excluem ou alocam). Uma classe MatrixViewer seria muito eficiente para encerrar as coisas.