I'm writing program to work with different types of matrices such sparse matrices and other.
Now I have complete class of one matrix type called DOK and decided that I need an abstract class Matrix to be inherited in other child matrices and I will be able to apply all virtual operations
with different classes. So I made
Base class:
#include "Triplet.h"
#include <iostream>
using namespace std;
template<typename T>
class Matrix{
public:
virtual Matrix<T>& operator*=(const Matrix<T>& B) = 0;
virtual const Matrix<T>& operator*(const Matrix<T>& B) const = 0;
virtual Matrix<T>& operator-=(const Matrix<T>& B) = 0;
virtual const Matrix<T>& operator-(const Matrix<T>& B) const = 0;
virtual Matrix<T>& operator+=(const Matrix<T>& B) = 0;
virtual const Matrix<T>& operator+(const Matrix<T>& B) const = 0;
virtual T operator()(int i, int j) = 0;
virtual T operator()(int i, int j) const = 0;
[[nodiscard]] virtual int getSizeN() const = 0;
[[nodiscard]] virtual int getSizeM() const = 0;
[[maybe_unused]] virtual void insert(const Triplet<T> &Element) = 0;
[[maybe_unused]] virtual void print() const = 0;
};
template<typename T>
ostream& operator<<(ostream &os, const Matrix<T>& matrix) {
matrix.print();
return os;
}
Triplet.h is struct
template<typename T>
struct Triplet{
int i;
int j;
T b;
};
Tabs is
template<typename T>
T Tabs(T num){
if(num<T(0)) return -num;
else return num;
}
And child class DOK:
#include "Matrix.h"
#include <map>
#include <iostream>
#include <vector>
#include <iterator>
#include "Triplet.h"
//#include "Solver.h"
#include "Tabs.h"
#include "cmath"
#include "gnuplot-iostream.h"
#include <utility>
using namespace std;
template<typename T>
T tolerance = T(1e-19);
template<typename T>
class DOK: public Matrix<T>{
private:
/*
* Dictionary of Keys, pair<int, int> is coordinates of non-zero elements,
* next int is value
*/
int size_n;
int size_m;
map<pair<int, int>, T> dict;
// int count;
public:
DOK(vector<Triplet<T>> &matrix, int n, int m){
this->resize(n, m);
this->fill(matrix);
}
DOK(int n, int m){
this->resize(n, m);
}
~DOK() = default;
void fill(vector<Triplet<T>> &matrix){
//this->count=matrix.size();
//cout<<"Input your coordinates with value in format \"i j val\" "<<endl;
for(int k = 0; k < matrix.size(); k++){
this->insert(matrix[k]);
}
}
void insert(const Triplet<T> &Element) override{
if(Element.i >= this->size_n){
this->size_n = Element.i+1;
}
if(Element.j >= this->size_m){
this->size_m = Element.j+1;
}
pair<int, int> coordinates = {Element.i, Element.j};
this->dict.insert(pair(coordinates, Element.b));
}
void resize(int n, int m){
this->size_n=n;
this->size_m=m;
}
void print() const override {
cout<<endl;
for(int i = 0; i < this->size_n; i++){
for(int j = 0; j < this->size_m; j++){
if(this->dict.find({i, j})!= this->dict.cend()) cout<< fixed << setprecision(18)<<this->dict.find(pair(i, j))->second<<" "; else cout<<0<<" ";
}
cout<<endl;
}
}
void clearZeros(){
for(auto i = this->dict.begin(); i!=this->dict.end();){
if(Tabs(i->second) <= tolerance<T>){
i = this->dict.erase(i);
} else{
i++;
}
}
}
[[nodiscard]] int getSizeN() const override{
return this->size_n;
}
[[nodiscard]] int getSizeM() const override{
return this->size_m;
}
void clearZeros(){
for(auto i = this->dict.begin(); i!=this->dict.end();){
if(Tabs(i->second) <= tolerance<T>){
i = this->dict.erase(i);
} else{
i++;
}
}
}
DOK<T>& operator+=(const Matrix<T> &matrix) override {
try{
if(this->getSizeN() != matrix.getSizeN() || this->getSizeM() != matrix.getSizeM()) throw 1;
for(int i = 0; i < this->getSizeN(); i++) {
for (int j = 0; j < this->getSizeM(); j++) {
T c = this->operator()(i, j) + matrix(i, j);
if(Tabs(c) > tolerance<T>) this->insert({i, j, c}); else this->dict.erase({i, j});
}
}
return *this;
}
catch (int a) {
cout<<"Sizes of Matrices are different."<<endl;
}
}
const DOK<T>& operator+(const Matrix<T>& matrix) const override {
DOK<T> t = *this;
return move(t+=matrix);
}
DOK<T>& operator-=(const Matrix<T>& matrix) override {
try{
if(this->getSizeN() != matrix.getSizeN() || this->getSizeM() != matrix.getSizeM()) throw 1;
for(int i = 0; i < this->getSizeN(); i++) {
for (int j = 0; j < this->getSizeM(); j++) {
T c = this->operator()(i, j) - matrix(i, j);
if(Tabs(c) > tolerance<T>) this->insert({i, j, c}); else this->dict.erase({i, j});
}
}
return *this;
}
catch (int a) {
cout<<"Sizes of Matrices are different."<<endl;
}
}
const DOK<T>& operator-(const Matrix<T> &matrix) const override {
DOK<T> t = *this;
return move(t-=matrix);
}
DOK<T>& operator*=(const Matrix<T> &matrix) override {
try {
if(this->getSizeN() != matrix.getSizeN()) throw 1;
DOK<T> M = DOK(this->getSizeN(), matrix.getSizeM());
for (int i = 0; i < this->getSizeN(); i++) {
for (int j = 0; j < matrix.getSizeM(); j++) {
T a=0;
for(int k = 0; k<this->getSizeM(); k++){
if(this->operator()(i, k) != 0 && matrix(k, j) != 0){
a+=this->operator()(i, k)*matrix(k,j);
//cout<<a<<endl;
}
}
Triplet<T> m = {i, j, a};
M.insert(m);
}
}
this->clearZeros();
*this=M;
return *this;
}
catch (int a) {
cout<<"Wrong sizes of matrices to multiplication"<<endl;
}
}
const DOK<T>& operator*(const Matrix<T>& matrix) const override{
DOK<T> t = *this;
return t*=matrix;
}
T operator()(int row, int col) override{
if(this->dict.find({row, col}) != dict.end()) return this->dict.find({row, col})->second;
else return T(0);
}
T operator()(int row, int col) const override{
if(this->dict.find({row, col}) != dict.end()) return this->dict.find({row, col})->second;
else return T(0);
}
};
But I faced a problem that now I can't create DOK object because Matrix is an abstract class.
So if I did
DOK<double> Q = DOK<double>(...)
cout<<Q*Q;
and it was working
but now I can't do like this and one possible variant is to dereference pointer
Matrix<double>* Q = new DOK<double>(...);
cout<<(*Q) * (*Q);
How can I fix it without rewriting code from references to pointers?
Related
I am trying to merge two dynamic arrays but I am getting an error in my merge function that
"data': is not a member of 'List<T>"
I know that the error is ocuring because the given parameter in the merge(const List& other) is list but I am confused how to access my ArrayList2 which has been passed in merge function in the main
my code is:
#include <iostream>
using namespace std;
template<class T>
class List {
public:
// return the capacity of the list
virtual size_t capacity() const = 0;
// return the number of elements in the list
virtual size_t size() const = 0;
// inserts an element to the beginning
virtual void push_front(const T& value) = 0;
// adds an element to the end
virtual void push_back(const T& value) = 0;
// removes the last element
virtual void pop_back() = 0;
// removes the first element
virtual void pop_front() = 0;
// remove the first occurrence of an element with the given value
virtual void remove(const T& val) = 0;
// merges two sorted lists
virtual void merge(const List<T>& other) = 0;
virtual ~List() {}
};
template<class T>
class ArrayList : public List<T>
{
private:
T* data;
size_t max_capacity;
size_t num_of_element;
public:
ArrayList() = delete; // disable default constructor
// constructor
ArrayList(size_t capacity) : max_capacity(capacity), num_of_element(0) {
data = new T[capacity];
}
// copy constructor
ArrayList(const ArrayList<T>& other_list) : max_capacity(other_list.max_capacity),
num_of_element(other_list.num_of_element) {
data = new T[max_capacity];
for (size_t i = 0; i < other_list.num_of_element; i++) {
data[i] = other_list.data[i];
}
}
// destructor
virtual ~ArrayList() {
delete[]data;
}
size_t capacity() const override {
return max_capacity;
}
size_t size() const override {
return num_of_element;
}
T& operator[](int index) {
return data[index];
}
bool operator==(const ArrayList<T>& other_list) {
// not comparing capacity as eventually array list can be made capacity irrelevant using dynamic allocation
if (num_of_element != other_list.num_of_element) {
return false;
}
for (int i = 0; i < num_of_element; i++) {
if (data[i] != other_list.data[i]) {
return false;
}
}
return true;
}
void push_front(const T& value)
{
}
void push_back(const T& value)
{
if (max_capacity > num_of_element)
{
num_of_element++;
data[num_of_element - 1] = value;
}
}
void pop_back()
{
}
void pop_front()
{
}
void remove(const T& val)
{
int i = 0, j;
while (i < max_capacity)
{
if (data[i] == val)
{
for (int j = i; j < num_of_element-1; j++)
data[j] = data[j + 1];
if (data[i] == val && (i + 1) > num_of_element - 1)
{
data[i] = {};
num_of_element--;
break;
}
num_of_element--;
}
else
i++;
}
}
void merge(const List<T>& other)
{
int i;
int newsize = size() + other.size();
T* temp = new T[newsize];
for (i = 0; i < num_of_element; i++)
temp[i] = data[i];
for (int j = 0; j < other.size(); j++)
{
temp[i] = other.data[j]; //I am getting error on this line
i++;
}
}
private:
void shift_left_to(size_t start) {
for (size_t i = start; i < num_of_element - 1; i++) {
data[i] = data[i + 1];
}
}
};
int main() {
ArrayList<int> list1(3);
list1.push_back(3);
list1.push_back(1);
list1.push_back(1);
ArrayList<int> list2(2);
list2.push_back(1);
list2.push_back(8);
list1.merge(list2);
/* for (size_t i = 0; i < list1.size(); i++)
cout<<list1[i]<<" ";
cout<<"Size:"<<list1.size()<<" Capacity:"<<list1.capacity();*/
system("pause");
return 0;
}
Presumably, all of your concrete List<T> classes (e.g. ArrayList<T>) will have some kind of accessors to the elements. You can make those accessors part of the List<T> interface and call them in the implementation of void merge(List<T> const&). As an example:
template <class T>
class List {
public:
// ...
virtual T& operator[](int index) = 0;
virtual T const& operator[](int index) const = 0;
};
template <class T>
class ArrayList : public List<T> {
private:
T* data;
size_t max_capacity;
size_t num_of_element;
public:
// ...
T& operator[](int index) override { return data[index]; }
T const& operator[](int index) const override { return data[index]; }
// ...
void merge(const List<T>& other) {
int i;
int newsize = size() + other.size();
T* temp = new T[newsize];
for (i = 0; i < num_of_element; i++) temp[i] = data[i];
for (int j = 0; j < other.size(); j++) {
temp[i] = other[j]; // < Use your List<T>::operator[] here
i++;
}
}
// ...
};
I'd say the message is quite descriptive: List does not have a member called data. You should use the [] operator instead to access the list elements in the merge function. [] operator is implemented by descendants of List.
temp[i] = other[j]
I am trying to make a sorting function for a ring buffer class object, but it gives me the below error and I couldn't remove it:
template placeholder type 'ring' must be followed by a simple declarator-id
argument list for class template "ring" is missing
'arr' was not declared in this scope
(arr) was declared in the parameter of the function but yet it does not recognize it
hopefully someone can explain what is wrong with the sorting function, here is below my code:
#include<iostream>
#include<initializer_list>
template<typename T>
void swap(T& x, T& y) {
T temp;
temp = x;
x = y;
y = temp;
}
template<typename T>
class ring {
public:
class iterator;
public:
ring(std::initializer_list<T>elements) {
sze = elements.size();
value = new T[sze];
for (auto& i : elements) {
add(i);
}
}
T& get(int x) { return value[x]; }
std::size_t size() { return sze; }
void add(T v) {
value[index++] = v;
if (index == sze)
index = 0;
}
iterator begin() { return iterator(0, *this); }
iterator end() { return iterator(sze, *this); }
friend void BubbleSort(ring& arr, std::size_t n);
~ring() { delete[] value; }
private:
int index = 0;
std::size_t sze;
T* value;
};
template<typename T>
class ring<T>::iterator {
public:
iterator(int x, ring& y) :index(x), obj(y) {}
iterator& operator++() { index++; return *this; }
iterator& operator++(int x) { index++; return *this; }
bool operator!=(const iterator& other) { return index != other.index; }
T& operator*() { return obj.get(index); }
private:
int index;
ring& obj;
};
template<typename T>
void BubbleSort(ring& arr, std::size_t n) { // here is the function of the sorting.
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr.value[j] > arr.value[j + 1]) {
swap(arr.value[j], arr.value[j + 1]);
}
}
}
}
Your friendly compiler showed you already the problem and in which line it happened.
And it gave you 3 error messages telling you exactly what the problem is.
See my compiler output
Your class ring needs a template parameter. So same as in line 49 of the picture.
The below will compile.
#include<iostream>
#include<initializer_list>
template<typename T>
void swap(T& x, T& y) {
T temp;
temp = x;
x = y;
y = temp;
}
template<typename T>
class ring {
public:
class iterator;
public:
ring(std::initializer_list<T>elements) {
sze = elements.size();
value = new T[sze];
for (auto& i : elements) {
add(i);
}
}
T& get(int x) { return value[x]; }
std::size_t size() { return sze; }
void add(T v) {
value[index++] = v;
if (index == sze)
index = 0;
}
iterator begin() { return iterator(0, *this); }
iterator end() { return iterator(sze, *this); }
friend void BubbleSort(ring& arr, std::size_t n);
~ring() { delete[] value; }
private:
int index = 0;
std::size_t sze;
T* value;
};
template<typename T>
class ring<T>::iterator {
public:
iterator(int x, ring& y) :index(x), obj(y) {}
iterator& operator++() { index++; return *this; }
iterator& operator++(int x) { index++; return *this; }
bool operator!=(const iterator& other) { return index != other.index; }
T& operator*() { return obj.get(index); }
private:
int index;
ring& obj;
};
template<typename T>
void BubbleSort(ring<T>& arr, std::size_t n) { // here is the function of the sorting.
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr.value[j] > arr.value[j + 1]) {
swap(arr.value[j], arr.value[j + 1]);
}
}
}
}
I did not check the functionality. Sorting a ringbuffer sounds somehow strange . . .
this is the header of a class that I have been designing for an assignment. I have included constructors, a destructors, as well as overloaded operators. Could you give me a hint how to properly define the constructors in a class using c++ 20 most recent features in an efficient way.
#ifndef VECTOR_DOUBLE_H
#define VECTOR_DOUBLE_H
#include <memory>
#include <vector>
class vector_double {
public:
vector_double(int size);
vector_double(std::initializer_list<double> lst);
vector_double(const double* array, int size);
vector_double(const vector_doubler& other);
vector_doubleoperator=(const vector_double& other);
// because I use a managed pointer I don't need a destructor
~vector_double() noexcept = default;
void set(int index, double val);
double& get(int index);
const double& get(int index) const;
int size() const;
void reset(double val);
void fill_from(std::initializer_list<double> lst);
void fill_from(const double* array, int size);
int copy_to(std::vector<double>& vec) const;
double& operator[](int index);
const double& operator[](int index) const;
operator double() const;
vector_double add(const vector_double& other) const;
vector_doubleadd(double number) const;
vector_doublemul_by(double number) const;
void resize(int size);
friend std::ostream& operator<<(std::ostream& out, const vector_double& vec);
private:
std::unique_ptr<double[]> m_array;
int m_size;
};
inline std::ostream& operator<<(std::ostream& out, const vector_double& vec){
if (vec.m_size == 0){
out << "{ }";
}
else{
auto first = true;
out << '{';
for (int i=0; i < vec.m_size; ++i){
if (!first)
out << ", ";
else
first = !first;
out << vec.m_array[i];
}
out << '}';
}
return out;
}
#endif //VECTOR_DOUBLE_H
This example definition may help, I tried sticking to C++20 features:
#include <cmath>
#include "vector_double.h"
vector_double::vector_double(int size):
m_array{ new double[size] },
m_size{size}
{}
vector_double::vector_double(std::initializer_list<double> lst): //Constructor that takes an init list
vector_double(lst.size())
{
std::copy(lst.begin(), lst.end(), m_array.get());
}
vector_double::vector_double(const double* array, int size): //Constructor that takes array and size
vector_double(size)
{
// std::copy(array, array + size, m_array.get());
std::copy(&array[0], &array[size], m_array.get());
}
vector_double::vector_double(const vector_double& other): //Copy Constructor
vector_double(other.m_size)
{
std::copy(&other.m_array[0], &other.m_array[m_size], &m_array[0]);
}
vector_double& vector_double::operator=(const vector_double& other) {
if (this != &other) {
if (m_size != other.m_size) {
auto* array = new double[other.m_size];
m_array.reset(array);
m_size = other.m_size;
}
std::copy(&other.m_array[0], &other.m_array[m_size], &m_array[0]);
}
return *this;
}
void vector_double::set(int index, double val) {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
m_array[index] = val;
}
double& vector_double::get(int index) {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
return m_array[index];
}
const double& vector_double::get(int index) const {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
return m_array[index];
}
int vector_double::size() const {
return m_size;
}
void vector_double::reset(double val) {
for (int i=0; i<m_size; ++i){
m_array[i] = val;
}
}
void vector_double::fill_from(std::initializer_list<double> lst) {
int size = std::min((int)lst.size(), m_size);
std::copy(lst.begin(), lst.begin() + size, &m_array[0]);
}
void vector_double::fill_from(const double* array, int size) {
size = std::min(size, m_size);
for (int i = 0; i < size; ++i) {
m_array[i] = array[i];
}
}
int vector_double::copy_to(std::vector<double>& vec) const {
for (int i = 0; i < m_size; ++i) {
vec.push_back(m_array[i]);
}
return m_size;
}
double& vector_double::operator[](int index) {
return m_array[index];
}
const double& vector_double::operator[](int index) const { //Overloading "[]" operator
return m_array[index];
}
vector_double::operator double() const {
double sum = 0.0;
for (int i = 0; i < m_size; ++i) {
sum += m_array[i] * m_array[i];
}
return std::sqrt(sum);
}
vector_double vector_double::add(const vector_double& other) const {
if (m_size != other.m_size)
throw std::logic_error("size mismatch");
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] += other[i];
}
return copy;
}
vector_double vector_double::add(double number) const {
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] += number;
}
return copy;
}
vector_double vector_double::mul_by(double number) const {
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] *= number;
}
return copy;
}
void vector_double::resize(int size) {
if (size != m_size){
auto array = new double[size] {0,};
auto common = std::min(size,m_size);
for (int i = 0; i < common; ++i) {
array[i] = m_array[i];
}
m_array.reset(array);
m_size = size;
}
}
I got an exercise form my teacher (the main() function) and was supposed to write functions and classes so that it would work. But I have seg fault and have no idea what to do about it. I would be grateful for any recommendations.
#include <iostream>
class TSeries{
public:
TSeries()
{
_size = 0;
_capacity = 0;
_tab = NULL;
}
TSeries(float *tab, const int size)
{
_tab = new float[size];
for(int i =0;i<size;i++) _tab[i] = tab[i];
_size = size;
}
~TSeries(){delete [] _tab;}
TSeries & operator+=(float value){return insert(value);}
TSeries & operator,(float value){return insert(value);}
TSeries & operator+(const TSeries & s)
{
// if(this->_size != s._size) std::cout<<"Size doesn't match!"<<std::endl;
/*else
{
std::cout<<"whee";
for(int i; i<this->_size;i++)
{
//this->_tab[i] += s._tab[i];
std::cout<<"nothing";
}
return *this;
}*/
std::cout<<"sth";
}
TSeries & operator()(int position1, int position2){}
TSeries & insert(float k)
{
if(_size >= _capacity) Enlarge();
_tab[_size++] = k;
return *this;
}
friend std::ostream & operator<<(std::ostream & out, const TSeries & s);
private:
int _size, _capacity;
float *_tab, *_itr;
static int _nr;
void Enlarge()
{
_capacity = 2 * _capacity + 1;
float *tmp = new float[_capacity];
for( int i=0;i<_size;++i)
{
tmp[i] = _tab[i];
}
delete [] _tab;
_tab = tmp;
}
};
std::ostream & operator<<(std::ostream & out, const TSeries & s)
{
int przedostatni = s._size - 1;
out<<"(";
for(int i =0;i<s._size;i++)
{
out<<(int)s._tab[i];
if(i != przedostatni)
out<<",";
}
out<<")"<<std::endl;
}
using namespace std;
int main(int argc, char **argv) {
TSeries series1;
series1 += 1.,2.,4.,2.;
cout<<"Series1: "<<series1<<endl;
const int size=7;
float tab[size] = {3.,3.,3.,4.,5.,1.,0.};
const TSeries series2(tab,size);
cout<<"Series2: "<<series2<<endl<<endl;
TSeries series3 = series1+series2;
cout<<"Series3: "<<series3<<endl<<endl;
series1+=1.,0.,3.;
series3=series1+series2;
cout<<" "<<series1<<endl;
cout<<" +"<<series2<<endl;
cout<<" ---------------------"<<endl;
cout<<"Series3: "<<series3<<endl<<endl;
//TSeries series4=series1(2,4);
cout<<"Series4: "<<series3<<endl;
return 0;
}
You fixed one of your problems (the assignment to the _tab pointer).
The other problem should have caused a warning from the compiler.
You need to return out from your operator<< method.
Note that you also should use the out parameter, rather than always using cout in the the method.
After returning object from the method matrix matrix::operator+(const matrix& right), the whole array seems to be erased! Let's describe this strange problem on the following simplified example:
main.cpp:
#include "matrix.h"
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
matrix a("a.mt");
matrix b("b.mt");
matrix d(a.getRows(),a.getColumns());
d = a+b;
std::cout<<"hooray!";
return 0;
}
matrix.h:
#ifndef H_MATRIX
#define H_MATRIX
#include <string>
struct field
{
int row;
int column;
double value;
};
class matrix
{
private:
int c; //columns
int r; //rows
field** b; //2d array
void allocmem();
public:
matrix(int rows,int columns);
matrix(std::string filename);
~matrix();
void read(std::string fname);
matrix operator+(const matrix& right);
matrix& operator=(const matrix& right); //deep copy
int getColumns() const;
int getRows() const;
};
#endif
matrix.cpp
#include "matrix.h"
#include <string>
#include <fstream>
#include <iostream>
void matrix::allocmem()
{
b = new field*[r];
for(int i=0; i < r; i++)
b[i] = new field[c];
}
matrix::matrix(int rows,int columns)
{
c = columns;
r = rows;
allocmem();
}
matrix::matrix(std::string fName)
{
read(fName);
}
matrix::~matrix()
{
for(int i=0; i<r;i++)
delete [] b[i];
delete b;
}
void matrix::read(std::string fname) //load matrix from file
{
std::ifstream is;
is.open(fname);
is>>r>>c; //get matrix dimensions
allocmem();
//go to the first row
char dull = is.peek();
while(dull != '\n'){dull = is.get();}
for(int i=0;i<r;i++)
{
for(int j=0;j<c;j++)
{
is>>b[i][j].value;
b[i][j].row=i+1;
b[i][j].column=j+1;
}
while(dull != '\n'){dull = is.get();}
}
is.close();
}
matrix matrix::operator+(const matrix& right)
{
matrix rMatrix(right.getRows(),right.getColumns());
if((r != right.r) || (c != right.c))
{
return NULL;
}
rMatrix.r = r;
rMatrix.c = c;
//matrix addition algorithm
for(int i=0;i<r;i++)
for(int j=0;j<c;j++)
{
rMatrix.b[i][j].value = b[i][j].value+right.b[i][j].value;
rMatrix.b[i][j].row = i+1;
rMatrix.b[i][j].column = j+1;
}
return rMatrix;
}
matrix& matrix::operator=(const matrix& right)
{
if(this == &right)
return *this;
for(int i=0; i<r;i++)
delete [] b[i];
delete b;
r = right.getRows();
c = right.getColumns();
allocmem();
for(int i=0;i<r;i++)
for(int j=0;j<c;j++)
{
b[i][j].value = right.b[i][j].value; //RUN-TIME ERROR!
b[i][j].column = j+1;
b[i][j].row = i+1;
}
return *this;
}
int matrix::getColumns() const
{
return c;
}
int matrix::getRows() const
{
return r;
}
a.mt:
4 4
10.5 20.7 30.5 40.1
0 0 15.4 9.8
4 2 -8.3 4.2
9.3 2.7 1.2 8.9
b.mt:
4 4
-2.5 0.7 30.5 -54.1
0 1 0 9.8
4 7 8.3 4.2
7.3 2.7 -1.2 3.9
This program should load two matrices from file, and then calculate their sum. In practice, it crashes inside the deep copy method(operator =) throwing such error:.
I'd like to ask you where the bug is and how to fix it.
Try adding a copy constructor as well.
When you return the matrix from the operator+ it uses the copy constructor to initialize the result. The default will copy member by member the calls (including the pointers to the data).
Then you release the memory because the rMatrix is destroyed when you leave operator+ but you try to access it for the operator = in the context above.
Well, it appears you do not know how to handle dynamic memory in C++.
Nothing strange here, it is a tough problem, so you have 2 solutions:
Do not manipulate raw memory
Learn how to manipulate raw memory
Obviously, in the long term, learning how to manipulate raw memory is better... but the short term solution is:
std::vector<std::vector<field>> b;
Now, let us look at the long term.
Preface: do not reinvent the wheel, except for learning purposes
Obey the Single Responsibility Principle: either a class manages resources OR it has a business functionality, but not both
A resources-handling class must obey the Rule of Three (carefully write all of copy constructor, copy assignment operator and destructor) and must take special care of handling exceptions arising during those methods
So... let's go! The general architecture will be:
a resources class, handling memory (and that's all)
a business class, handling operations and relying on the resources class under the covers
A little nibbling first:
// No reason to have line and column there, is it ?
struct Field {
Field(): value() {} // initialize value on construction, please!
double value;
};
Start with the resources class:
// An array of N*M "Field" elements
// It is minimalist, but minimalist is good!
class FieldsArray {
public:
FieldsArray(size_t rows, size_t columns);
FieldsArray(FieldsArray const& other);
FieldsArray& operator=(FieldsArray const& other);
~FieldsArray();
void swap(FieldsArray& other);
Field& at(size_t i, size_t j);
Field const& at(size_t i, size_t j) const;
private:
void allocate(); // rows & columns must be set
void release(); // rows & columns must be set
size_t rows;
size_t columns;
Field** fields;
}; // class FieldsArray
inline void swap(FieldsArray& left, FieldsArray& right) {
left.swap(right);
} // swap
On to the definitions, where we realize that using a table of tables is inconvenient (would have been easier to just use ONE big N*M table).
FieldsArray::FieldsArray(size_t rows, size_t columns):
rows(rows), columns(columns)
{
this->allocate();
} // FieldsArray::FieldsArray
FieldsArray::FieldsArray(FieldsArray const& other):
rows(other.rows), columns(other.columns)
{
// Perform deep copy
this->allocate();
try {
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < columns; ++j) {
fields[i][j] = other.fields[i][j];
}
}
} catch(...) {
this->release();
throw; // rethrow
}
} // FieldsArray::FieldsArray
FieldsArray& FieldsArray::operator=(FieldsArray const& other) {
FieldsArray tmp(other);
this->swap(tmp);
return *tmp;
} // FieldsArray::operator=
FieldsArray::~FieldsArray() {
this->release();
} // FieldsArray::~FieldsArray
void FieldsArray::swap(FieldsArray& other) {
using std::swap;
swap(this->rows, other.rows);
swap(this->columns, other.columns);
swap(this->fields, other.fields);
} // FieldsArray::swap
Field& FieldsArray::at(size_t i, size_t j) {
assert(i < rows && "Wrong index!");
assert(j < columns && "Wrong index!");
return _fields[i][j];
} // FieldsArray::at
Field const& FieldsArray::at(size_t i, size_t j) const {
assert(i < rows && "Wrong index!");
assert(j < columns && "Wrong index!");
return _fields[i][j];
} // FieldsArray::at
void FieldsArray::allocate(size_t rows, size_t columns) {
fields = new Field*[rows];
try {
for (size_t i = 0; i < rows; ++i) { fields[i] = new Fields[columns]; }
} catch(...) {
this->release();
throw; // rethrow
}
} // FieldsArray::allocate
void FieldsArray::release() {
for (size_t i = 0; i < rows; ++i) { delete[] fields[i]; }
delete[] fields;
} // FieldsArray::release
Yeah, all of that just to get the equivalent of std::vector<Field> (of size N*M). I just hope I did not mess it up (Note: in C++11, std::unique_ptr<Field[]> would help greatly...)
And now, finally, we get to work on the core business:
class Matrix {
public:
Matrix(size_t rows, size_t columns): _data(rows, columns) {}
Field& at(size_t i, size_t j) { return _data.at(i, j); }
Field const& at(size_t i, size_t j) const { return _data.at(i, j); }
Matrix& operator+=(Matrix const& other);
private:
FieldsArray _data;
}; // class Matrix
inline Matrix operator+(Matrix const& left, Matrix const& right) {
Matrix result(left);
result += right;
return result;
} // operator+
And the definition of operator+=:
Matrix& Matrix::operator+=(Matrix const& other) {
assert(this->rows == other.rows && "Rows differ!");
assert(this->columns == other.columns && "Columns differ!");
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < columns; ++j) {
this->at(i, j) += other.at(i, j);
}
}
return *this;
} // Matrix::operator+=
I'll leave the implementation of other methods as an exercise for the reader ;)