There are two files:
Matrix.hpp:
template <typename T>
class Matrix {
private:
size_t rows = 0;
size_t cols = 0;
T* data = nullptr;
public:
Matrix() = default;
~Matrix();
Matrix(size_t n, size_t m);
T& operator() (size_t i, size_t j);
};
template <typename T>
Matrix<T>::Matrix(size_t n, size_t m) : rows(n), cols(m) {
try {
data = new T[rows*cols];
} catch (const std::bad_alloc& e) {
std::exit(EXIT_FAILURE);
}
};
template <typename T>
Matrix<T>::~Matrix() {
delete[] data;
}
template <typename T>
T& Matrix<T>::operator()(size_t i, size_t j) {
if (i < rows && i >= 0 && j < cols && j >= 0) {
return data[(i+1)*cols + (j+1)];
} else {
throw std::logic_error("matrix indices out of range");
}
}
and
Main.cpp:
#include <iostream>
#include "Matrix.hpp"
int main() {
size_t n, k;
std::cin >> n >> k;
Matrix<long double> m = {n, k};
for (size_t i = 0; i < m.getNumRows(); ++i) {
for (size_t j = 0; j < m.getNumCols(); ++j) {
std::cin >> m(i,j);
}
}
for (size_t i = 0; i < m.getNumRows(); ++i) {
std::cout << "\n";
for (size_t j = 0; j < m.getNumCols(); ++j) {
std::cout << m(i, j) << " ";
}
}
return 0;
}
When I'm entering something like:
1 2 3 4
I can get
3 4
as answer but sometimes the same input causes Segmentation fault 11 moreover when I'm changing template argument from long double to int, error disappears. How can I fix it?
Your operator function is accessing data outside its bounds.
Passing (0,0) to the function should return data[0]. Currently it returns data[2].
Change line
return data[(i+1)*cols+(j+1)];
to
return data[i*cols+j];
Related
I'm trying to split a matrix given into 4, but I'm getting some errors and I can't figure out why. I'm kind of new to the language. Does anybody knows what am I doing wrong?
void split_tl(T **matrice, unsigned int dim){
if(dim == 1){
return;
}
T **tl = new T*[dim/4];
for(unsigned int i = 0; i<dim/4;++i){
tl[i] = new T[dim/4];
}
for(unsigned int i=0; i<dim;++i){
for(unsigned int j=0; j<dim;j++){
if((i<dim/2) && (j<dim/2)){
tl[i][j] = matrice[i][j];
} else{
std::cout << "no ";
}
}
std::cout << std::endl;
}
}
In this function I'm trying to obtain the top left corner of the matrix.
int **matrice = new int*[2];
for(unsigned int i = 0; i<2;++i){
matrice[i] = new int[2];
}
for(unsigned int i = 0; i<2;++i){
for(unsigned int j = 0; j<2;++j){
matrice[i][j] = i+j;
}
}
This is the matrix I'm sending. It is a 2x2 matrix, just for testing purposes.
These are the errors from Valgrind:
==133== Invalid read of size 8
==133== Invalid write of size 4
==133== Process terminating with default action of signal 11 (SIGSEGV)
==133== Access not within mapped region at address 0x0
If dim is the side of a matrix, allocating to a quarter matrix should be dim/2.
Below in the code you are using :
if((i<dim/2) && (j<dim/2)){
tl[i][j] = matrice[i][j];
}
here tl may exceed the allocation
What you're doing wrong? You're allocating memory and passing pointers around.
Build a proper matrix class, e.g. (very simplified version):
template <typename T, unsigned Rows, unsigned Cols>
struct generic_matrix {
using datatype = T;
static constexpr unsigned rows = Rows;
static constexpr unsigned cols = Cols;
datatype data[rows][cols];
constexpr datatype& operator()(unsigned row, unsigned col) noexcept
{ return data[row][col]; }
constexpr const datatype& operator()(unsigned row, unsigned col) const noexcept
{ return data[row][col]; }
};
Submatrix:
/* Returns a submatrix of the matrix m,
* by deleting the row r and the column c.*/
template <typename M>
auto submatrix(const M& m, unsigned r, unsigned c) noexcept
{
generic_matrix<typename M::datatype, M::rows-1, M::cols-1> res;
for (unsigned row = 0, i = 0; row < M::rows; ++row) {
if (row == r) continue; //this row we do not want
for (unsigned col = 0, j = 0; col < M::cols; ++col) {
if (col == c) continue; //this col we do not want
res(i,j) = m(row,col);
++j;
}
++i;
}
return res;
}
Print:
template <typename M>
void printmatrix(const M& m) noexcept
{
for (unsigned r=0; r < M::rows; ++r) {
for (unsigned c=0; c < M::cols; ++c) {
std::cout << m(r,c) << ' ';
}
std::cout << '\n';
}
}
Test:
int main()
{
int n=0;
generic_matrix<int, 3, 3> m;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 3; ++c)
m(r,c) = ++n;
printmatrix(m);
std::cout << '\n';
printmatrix(submatrix(m, 0, 0));
std::cout << '\n';
printmatrix(submatrix(m, 1, 1));
std::cout << '\n';
printmatrix(submatrix(m, 2, 2));
return 0;
}
Note: It is just a hint. As you can see, no allocation nor casting is needed.
I have a template of a matrix class:
template <typename T>
class Matrix {
And many functions (like adding two matrices) return std::optional. I wanted to make an operator that would unwrap the value (or throw an exception):
template <class T>
Matrix<T> operator!(const std::optional<Matrix<T>>& other) {
return other.value();
}
Doing that I get the error C2440: "Cannot convert from const _Ty to Matrix< int > with [ _Ty = Matrix]". It says that construction of Matrix class cannot be done because of ambiguous copying constructors or unavailable copying constructor.
EDIT:
#include <iostream>
#include <optional>
template <typename T>
class Matrix {
private:
T** matrix;
int sizeX;
int sizeY;
public:
Matrix(int x, int y);
Matrix(Matrix<T>& other);
Matrix(Matrix<T>&& other);
void set_value(T val, int x, int y);
std::optional<Matrix<T>> vec_from_col(int colIndex);
};
template <typename T>
Matrix<T>::Matrix(int x, int y) {
std::cout << "Matrix Param\n";
if (x <= 0 || y <= 0) {
return;
throw -1;
}
else {
matrix = new T*[x];
for (int i = 0; i < x; i++) {
matrix[i] = new T[y];
for (int j = 0; j < y; j++) {
matrix[i][j] = 0;
}
}
sizeX = x;
sizeY = y;
}
}
template <typename T>
Matrix<T>::Matrix(Matrix<T>& other) {
std::cout << "Matrix Copy\n";
sizeX = other.sizeX;
sizeY = other.sizeY;
matrix = new T*[sizeX];
for (int i = 0; i < sizeX; i++) {
matrix[i] = new T[sizeY];
for (int j = 0; j < sizeY; j++) {
matrix[i][j] = other.matrix[i][j];
}
}
}
template <typename T>
Matrix<T>::Matrix(Matrix<T>&& other) {
std::cout << "Matrix Move\n";
sizeX = other.sizeX;
sizeY = other.sizeY;
matrix = other.matrix;
other.matrix = NULL;
}
template <typename T>
void Matrix<T>::set_value(T val, int x, int y) {
if (x < 0 || x >= sizeX || y < 0 || y >= sizeY) {
std::cout << "Invalid index was given. Matrix was unchanged.\n";
return;
}
else {
matrix[x][y] = val;
}
}
template <typename T>
std::optional<Matrix<T>> Matrix<T>::vec_from_col(int colIndex) {
if (colIndex < 0 || colIndex >= sizeX) {
return {};
}
Matrix<T> newVec(1, sizeY);
for (int i = 0; i < sizeY; i++) {
newVec.set_value(matrix[colIndex][i], 0, i);
}
return newVec;
}
template <class T>
Matrix<T> operator!(const std::optional<Matrix<T>>& other) {
return other.value();
}
int main() {
Matrix<int> test(2, 3);
test.set_value(10, 0, 1);
test.set_value(5, 0, 0);
test.set_value(13, 0, 2);
test.set_value(8, 1, 0);
Matrix<int> vec = !test.vec_from_col(0);
}
Your copy constructor is wrong which causes this ambiguity.
Matrix(Matrix<T>& other);
should be
Matrix(const Matrix<T>& other);
Note: You also leak memory since you new[] but don't delete[].
The method template <class T> const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const for program matrix.cc should be able to return the sum of calling object's matrix and rhs's matrix as a new object. Also, the lhs and rhs rows and cols will be equal.
The error output that I am receiving from the compiler is:
[hw7] make clean && make bin/test_add && ./bin/test_add UserSettings ✱
rm -f bin/*
g++ -std=c++11 -Wall -I inc -I src -c src/test_matrix_add.cc -o bin/test_matrix_add.o
g++ -std=c++11 -Wall -I inc -I src -o bin/test_add bin/test_matrix_add.o
Testing Matrix::operator+
Expected Matrix2[0][0]: 3.0, Actual: 1
FAILED
Could someone let me know why I receive this "Failed" output when I know I pass the // TEST MUL ASSIGMENT OP CORRECT RETURN section.
Here is my matrix.cc:
#include <matrix.h>
template <class T>
Matrix<T>::Matrix() {
rows_ = 0;
cols_ = 0;
m_ = nullptr;
}
template <class T>
Matrix<T>::Matrix(unsigned int rows, unsigned int cols)
: rows_(rows), cols_(cols) {
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
}
}
template <class T>
Matrix<T>::Matrix(const Matrix<T> &that) {
rows_ = that.rows_;
cols_ = that.cols_;
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] = that.m_[i][j];
}
}
}
template <class T>
Matrix<T>::~Matrix() {
for (unsigned int i = 0; i < rows_; ++i) {
delete[] m_[i]; // delete columns
}
delete[] m_; // delete columns
}
template <class T>
T Matrix<T>::Get(unsigned int row, unsigned int col) const {
if (row > rows_ && col > cols_) {
throw std::out_of_range("error: index out of range");
}
return this->m_[row][col];
}
template <class T>
const Matrix<T> &Matrix<T>::operator=(const Matrix<T> &rhs) {
if (this == &rhs) {
return *this;
} // returns the address
for (unsigned int i = 0; i < rows_; ++i) {
delete[] m_[i];
}
delete[] m_;
rows_ = rhs.rows_;
cols_ = rhs.cols_;
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] = rhs.m_[i][j];
}
}
return *this;
}
template <class T>
const Matrix<T> &Matrix<T>::operator*=(T rhs) {
for (unsigned int i = 0; i < rows_; ++i) {
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] *= rhs;
}
}
return *this;
}
template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const {
if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_)) {
std::cout << "Cannont add matrices. Wrong dimensions\n";
exit(0);
}
Matrix<T> lhs;
lhs.rows_ = this->rows_;
lhs.cols_ = this->cols_;
for (unsigned int i = 0; i < lhs.rows_; ++i) {
for (unsigned int j = 0; j < lhs.cols_; ++j) {
lhs[i][j] += rhs[i][j];
}
}
return lhs;
}
Here is my matrix.h:
#include <cassert>
// using assert
#include <exception>
#include <iostream>
template <class T>
class Matrix {
public:
friend class MatrixTester;
Matrix(); // for testing, useless in practice
Matrix(unsigned int rows, unsigned int cols);
Matrix(const Matrix<T> &that);
~Matrix();
T Get(unsigned int row, unsigned int col) const;
const Matrix<T> &operator=(const Matrix<T> &rhs);
const Matrix<T> &operator*=(T rhs);
const Matrix<T> operator+(const Matrix<T> &rhs) const;
private:
T **m_;
unsigned int rows_;
unsigned int cols_;
};
#include <matrix.cc> //NOLINT
This is my test_matrix_add.cc tester:
#include <test_matrix.h>
int main(int argc, char** argv) {
MatrixTester tester;
cout << "Testing Matrix::operator+" << endl;
if (tester.Test_AddOp()) {
cout << " PASSED" << endl;
return 0;
}
cout << " FAILED" << endl;
return 1;
}
bool MatrixTester::Test_AddOp() const {
const int kRows = 4, kCols = 5;
Matrix<double> m1;
m1.m_ = new double*[kRows];
for (unsigned int i = 0; i < kRows; ++i) {
m1.m_[i] = new double[kCols];
for (unsigned int j = 0; j < kCols; ++j)
m1.m_[i][j] = (i + 1.0) * (j + 1.0);
}
m1.rows_ = kRows;
m1.cols_ = kCols;
// TEST ADDITION CORRECTNESS
Matrix<double> m2;
m2 = m1;
// + m1 + m1;
if (m2.m_[0][0] != 3) {
cout << " Expected Matrix2[0][0]: 3.0, Actual: " << m2.m_[0][0] << endl;
return false;
}
if (m2.m_[1][3] != 24.0) {
cout << " Expected Matrix2[1][3]: 24.0, Actual: " << m2.m_[1][3] << endl;
return false;
}
if (m2.m_[2][2] != 27.0) {
cout << " Expected Matrix2[2][2]: 27.0, Actual: " << m2.m_[2][2] << endl;
return false;
}
if (m2.m_[3][4] != 60.0) {
cout << " Expected Matrix2[2][2]: 60.0, Actual: " << m2.m_[2][2] << endl;
return false;
}
return true;
}
Firstly, there is way too much code here.
To address your problem, I see don't see you allocating memory to lhs.m_. This is a problem because you initialize lhs with the default constructor, which only assigns this->m_ to a nullptr.
To fix this, this should work (although untested):
template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& rhs) const
{
if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_))
{
std::cout << "Cannot add matrices. Wrong dimensions\n";
exit(0);
}
Matrix<T> lhs;
lhs.rows_ = this->rows_;
lhs.cols_ = this->cols_;
// Allocate memory for `lhs.m_`, like you did in your 2nd constructor
lhs.m_ = new T* [rows_];
for (unsigned i = 0; i < rows_; ++i)
{
m_[i] = new T[cols_];
}
// [End] allocation
for (unsigned int i = 0; i < lhs.rows_; ++i)
{
for (unsigned int j = 0; j < lhs.cols_; ++j)
{
lhs[i][j] += rhs[i][j];
}
}
return lhs;
}
Also, somewhat unrelated, be careful that you consistently treat m_ as a double-pointer. I didn't read all your code, but just be cautious. And also remember that you have to deallocate all the memory you allocated with new in your destructor. Personally, I believe you should use smart pointers from <memory> (e.g. std::unique_ptr, etc), which you can learn more about here. Using smart pointers would make the pointers deallocate the memory on their own and you wouldn't have to worry about memory leaks.
Edit 1
As walnut stated, a better solution would be to just call the 2nd constructor, which will allocate the memory for you. So, your revised function would be:
template <class T>
/**
Note:
> When you call this function (e.g. Matrix<T> new_mat = mat1 + mat2),
`mat1` is `this` and `mat2` is what you're calling `rhs`. I've done
some renaming and corrected your logic errors here
*/
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& other) const
{
if (!(this->cols_ == other.cols_) || (this->rows_ == other.rows_))
{
std::cout << "Cannot add matrices. Wrong dimensions\n";
exit(0);
}
// Call the 2nd constructor
Matrix<T> res(this->rows_, this->cols_);
for (unsigned i = 0; i < res.rows_; ++i)
{
for (unsigned j = 0; j < res.cols_; ++j)
{
res.m_[i][j] = this->m_[i][j] + other.m_[i][j];
}
}
return res;
}
Edit 2
The above code has been correct to add the matrices correctly, as per #walnut's comment.
I get this error while running the following program (it execute the code perfectly but looks like there are some issues about pointers/memory). thanks in advance for your help...
This is the message i get:
REVIEW(8310) malloc: * error for object 0x100103b80: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
(lldb)
My code:
In file Matrix.h
template <typename T>
class Matrix
{
private:
T** M;
// unsigned numCol, numRow;
unsigned minRowIndex, maxRowIndex;
unsigned minColIndex, maxColIndex;
public:
Matrix(); // default constructor
Matrix(const unsigned& _numRow,
const unsigned& _numCol,
const T& value,
const unsigned& _minRowIndex = 0,
const unsigned& _minColIndex = 0);
~Matrix();
void Print();
T& operator() (const unsigned& row, const unsigned& col);
};
template<typename T>
Matrix<T> :: Matrix()
{
maxRowIndex = 9;
maxColIndex = 9;
unsigned i,j;
M = new T*[maxRowIndex + 1];
for (i = minRowIndex; i < maxRowIndex; i++)
M[i] = new T[maxColIndex + 1];
for (i = minRowIndex; i < maxRowIndex; i++)
for (j = minColIndex; j < maxColIndex; j++)
M[i][j] = 0;
}
template<typename T>
Matrix<T> :: Matrix( const unsigned& _numRow,
const unsigned& _numCol,
const T& value,
const unsigned& _minRowIndex,
const unsigned& _minColIndex)
{
minRowIndex = _minRowIndex;
minColIndex = _minColIndex;
maxRowIndex = _minRowIndex + _numRow - 1;
maxColIndex = _minColIndex + _numRow - 1;
unsigned i,j;
M = new T*[maxRowIndex + 1];
for (i = minRowIndex; i <= maxRowIndex; i++)
M[i] = new T[maxColIndex + 1];
for (i = minRowIndex; i <= maxRowIndex; i++)
for (j = minColIndex; j <= maxColIndex; j++)
M[i][j] = value;
}
template<typename T>
Matrix<T> :: ~Matrix()
{
for (unsigned i = 0; i <= maxRowIndex; i++)
delete[] M[i];
delete[] M;
}
template<typename T>
void Matrix<T> :: Print()
{
unsigned i,j;
for (i = minRowIndex ; i <= maxRowIndex; i++)
for (j = minColIndex; j <= maxColIndex; j++)
{
cout << M[i][j] << " ";
if (j == maxColIndex)
cout << endl;
}
cout << endl;cout << endl;
}
template<typename T>
T& Matrix<T> :: operator() (const unsigned& row, const unsigned& col)
{
return M[row][col];
}
In file main.cpp
#include "Matrix.h"
using namespace std;
int s(Matrix<int> L)
{
return L(2,2);
}
int main()
{
Matrix<int> L (5,5,100);
cout << "L(2,2) = " << s(L) << endl << endl;
return 0;
}
Classes that allocate fields using new and delete should have copy constructors and overload operator=. Failing to do so will use the default forms where fields are simply copied.
In your case, T** M is copied during the call to s(L) and upon return, the copy is destructed, causing deletes for all the arrays. At the end of main, another destruction takes place, but now the pointers refer to already freed blocks.
For function s, you might also pass a reference to avoid copying (but this doesn't solve the general problem).
I am not sure if I am correctly overloading the << operator. The following code compiles without problem but does not produce the expected output.
#include <iostream>
#include "Matrix.h"
template<class T>
std::ostream& operator<<(std::ostream &out, const matrix<T> &A)
{
for(int ii = 0; ii << A.size(1); ii++)
{
for(int jj = 0; jj < A.size(2); jj++)
{
out << A(ii,jj) << " ";
}
out << std::endl;
}
return out;
}
int main(int argc, char** argv)
{
matrix<double> A = {{1.0, 2.0},{1.0,-1.0}};
cout << "\"" << A << "\"\n";
return 0;
}
The only output is:
""
Matrix.h
template<class T>
class matrix
{
public:
matrix(int rows, int cols);
matrix(const std::initializer_list<std::initializer_list<T>>& lst);
T& operator()(int i, int j);
T operator()(int i, int j) const;
int size(int n) const;
private:
int mRows;
int mCols;
std::vector<T> mData;
};
template<class T>
matrix<T>::matrix(int rows, int cols)
: mRows(rows),
mCols(cols),
mData(rows * cols)
{
}
template<class T>
matrix<T>::matrix(const std::initializer_list<std::initializer_list<T> >& lst)
: matrix(lst.size(), lst.size() ? lst.begin()->size() : 0)
{
int ii = 0, jj = 0;
for(const auto& l : lst)
{
for(const auto& v : l)
{
mData[ii*mCols + jj] = v;
jj++;
}
jj = 0;
ii++;
}
}
template<class T>
T& matrix<T>::operator()(int i, int j)
{
return mData[i*mCols + j];
}
template<class T>
T matrix<T>::operator()(int i, int j) const
{
return mData[i*mCols + j];
}
template<class T>
int matrix<T>::size(int n) const
{
if(n == 1)
{
return mRows;
}
else if(n == 2)
{
return mCols;
}
}
In your first for loop, you have:
for(int ii = 0; ii << A.size(1); ii++)
^
That should be a single < character:
for(int ii = 0; ii < A.size(1); ii++)
^
The reason why it wasn't doing anything is because the original loop resulted in a condition of 0 << A.size(1), which is 0, or false; thus, the outer loop is never executed.