Grundlegende Implementierung einer Ganzzahlmatrix
Ich muss eine CustomBasicMatrixKlassenimplementierung für das College schreiben . Dazu gehören grundlegende Operationen wie intund CustomBasicMatrixAddition und Subtraktion, Umsetzung und Iterationen / konst Iterationen .
Ich würde gerne wissen, ob es Codierungskonventionen oder, was noch wichtiger ist, Möglichkeiten für Speicherlecks / Segmentierungsfehler gibt .
Kontext:
- Die Implementierung muss in einen Namespace "sys" eingeschlossen werden.
- Die einzige externe Datei, die verwendet wird, ist "Auxiliaries.h", die Folgendes enthält: "Dimension" -Struktur enthält nur 'width' und 'height' mit zusätzlichen Hilfsfunktionen zum Drucken einer Matrix.
- Anstatt eine Funktion durch Umdrehen von Dimensionen zu transponieren, habe ich einen booleschen Wert gespeichert, der angibt, ob die Matrix transponiert ist. Wenn wir also den Wert abrufen, verwenden wir diesen booleschen Wert, um zu bestimmen, ob wir (i, j) oder (j, i) abrufen. Dies spart Speicher und Overhead.
Danke im Voraus!
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);
}
Bearbeiten: Zusatz-Header-Datei hinzugefügt. Es wird bereitgestellt, damit die CPP-Datei nicht verfügbar ist, und Sie können sie in der Überprüfung ignorieren
Auxiliaries.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;
}
}
Antworten
-
Anstatt eine Funktion durch Umdrehen von Dimensionen zu transponieren, habe ich einen booleschen Wert gespeichert, der angibt, ob die Matrix transponiert ist. Wenn wir also den Wert abrufen, verwenden wir diesen booleschen Wert, um zu bestimmen, ob wir (i, j) oder (j, i) abrufen. Dies spart Speicher und Overhead.
Dies erhöht leider nur den Overhead. Auf diese Weise haben Sie eine unnötige Verzweigung, wenn Sie einfach auf ein Element der Matrix zugreifen möchten, das den Code verlangsamt, und außerdem führt dies sicherlich zu einem schlechten Speicherzugriff, der den Code noch weiter verlangsamt.
Auch die Implementierung von Operationen wie +=ignoriert, ob die Matrizen transponiert sind. Und die einzige Möglichkeit, eine Matrix zu transponieren, ist ein Aufruf, transpose()der sowieso eine Kopie erstellt.
-
int** data;
Das ist nicht gut Sie nehmen für jedes Spaltenelement der Matrix eine Zuordnung vor, die zur Speicherfragmentierung beiträgt. Es ist vorzuziehen, das gesamte Datenarray als zusammenhängendes Datenelement zu speichern, dh int* data;Sie ermitteln über die Größe von, wo Spalten beginnen und enden row. Oder wickeln Sie besser einen vorhandenen Overhead-freien Smart-Zeiger ein, std::unique_ptr<int[]> data;und nebenbei müssen Sie nicht alles try/catchfür die Freigabe schreiben .
Warum kein Standardkonstruktor? Zumindest aktivieren. Außerdem besteht hier absolut keine Notwendigkeit, den Destruktor virtuell zu machen - dies ist für diese Klasse nicht erforderlich. Machen Sie Destruktoren für Klassen mit polymorphen Methoden virtuell.
-
int &operator()(int row, int col);int &operator()(int row, int col) const;
Ich glaube, Sie wollten, dass die constVersion entweder zurückkehrt intoder const int&nicht int&.
Die Klasse sollte einen Verschiebungskonstruktor und einen Verschiebungszuweisungsoperator haben. Dies ist für Speicherzwecke von entscheidender Bedeutung.
Was macht das
iteratorin der Matrix? Was iteriert es und in welcher Reihenfolge? Es ist nicht aus der Kopfzeile ersichtlich. Außerdemiteratorsollte das über Zeilen anstatt über Elemente der Matrix iterieren.
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);
Wollen Sie die Matrix wirklich so verwenden? Es sieht seltsam für mich aus. Ich könnte verstehen, wenn Sie so etwas für ein Bild wollten ... opencv verwendet es cv::Matsowohl für Matrizen als auch für Bilder, aber ich finde es keine gute Design-Wahl, alles über eine Klasse zu verpacken.
Alle Ihre Funktionsimplementierungen befinden sich in einer CPP-Datei. Es ist nicht gut. Funktionen können nicht eingefügt werden, wenn ihre Definition ausgeblendet ist. Sie sollten alle kleinen Funktionsdefinitionen in die Kopfzeile verschieben.
Ich glaube, die Hauptoperationen einer Dynamikbereichsmatrix sollten die Multiplikation mit dem Vektor und die Berechnung ihrer Inversen sein. Beides fehlt. Kein Wunder, wenn man bedenkt, dass Sie eine
intTypmatrix anstelle geeigneterer Typen für eine Matrix wiefloatund geschrieben habendouble.Ich bin sicher, Sie könnten ein paar einfache Funktionen wie
reserveoder schreibenresizeund sie einfach verwenden, anstatt das Zuordnungsverfahren zu kopieren und einzufügen. Durch die Zuweisung von Kopien werden nicht alle Daten gelöscht, auch wenn die Abmessungen übereinstimmen.Als Teil des allgemeinen Designs sind C ++ - Viewer derzeit sehr beliebt und werden empfohlen - Klassen, die keinen Speicher besitzen (nicht löschen oder zuweisen). Eine MatrixViewer-Klasse wäre sehr effizient beim Abschluss.