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 ;)
Related
I've got two classes (structs) - Editor and Matrix. The matrix itself is working fine. But if I want to use Matrix via Editor, it's not working. I believe there is some problem with memory because I can't deallocate and even use matrix inside the Editor struct. I've tried to allocate the matrix dynamically, but then I couldn't use the addRow method.
Not really good with c++, but have to use those classes, can't use std::vector and stuff like that.
Editor definition:
struct Editor
{
private:
Matrix<std::string> data;
public:
Editor();
Editor(Matrix<std::string> oldData);
~Editor();
void addRow(std::string* row);
int getNumberOfRows();
int getNumberOfColumns();
};
Editor implementation:
using namespace std;
Editor::Editor()
{
}
Editor::Editor(Matrix<string> oldData)
{
data = oldData;
}
Editor::~Editor()
{
}
void Editor::addRow(std::string* row)
{
data.addRow(row);
}
int Editor::getNumberOfRows()
{
return this->data.getNumberOfRows();
}
int Editor::getNumberOfColumns()
{
return this->data.getNumberOfColumns();
}
Matrix definition:
template<typename T>
struct Matrix
{
private:
T** data;
int numberOfRows;
int numberOfColumns;
public:
Matrix(int numberOfRows, int numberOfColumns);
Matrix(const Matrix<T>& m);
~Matrix();
int getNumberOfRows();
int getNumberOfColumns();
T getItem(int indexRow, int indexColumn) const;
void addRow(T* newRow);
T** getData();
};
Matrix implementation:
template<typename T>
inline Matrix<T>::Matrix(int numberOfRows, int numberOfColumns)
{
this->numberOfColumns = numberOfColumns;
this->numberOfRows = numberOfRows;
this->data = new T * [numberOfRows];
for (int i = 0; i < this->numberOfRows; i++)
{
this->data[i] = new T[numberOfColumns];
}
}
template<typename T>
inline Matrix<T>::Matrix(const Matrix<T>& m)
{
numberOfRows = m.numberOfRows;
numberOfColumns = m.numberOfColumns;
if (m.data)
{
data = new T * [numberOfRows];
for (int i = 0; i < numberOfRows; i++)
data[i] = new T[numberOfColumns];
for (int i = 0; i < numberOfRows; i++)
{
for (int j = 0; j < numberOfColumns; j++)
{
data[i][j] = m.data[i][j];
}
}
}
}
template<typename T>
inline Matrix<T>::~Matrix()
{
for (int i = 0; i < this->numberOfRows; i++)
{
delete[] data[i];
}
delete[] data;
}
template<typename T>
inline int Matrix<T>::getNumberOfRows()
{
return this->numberOfRows;
}
template<typename T>
inline int Matrix<T>::getNumberOfColumns()
{
return this->numberOfColumns;
}
template<typename T>
inline T** Matrix<T>::getData()
{
return this->data;
}
template<typename T>
inline T Matrix<T>::getItem(int indexRow, int indexColumn) const
{
if (indexRow < 0 || indexRow > numberOfRows || indexColumn < 0 || indexColumn > numberOfColumns)
{
throw std::exception("not valid at least one of those indexes");
}
return this->data[indexRow][indexColumn];
}
template<typename T>
inline void Matrix<T>::addRow(T* newRow)
{
if (newRow == nullptr)
{
throw std::exception("not valid row");
}
T** newData = new T * [numberOfRows + 1];
for (int i = 0; i < numberOfRows + 1; i++)
{
newData[i] = new T[numberOfColumns];
for (int j = 0; j < numberOfColumns; j++)
{
if (i != this->numberOfRows)
{
newData[i][j] = data[i][j];
}
else {
newData[i][j] = newRow[j];
}
}
}
for (int i = 0; i < this->numberOfRows; i++)
{
delete[] this->data[i];
}
delete[] this->data;
this->data = newData;
this->numberOfRows++;
}
Main:
using namespace std;
int main()
{
Matrix<string> mt{1,1};
string* st = new string[3];
st[0] = "aa";
st[1] = "bb";
st[2] = "cc";
mt.addRow(st); // works
Editor ed{ mt };
ed.addRow(st); // doesn't work
return 0;
}
It crashes in xstring* on this:
_CONSTEXPR20_CONTAINER void _Copy_assign(const basic_string& _Right, false_type) {
_Pocca(_Getal(), _Right._Getal());
assign(_Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize);
}
with code:
Exception: Read access violation.
_Right – 0xDDDDDDDD.
EDIT:
Did cut most of the stuff from the project to just show the minimum. Anyway, the answer with semi-shallow copy was the right. Altho I thought
struct = struct;
calls for copy constructor. But it seems that it doesn't. I had to add operator= to somehow make it work properly.
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?
I'm building a class that has an array variable, but I need to give the dimensions in the constructor to make the variable.
Some like:
class Table {
int array[dim][dim];
Table(int dim) {
array[dim][dim]; //???
}
}
What can I do?
What you need is to allocate the array dynamically at runtime.
You could use new[]/delete[] to allocate/free the array manually:
class Table {
int **array;
int arrDim;
Table(int dim) : arrDim(dim) {
array = new int*[dim];
for(int i = 0; i < dim; ++i) {
array[i] = new int[dim];
}
}
~Table() {
for(int i = 0; i < arrDim; ++i) {
delete[] array[i];
}
delete[] array;
}
};
You would also need to manually implement an operator=, per the Rule of 3/5/0.
However, this issue is better handled using std::vector instead:
#include <vector>
class Table {
std::vector<std::vector<int>> array;
Table(int dim) : array(dim, std::vector<int>(dim)) {}
};
Or:
#include <vector>
class Table {
std::vector<std::vector<int>> array;
Table(int dim) {
array.resize(dim);
for(int i = 0; i < dim; ++i) {
array[i].resize(dim);
}
}
};
If you are worry about speed and memory then it is better to use single continuous memory buffer for 2d arrays. Something like this.
Live Code
#include <stdint.h>
#include <cassert>
#include <vector>
template <class T>
class array_2d
{
public:
template<typename U>
using ArrayT = std::vector<U>;
protected:
ArrayT<T> m_buffer;
uint32_t m_rows;
uint32_t m_columns;
inline uint32_t index(uint32_t row, uint32_t column) const {
assert(row >= 0 && row < m_rows && column >= 0 && column < m_columns);
return row*m_columns + column;
}
public:
array_2d(uint32_t rows, uint32_t columns) : m_rows(rows), m_columns(columns) { m_buffer.resize(rows*columns); }
array_2d(uint32_t rows, uint32_t columns, const T & elem) : m_rows(rows), m_columns(columns) { m_buffer.resize(rows*columns, elem); }
~array_2d() = default;
T &operator()(uint32_t row, uint32_t column) { return m_buffer[index(row, column)]; }
T &at(uint32_t row, uint32_t column) { return operator()(row, column); }
const T &operator()(uint32_t row, uint32_t column) const { return m_buffer[index(row, column)]; }
const T &at(uint32_t row, uint32_t column) const { return operator()(row, column); }
auto cbegin() const { return m_buffer.cbegin(); }
auto cend() const { return m_buffer.cend(); }
auto begin() { return m_buffer.begin(); }
auto end() { return m_buffer.end(); }
uint32_t size() const { return m_buffer.size(); }
};
I'm a beginner when it comes to C++ and have recently ran in to a very frustrating problem with my small program where I'm practicing operator overloading and templates.
I've created a template-class called SortedVector that can store instances of various types.
using namespace std;
template <class T, int size> class SortedVector {
public:
SortedVector();
bool add(const T& v);
T& median();
void sortArray();
void removeLarge(const T& v);
void print(ostream &os);
void compexch(T& x, T& y);
void sortArray(T* data, int s);
private:
T arr[size];
int arraySize;
};
template <class T, int size> SortedVector<T, size>::SortedVector() {
arraySize = 0;
for (int i = 0; i < size; i++) {
arr[i] = T();
}
}
template <class T, int size> bool SortedVector<T, size>::add(const T& v) {
if (arraySize > size - 1) {
cout << "Array is full!" << endl;
return false;
} else {
arr[arraySize] = v;
arraySize++;
sortArray(arr, arraySize);
}
return true;
}
template <class T, int size> void SortedVector<T, size>::sortArray(T* data, int s) {
for (int i = 0; i < s - 1; i++) {
for (int j = i + 1; j < s; j++) {
compexch(data[i], data[j]);
}
}
}
template <class T, int size > T & SortedVector<T, size>::median() {
}
template <class T, int size> void SortedVector<T, size>::removeLarge(const T & v) {
}
template <class T, int size> void SortedVector<T, size>::print(ostream & os) {
for (int i = 0; i < arraySize; i++) {
cout << arr[i] << endl;
}
}
template <class T, int size> inline void SortedVector<T, size>::compexch(T& x, T& y) {
if (y < x) {
T temp = x;
x = y;
y = temp;
}
}
It can store ints succesfully and it can also store Polygons (a custom made class created in a earlier assignment).
Polygon.h:
class Polygon {
public:
Polygon(Vertex vertexArray[], int size);
Polygon() : vertices(0), arraySize(0) {}
~Polygon() {delete[] vertices;}
void add(Vertex v);
float area();
int minx();
int maxx();
int miny();
int maxy();
int numVertices() const {return arraySize;}
friend ostream &operator << (ostream &output, const Polygon& polygon);
friend bool operator > (Polygon polygon1, Polygon polygon2);
friend bool operator < (Polygon polygon1, Polygon polygon2);
private:
int arraySize;
Vertex * vertices;
};
Polygon.cpp declaration:
using namespace std;
void Polygon::add(Vertex v) {
arraySize++;
Vertex * tempVertexes = new Vertex[arraySize];
for (int i = 0; i < arraySize; i++) {
if (i == arraySize - 1) {
tempVertexes[i] = v;
} else {
tempVertexes[i] = vertices[i];
}
}
delete [] vertices;
vertices = tempVertexes;
}
Polygon::Polygon(Vertex vertexArray[], int size) {
arraySize = size;
vertices = new Vertex[size];
for (int i = 0; i < size; i++) {
vertices[i] = vertexArray[i];
}
}
float Polygon::area() {
float area = 0.0f;
for (int i = 0; i < arraySize - 1; ++i) {
area += (vertices[i].getXposition() * vertices[i + 1].getYposition()) - (vertices[i + 1].getXposition() * vertices[i].getYposition());
}
area += (vertices[0].getYposition() * vertices[arraySize - 1].getXposition()) - (vertices[arraySize - 1].getYposition() * vertices[0].getXposition());
area = abs(area) *0.5;
return area;
}
ostream& operator<<(ostream &output, const Polygon& polygon) { //Kolla denna!
output << "{";
for (int i = 0; i < polygon.numVertices(); i++) {
output << "(" << polygon.vertices[i].getXposition() << "," << polygon.vertices[i].getYposition() << ")";
}
output << "}";
return output;
}
bool operator>(Polygon polygon1, Polygon polygon2) {
if (polygon1.area() > polygon2.area()) {
return true;
} else {
return false;
}
}
bool operator<(Polygon polygon1, Polygon polygon2) {
if (polygon1.area() < polygon2.area()) {
return true;
} else {
return false;
}
}
template <class T> inline void compexch(T& x, T& y) {
if (y < x) {
T temp = x;
x = y;
y = temp;
}
}
The code for the Vertex class:
class Vertex {
public:
Vertex() : y(0), x(0) {}
Vertex(int xPosition, int yPosition) : x(xPosition), y(yPosition) {}
~Vertex() {}
int getXposition() const {return x;}
int getYposition() const {return y;}
private:
int x;
int y;
};
The problem however is that the overloaded <<-operator seems print out the wrong values from the main-method:
int main() {
SortedVector<Polygon, 10> polygons;
SortedVector<int, 6> ints;
ints.add(3);
ints.add(1);
ints.add(6);
Vertex varr[10];
varr[0] = Vertex(0, 0);
varr[1] = Vertex(10, 0);
varr[2] = Vertex(5, 2);
varr[3] = Vertex(5, 5);
polygons.add(Polygon(varr, 4));
cout << "varr area:" << (Polygon(varr, 4)).area() << endl;
varr[0] = Vertex(0, 0);
varr[1] = Vertex(25, 8);
varr[2] = Vertex(10, 23);
polygons.add(Polygon(varr, 3));
cout << "var area (1):" << (Polygon(varr, 3)).area() << endl;
varr[0] = Vertex(0, 0);
varr[1] = Vertex(5, 0);
varr[2] = Vertex(5, 3);
varr[3] = Vertex(4, 8);
varr[4] = Vertex(2, 10);
polygons.add(Polygon(varr, 5));
cout << "var area (2):" << (Polygon(varr, 5)).area() << endl;
polygons.print(cout);
ints.print(cout);
cout << "MEDIAN: " << ints.median() << endl;
cout << "MEDIAN: " << polygons.median() << endl;
return 0;
}
The code that is printed is:
var area (1):247.5
var area (2):33.5
{(6029504,0)(5,0)(5,3)}
{(6029504,0)(5,0)(5,3)(4,8)}
{(6029504,0)(5,0)(5,3)(4,8)(2,10)}
1
3
6
MEDIAN: 1
MEDIAN: {(6029504,0)(5,0)(5,3)}
Firstly, the method prints out the same polygon but with varying sizes. Secondly, it points out the wrong getXPosition() for the first object in the array. Everything else (that is implemented, like the ints and the area) is correct tho. Why is this? Am I missing something important here or am I just completely of with my program?
If theres any more code needed I am happy to provide it.
Regards
Given the code you posted, the issues are clear as to what's wrong.
You're passing Polygon's by value here:
friend bool operator > (Polygon polygon1, Polygon polygon2);
friend bool operator < (Polygon polygon1, Polygon polygon2);
and you're copying and assigning values here in: compexch:
if (y < x) {
T temp = x; // copy constructor
x = y; // assignment
y = temp; // assigment
}
This means that copies will be made, and your Polygon class cannot be copied safely. You will have memory leaks and bugs when calling either of these functions.
You should implement the appropriate copy constructor and assignment operator, whose signatures are:
Polygon(const Polygon& rhs); // copy constructor
Polygon& operator=(const Polygon& rhs); // assignment operator
Both of these functions should be implemented. Please see the Rule of 3 for this information.
However, for operator < and operator >, you should pass references, not values to these functions:
friend bool operator > (Polygon& polygon1, Polygon& polygon2);
friend bool operator < (Polygon& polygon1, Polygon& polygon2);
Then the copy constructor and assignment operator are not brought into play, since the parameter type is a reference.
Let's try to implement the copy / assignment functions anyway, for completeness:
For example, the copy constructor can be implemented like this:
Polygon::Polygon(const Polygon& rhs) : vertices(new int[rhs.arraySize]),
arraySize(rhs.arraySize)
{
for (int i = 0; i < arraySize; ++i)
vertices[i] = rhs.vertices[i];
}
Then for the assignment operator, using the copy / swap idiom:
Polygon& operator=(const Polygon& rhs)
{
Polygon temp(rhs);
std::swap(temp.arraySize, arraySize);
std::swap(temp.vertices, vertices);
return *this;
}
Once you've implemented these function, plus the destructor that calls delete[], you should no longer have an issue with copying the objects.
Other issues:
In addition, you really should only overload < and ==, initially with their "full" implementation, and write the other relational operators with respect to these two operators.
Right now, you're making the classic mistake of writing one operator (operator >), and then trying to turn the logic "inside-out" when implementing operator <. What if the logic for operator > were more complex, and it took yeoman's work to figure out what is the "opposite of <"?
If you implemented ==, then operator > just becomes:
return !(polygon1 < polygon2) && !(polygon == polygon2); // <-- this can be further improved by implementing operator !=
I have a class that takes the in an array and its size. in the class I have an index operator "[]" that has been overloaded to pass in its contents to a class member function and return that function. It also checks if I am accessing contents out side of the array size.
this_type operator[] (int index)
{
assert (index > 0 && index<=len);
at(index);
return c_arr()[index];
}
I made a copy constructor for it
//constructor
my_array(this_type const arr[], int size)
{
len = size;
assert(arr != NULL);
assert(size >= 0);
this->arr = new this_type[size];
for (int i = 0; i < size; i++)
(*this).arr[i] = arr[i];
}
//copy constructor
my_array( const my_array<this_type> & arr)
{
this->arr = new this_type[sizeof(arr)];
memcpy(this->arr, arr.arr, sizeof(this_type)*arr.len);
}
my_array(int size)
{
len = size;
assert(size >= 0);
this->arr = new this_type[size];
}
But it does not seem to pass in the array size value when called to the member function "len". Any thoughts?
#include <iostream>
#include <cassert>
#include <assert.h>
using namespace std;
template <class this_type>
class my_array
{
private:
this_type *arr;
int len;
int sum()
{
int sum;
for (int i = 0; i < len; i++)
sum += arr[i];
}
public:
int size() const
{
return len;
}
this_type &at(int index)
{
assert( index >= 0 && index < len);
return arr[index];
}
my_array(this_type const arr[], int size)
{
len = size;
assert(arr != NULL);
assert(size >= 0);
this->arr = new this_type[size];
for (int i = 0; i < size; i++)
(*this).arr[i] = arr[i];
}
my_array( const my_array<this_type> & arr)
{
this->arr = new this_type[sizeof(arr)];
memcpy(this->arr, arr.arr, sizeof(this_type)*arr.len);
}
my_array(int size)
{
len = size;
assert(size >= 0);
this->arr = new this_type[size];
}
~my_array()
{
delete[] arr;
}
this_type* c_arr()
{
return arr;
}
this_type & operator[] (int index)
{
assert (index > 0 && index<=len);
at(index);
return c_arr()[index];
}
this_type operator[] (int index)
{
assert (index > 0 && index<=len);
at(index);
return c_arr()[index];
}
friend istream & operator>>(istream &lhs, my_array<this_type> &rhs);
friend ostream & operator<<(ostream &lhs, my_array<this_type> &rhs);
};
template <class this_type>
ostream & operator<<(ostream &lhs, my_array<this_type>&rhs)
{
for ( int i = 0; i < rhs.size(); i++)
lhs << rhs.arr[i] << endl;
return lhs;
}
template <class this_type>
istream & operator>>(istream &lhs, my_array<this_type> &rhs)
{
for ( int i = 0; i < rhs.size(); i++)
lhs >> rhs.arr[i];
return lhs;
}
int main()
{
char arra[5]={'c','o','d','e','s'};
my_array<char> arr(arra,5), arr1(5), arr2(arr);
for(int t=0;t< 9;t++)
{
//use the operator that is attached to the class instance
cout << arr2[t];
}
for(int t=0;t< 9;t++)
{
cout<<arr2.c_arr()[t];
}
return 0;
}
this->arr = new this_type[sizeof(arr)];
This line from your copy constructor is not correct. arr is an object of your my_array class. sizeof(arr) is a compile time constant, and completely independent of the number of elements allocated for the array. Those elements are not even contained in the class. They are on the free store, and the class holds a pointer to them. What you want instead is this:
this->arr = new this_type[arr.len];
You also want to assign to the len member of the object you are constructing.
this->len = arr.len;
I am obliged to say that, unless you are creating this class for learning purposes, just use std::vector.