For the following mymatrix class definition, why don't I need the commented parts of the destructor? Don't we need to delete what the a pointer points to as well? Or is it because we deleted all the meaningful data that we don't need these (commented-out) parts of the destructor?
template<typename T>
class mymatrix
{
private:
struct ROW
{
T* Cols; // dynamic array of column elements
int NumCols; // total # of columns (0..NumCols-1)
};
ROW* Rows; // dynamic array of ROWs
int NumRows; // total # of rows (0..NumRows-1)
}
Destructor:
virtual ~mymatrix()
{
for(int r=0;r<numRows;r++)
{
for(int c=0;c<Rows[r].NumCols;c++)
{
delete Rows[r].Cols[c];
}
// delete Rows[r];
}
// delete Rows;
}
Constructor:
mymatrix(int R, int C)
{
if (R < 1)
throw invalid_argument("mymatrix::constructor: # of rows");
if (C < 1)
throw invalid_argument("mymatrix::constructor: # of cols");
Rows = new ROW[R]; // an array with R ROW structs:
NumRows = R;
//intialize each row to C columns
for(int r=0;r<R;r++){
Rows[r].Cols=new T[C];
Rows[r].NumCols=C;
//initialize elements to their default value
for(int c=0;c<Rows[r].NumCols;c++){
Rows[r].Cols[c]=T{}; // default value for type T;
}
}
}
You need to use array-delete syntax because you are deleting arrays, not single objects:
delete[] Rows[r].Cols
...
delete[] Rows
Edit: I originally simply included the correct delete[] operator usage and left everything unchanged in my original example for brevity, but as #idclev463035818 pointed out, whenever you define your own destructor, copy constructor, or copy assignment operator (especially when they involve dynamic memory allocation), you almost always need to have all three. Almost never do you want any one without the others because if you have raw pointers in your object, then they will be shallow-copied to the new objects being instantiated. Then later on, the destructors for each of these objects will be called and attempt to delete the same portions of memory multiple times, which is a major error. I've added these to the code example and make use of them in new tests in the main function.
Full code:
#include <iostream>
using namespace std;
template<typename T>
class mymatrix
{
public:
struct ROW
{
T* Cols; // dynamic array of column elements
int NumCols; // total # of columns (0..NumCols-1)
};
ROW* Rows; // dynamic array of ROWs
int NumRows; // total # of rows (0..NumRows-1)
public:
mymatrix(int R, int C)
{
init(R, C);
}
void init(int R, int C) {
if (R < 1)
throw "";//throw invalid_argument("mymatrix::constructor: # of rows");
if (C < 1)
throw "";//invalid_argument("mymatrix::constructor: # of cols");
Rows = new ROW[R]; // an array with R ROW structs:
NumRows = R;
//intialize each row to C columns
for (int r = 0; r < R; r++) {
Rows[r].Cols = new T[C];
Rows[r].NumCols = C;
//initialize elements to their default value
for (int c = 0; c < Rows[r].NumCols; c++) {
Rows[r].Cols[c] = T{}; // default value for type T;
}
}
}
mymatrix(const mymatrix& other) : mymatrix(other.NumRows, other.Rows[0].NumCols) {
for (int r = 0; r < NumRows; ++r) {
ROW& thisRow = Rows[r];
ROW& otherRow = other.Rows[r];
for (int c = 0; c < thisRow.NumCols; ++c) {
thisRow.Cols[c] = otherRow.Cols[c];
}
}
}
mymatrix& operator=(const mymatrix& other) {
if (other.NumRows != NumRows || other.Rows[0].NumCols != Rows[0].NumCols) {
clear();
init(other.NumRows, other.Rows[0].NumCols);
}
for (int r = 0; r < NumRows; ++r) {
ROW& thisRow = Rows[r];
ROW& otherRow = other.Rows[r];
for (int c = 0; c < thisRow.NumCols; ++c) {
thisRow.Cols[c] = otherRow.Cols[c];
}
}
return *this;
}
void clear() {
for (int r = 0; r < NumRows; r++)
{
delete[] Rows[r].Cols;
}
delete[] Rows;
Rows = NULL;
NumRows = 0;
}
virtual ~mymatrix()
{
clear();
}
};
int main() {
mymatrix<int> mat(5, 5);
mat.Rows[0].Cols[2] = 5;
mymatrix<int> matClone(mat);
cout << matClone.Rows[0].Cols[2] << endl;
matClone.Rows[0].Cols[1] = 8;
cout << mat.Rows[0].Cols[1] << endl;
mat = matClone;
cout << mat.Rows[0].Cols[1] << endl;
system("pause");
return 0;
}
I'm telling this every time I see the usage of new/delete in C++.
Please don't use new/delete in C++!
Here is a minimal example of how to create a matrix which will allocate and delete itself without any manual memory allocations.
#include <vector>
class Matrix : public std::vector<std::vector<int>> {
public:
Matrix(size_t numRows, size_t numCols)
: std::vector<std::vector<int>>(numRows, std::vector<int>(numCols, 0)) {}
size_t numRows() const { return size(); }
size_t numCols() const { return front().size(); }
};
int main() {
auto m = Matrix(5, 4);
return m[4][3];
}
Related
I have a matrix class with fields like this:
template <typename T>
class Matrix
{
private:
T **matrix = nullptr;
int rows;
int cols;
At this stage, I have written an assignment operator and a copy constructor. But firstly, there is code duplication, how can it be avoided, and secondly, they seem very similar to me, how can these methods be improved to look normal?
Matrix(const Matrix &matrix_) : rows(matrix_.rows), cols(matrix_.cols)
{
matrix = static_cast<T **>(new T *[rows]);
for (int i = 0; i < rows; i++)
{
matrix[i] = static_cast<T *>(new T[cols]);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
matrix[i][j] = matrix_[i][j];
}
}
}
Matrix &operator=(const Matrix &matrix_)
{
if (&matrix == this)
{
return *this;
}
clean();
rows = matrix_.rows;
cols = matrix_.cols;
matrix = static_cast<T **>(new T *[rows]);
for (int i = 0; i < rows; i++)
{
matrix[i] = static_cast<T *>(new T[cols]);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
matrix[i][j] = matrix_[i][j];
}
}
}
void clean()
{
if (cols > 0)
{
for (int i = 0; i < rows; i++)
{
delete[] matrix[i];
}
}
if (rows > 0)
{
delete[] matrix;
}
}
According to the condition of the assignment, it is forbidden to use STL containers, I must implement the controls myself
Added move semantics
Matrix(Matrix &&other) noexcept : rows(std::move(other.rows)), cols(std::move(other.cols)), data(new T(rows * cols))
{
other.data = nullptr;
rows = 0;
cols = 0;
}
Matrix &operator=(Matrix &&other) noexcept
{
if (&other == this)
{
return *this;
}
if (rows != other.rows && cols != other.cols)
{
std::cout << "Error assigning matrices of different sizes" << std::endl;
exit(-1);
}
clean();
std::swap(data, other.data);
std::swap(rows, other.rows);
std::swap(cols, other.cols);
return *this;
}
Generally, if you need common code between methods, the best way is to factor out the common code into (private) helper methods. For example, you might have a method alloc_ that has the loop calling new and a free_ that calls delete. Then you could have:
Matrix(const Matrix &a) : rows(a.rows), cols(a.cols) {
alloc_();
copy_(a);
}
Matrix &operator=(const Matrix &a) {
free_();
rows = a.rows;
cols = a.cols;
alloc_();
copy_(a);
}
~Matrix() { free_(); }
Use a 1D array then. It will be much cleaner and simpler and faster than an array of pointers to arrays... You can do something like:
template <typename T>
class Matrix
{
private:
// Note: Assuming T is a trivial type, most likely a fundamental type...
T* data; // Flattened matrix with size = rows*cols. Be careful,
// for really big matrices this multiplication could overflow!!!
// You can use unsigned type since negative size is a nonsense...
unsigned int rows;
unsigned int cols;
public:
Matrix(const Matrix& other)
: data(new T[other.rows*other.cols])
, rows(other.rows)
, cols(other.cols)
{
/// You can do this:
/// for(int i = 0; i < rows*cols; ++i)
/// data[i] = other.data[i];
/// or simply call the copy assign operator:
operator=(other);
}
Matrix& operator=(const Matrix& other)
{
// This is only for matrix with the same dimensions.
// Delete and allocate new array if the dimensions are different.
// This is up to the OP if he can have differently sized matrices or not...
// Also assert will "disappear" if NDEBUG (ie. in release) is defined.
assert(rows == other.rows);
assert(cols == other.cols);
for(int i = 0; i < rows*cols; ++i)
data[i] = other.data[i];
return *this;
}
};
Note: You will also need to define the constructor(s) and destructor of course...
I'm pretty sure you can't make it much simpler than this...
I got a class Matrix and a class Row. Matrix has as member variable a pointer to a pointer of an object from class Row. I overloaded the operator [] for Matrix and Row. But somehow the overloaded operator from Row is never getting called and I can't figure out why not.
Example Code:
matrix.h
class Row
{
int* value;
int size;
public:
int& operator[](int i)
{
assert(i >= 0 && i < size);
return value[i];
}
};
class Matrix
{
private:
Row **mat; // Pointer to "Row"-Vector
int nrows, ncols; // Row- and Columnnumber
public:
Row& Matrix::operator[](int i){
assert(i >= 0 && i < nrows);
return *mat[i];
}
Row** getMat() {
return mat;
}
// Constructor
Matrix(int rows, int cols, int value);
};
matrix.cpp
#include "matrix.h"
Matrix::Matrix(int rows, int cols, int value) : nrows(rows), ncols(cols){
mat = new Row*[rows];
for(int i = 0; i < rows; i++) {
mat[i] = new Row(ncols);
for(int j = 0; j < ncols; j++){
// the operator-overload of Row[] isn't getting called and I don't get why not
mat[i][j] = value;
}
}
}
int main(){
Matrix m = new Matrix(2, 2, 4);
return 0;
mat[i] gives you Row*, and you want to call Row::operator[], but pointer to Row is not dereferenced automatically. So you have to dereference it manually: (*mat[i])[j].
So I just figured it out myself.
I tried to call the []-operator from Matrix through mat[][], but since mat is a Row** Row& Matrix::operator[](int i) is never getting called.
I'm just going to preface this with the fact that I'm new to C++ so it's quite possible there's just a stupid error here, but I can't find it.
I'm just trying to overload the increment operator in a friend function. Everything compiles perfectly and everything works if I explicitly call the postfix increment overload:
operator++(*test, 0);
Every element in the matrix is incremented and the program prints it out using cout perfectly. The problem is when I try to do the normal ++ increment test++; it appears as though something wrong happens with the test pointer to where when it tries to print the test object it doesn't print anything.
Any idea what's going on? I'm clueless. Here's the code I'm working with...
Compile & Run
g++ -o App App.cpp Matrix.cpp
./App
App.cpp
#include <iostream>
#include "Matrix.h"
using namespace std;
#define X 9
int main(int argc, char *argv[])
{
// Start the actual program here
Matrix* test = new Matrix(3,3);
// Row 1
test->setElement(0,0,1);
test->setElement(0,1,2);
test->setElement(0,2,3);
// Row 2
test->setElement(1,0,4);
test->setElement(1,1,5);
test->setElement(1,2,6);
// Row 3
test->setElement(2,0,7);
test->setElement(2,1,8);
test->setElement(2,2,9);
operator++(*test, 0);
//test++;
//++test;
// Print the Matrix object
cout << *test << endl;
}
Matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <iostream>
using namespace std;
class Matrix {
friend ostream& operator<<(ostream&, const Matrix&);
friend Matrix& operator++(Matrix&); // prefix increment
friend Matrix& operator++(Matrix&, int); // postfix increment
private:
int rows;
int cols;
int** elements;
public:
// Constructors
Matrix(int);
Matrix(int,int);
Matrix(const Matrix&);
// Define setters
void setElement(int,int,int);
// Define getters
int getRowCount();
int getColCount();
int getElementAt(int,int);
void increment();
// Destructor
~Matrix();
};
#endif
Matrix.cpp
#include <iostream>
#include "Matrix.h"
using namespace std;
//===================================
// DEFINE [CON]/[DE]STRUCTORS
//===================================
// Constructor for creating square matricies
Matrix::Matrix(int _size) {
rows = _size;
cols = _size;
elements = new int*[_size];
for (int i = 0; i < _size; i++) {
elements[i] = new int[_size];
}
}
// Constructor for supporting non-square matricies
Matrix::Matrix(int _rows, int _cols) {
rows = _rows;
cols = _cols;
elements = new int*[_rows];
for (int i = 0; i < _rows; i++) {
elements[i] = new int[_cols];
}
}
// Copy constructor
Matrix::Matrix(const Matrix& mat1) {
Matrix(mat1.rows, mat1.cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
elements[i][j] = mat1.elements[i][j];
}
}
}
// Destructor
Matrix::~Matrix() {
for (int i = 0; i < rows; i++) {
delete[] elements[i];
}
delete[] elements;
}
//===================================
// DEFINE SETTER FUNCTIONS
//===================================
void Matrix::setElement(int row, int col, int newElement) {
if (row > rows-1 || row < 0)
throw "Row out of index";
if (col > cols-1 || col < 0)
throw "Column out of index";
elements[row][col] = newElement;
}
//===================================
// DEFINE GETTER FUNCTIONS
//===================================
int Matrix::getRowCount() { return rows; }
int Matrix::getColCount() { return cols; }
int Matrix::getElementAt(int row, int col) {
if (row > rows-1 || row < 0)
throw "Row out of index";
if (col > cols-1 || col < 0)
throw "Column out of index";
return elements[row][col];
}
//===================================
// OVERRIDE OPERATOR FUNCTIONS
//===================================
// Print the Matrix to the output stream
ostream& operator<<(ostream& out, const Matrix& mat) {
for (int i = 0; i < mat.rows; i++) {
for (int j = 0; j < mat.cols; j++) {
out << mat.elements[i][j] << " ";
}
out << endl;
}
return out;
}
// Prefix. Increment immediately and return the object.
Matrix& operator++(Matrix& mat) {
cout << "Prefix ++ operator" << endl;
// Increment all elements in the object by 1
for (int i = 0; i < mat.rows; i++) {
for (int j = 0; j < mat.cols; j++) {
mat.elements[i][j] += 1;
}
}
return mat;
}
// Postfix. Return the current object and "save" the incremented.
Matrix& operator++(Matrix& mat, int x) {
cout << "Postfix ++ operator" << endl;
// Save the current values
Matrix* curVals = new Matrix(mat);
// Increment the object
++(mat);
// Return the unincremented values
return *curVals;
}
test++ increments the value of test, so that it will point to the memory after your Matrix object. You need to dereference the pointer to get a Matrix object, then apply the increment to that.
What you want is (*test)++ or ++*test.
Assume I have a class A that has say 3 methods. So the first methods assigns some values to the first array and the rest of the methods in order modify what is computed by the previous method. Since I wanted to avoid designing the methods that return an array (pointer to local variable) I picked 3 data member and store the intermediate result in each of them. Please note that this simple code is used for illustration.
class A
{
public: // for now how the class members should be accessed isn't important
int * a, *b, *c;
A(int size)
{
a = new int [size];
b = new int [size];
c = new int [size];
}
void func_a()
{
int j = 1;
for int(i = 0; i < size; i++)
a[i] = j++; // assign different values
}
void func_b()
{
int k = 6;
for (int i = 0; i < size; i++)
b[i] = a[i] * (k++);
}
void func_c()
{
int p = 6;
for int (i = 0; i < size; i++)
c[i] = b[i] * (p++);
}
};
Clearly, if I have more methods I have to have more data members.
** I'd like to know how I can re-design the class (having methods that return some values and) at the same time, the class does not have the any of two issues (returning pointers and have many data member to store the intermediate values)
There are two possibilities. If you want each function to return a new array of values, you can write the following:
std::vector<int> func_a(std::vector<int> vec){
int j = 1;
for (auto& e : vec) {
e = j++;
}
return vec;
}
std::vector<int> func_b(std::vector<int> vec){
int j = 6;
for (auto& e : vec) {
e *= j++;
}
return vec;
}
std::vector<int> func_c(std::vector<int> vec){
//same as func_b
}
int main() {
std::vector<int> vec(10);
auto a=func_a(vec);
auto b=func_b(a);
auto c=func_c(b);
//or in one line
auto r = func_c(func_b(func_a(std::vector<int>(10))));
}
Or you can apply each function to the same vector:
void apply_func_a(std::vector<int>& vec){
int j = 1;
for (auto& e : vec) {
e = j++;
}
}
void apply_func_b(std::vector<int>& vec){
int j = 6;
for (auto& e : vec) {
e *= j++;
}
}
void apply_func_c(std::vector<int>& vec){
// same as apply_func_b
}
int main() {
std::vector<int> vec(10);
apply_func_a(vec);
apply_func_b(vec);
apply_func_c(vec);
}
I'm not a big fan of the third version (passing the input parameter as the output):
std::vector<int>& func_a(std::vector<int>& vec)
Most importantly, try to avoid C-style arrays and use std::vector or std::array, and don't use new, but std::make_unique and std::make_shared
I'm assuming you want to be able to modify a single array with no class-level attributes and without returning any pointers. Your above code can be modified to be a single function, but I've kept it as 3 to more closely match your code.
void func_a(int[] arr, int size){
for(int i = 0; i < size; i++)
arr[i] = i+1;
}
void func_b(int[] arr, int size){
int k = 6;
for(int i = 0; i < size; i++)
arr[i] *= (k+i);
}
//this function is exactly like func_b so it is really unnecessary
void func_c(int[] arr, int size){
int p = 6;
for(int i = 0; i < size; i++)
arr[i] *= (p+i);
}
But if you just want a single function:
void func(int[] arr, int size){
int j = 6;
for(int i = 0; i < size; i++)
arr[i] = (i+1) * (j+i) * (j+i);
}
This solution in other answers is better, if you are going to allocate memory then do it like this (and test it!) also if you are not using the default constructor and copy constructor then hide them, this will prevent calling them by accident
class A{
private:
A(const &A){}
A() {}//either define these or hide them as private
public:
int * a, *b, *c;
int size;
A(int sz) {
size = sz;
a = new int[size];
b = new int[size];
c = new int[size];
}
~A()
{
delete[]a;
delete[]b;
delete[]c;
}
//...
};
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Operator[][] overload
I have made class which contains an array containing (in one row) all the numbers from the given 2d array. For example given: {{1,2}{3,4}} the b field in the object of class T contains {1,2,3,4}. I would like to overload[][] operator for this class so it will work like that
T* t.....new etc.
int val = (*t)[i][j]; //I get t->b[i*j + j] b is an 1dimension array
class T{
public:
int* b;
int m, n;
T(int** a, int m, int n){
b = new int[m*n];
this->m = m;
this->n = n;
int counter = 0;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
b[counter] = a[i][j];
counter++;
}
}
}
int main()
{
int m = 3, n = 5, c = 0;
int** tab = new int*[m];
for(int i = 0; i < m; i++)
tab[i] = new int[n];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
tab[i][j] = c;
c++;
cout<<tab[i][j]<<"\t";
}
cout<<"\n";
}
T* t = new T(tab,3,5);
};
You cannot. You have to overload operator[] to return a proxy object, that in turn, overloads operator[] to return the final value.
Something like:
class TRow
{
public:
TRow(T &t, int r)
:m_t(t), m_r(r)
{}
int operator[](int c)
{
return m_t.tab[m_t.n*m_r + c];
}
private:
T &m_t;
int m_r;
};
class T
{
friend class TRow;
/*...*/
public:
TRow operator[](int r)
{
return TRow(*this, r);
}
};
Instead of saving a T& in TRow you could save directly a pointer to the row, that's up to you.
A nice feature of this solution is that you can use the TRow for other things such as operator int*().
In the case of a 2d array, you don't need to create a proxy type. Just use int*:
#include <iostream>
class T {
public:
int m, n;
int *b;
T(int m, int n) : m(m), n(n), b(new int[m*n]) {
}
int*operator[](std::size_t i) {
return &b[i*m];
}
};
int main () {
T t(2,2);
t[0][0] = 1;
t[0][1] = 2;
t[1][0] = 3;
t[1][1] = 4;
std::cout << t.b[0] << t.b[1] << t.b[2] << t.b[3] << "\n";
}