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.
Related
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*=(T rhs) for program matrix.cc should be able to returns calling object with matrix scaled by rhs, and the parameter rhs will be the same type as the matrix.
The error output that I am receiving from the compiler is:
[hw7] make clean && make bin/test_matrix_mul_assign && ./bin/test_matrix_mul_assign
rm -f bin/*
g++ -std=c++11 -Wall -I inc -I src -c src/test_matrix_mul_assign.cc -o bin/test_matrix_mul_assign.o
g++ bin/test_matrix_mul_assign.o -o bin/test_matrix_mul_assign
Testing Matrix::operator*=
Expected Matrix[0][0]: 2.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>
const Matrix<T> &Matrix<T>::operator*=(T rhs) {
unsigned int rows_ = 0;
unsigned int cols_ = 0;
T **m_ = nullptr;
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][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] += rhs[i];
}
}
return lhs;
}
Here is my matrix.h:
#include <cassert>
// using assert
#include <exception>
#include <iostream>
template <class T>
class Matrix {
public:
friend class MatrixTester;
/* Times Equals Op: 1 Point
* Returns calling object with matrix scaled by rhs.
* Parameter:
* - rhs will be the same type as the matrix
*/
const Matrix<T> &operator*=(T rhs);
/* Add Op: 1 Point
* Returns the sum of calling object's matrix and rhs's matrix as a new
* object.
* Precondition(s):
* - lhs rows must equal rhs rows
* - lhs cols must equal rhs cols
*/
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_mul_assign.cc tester:
#include <test_matrix.h>
int main(int argc, char **argv) {
MatrixTester tester;
cout << "Testing Matrix::operator*=" << endl;
if (tester.Test_MulAssignOp()) {
cout << " PASSED" << endl;
return 0;
}
cout << " FAILED" << endl;
return 1;
}
bool MatrixTester::Test_MulAssignOp() const {
const int kRows = 3, kCols = 4;
Matrix<double> test_m;
test_m.m_ = new double *[kRows];
for (unsigned int i = 0; i < kRows; ++i) {
test_m.m_[i] = new double[kCols];
for (unsigned int j = 0; j < kCols; ++j)
test_m.m_[i][j] = (i + 1.0) * (j + 1.0);
}
test_m.rows_ = kRows;
test_m.cols_ = kCols;
// TEST MUL ASSIGMENT OP CORRECT RETURN
const Matrix<double> *m_ptr = &(test_m *= 2.0);
if (m_ptr != &test_m) {
cout << " Expected return address of assigment: " << &test_m
<< ", Actual: " << m_ptr << endl;
return false;
}
// TEST MUL ASSIGMENT OP CALCULATION
if (test_m.m_[0][0] != 2.0) {
cout << " Expected Matrix[0][0]: 2.0, Actual: " << test_m.m_[0][0] << endl;
return false;
}
if (test_m.m_[1][3] != 16.0) {
cout << " Expected Matrix[1][3]: 16.0, Actual: " << test_m.m_[1][3]
<< endl;
return false;
}
if (test_m.m_[2][2] != 18.0) {
cout << " Expected Matrix[2][2]: 18.0, Actual: " << test_m.m_[2][2]
<< endl;
return false;
}
return true;
}
You have the following variable definitions in the operator*= implementation:
unsigned int rows_ = 0;
unsigned int cols_ = 0;
T **m_ = nullptr;
They will shadow all of the members of the class. When you use rows_, cols_ and m_ later in the function definition they will refer to these local variables, not the class members of the current instance.
Therefore effectively your implementation of operator*= does nothing at all. It is not surprising that the test for the correct value then fails.
Simply remove these declarations, so that the names will refer to the current instance's members instead.
Then there is also not going to be any point to m_[i] = new T[cols_];. So remove that as well.
Why are there all of these dynamic allocations with new in the first place? This is seriously bad style and is going to cause you all kinds of issues. Use std::vector instead.
class Matrix also seems to be lacking a proper constructor. This again will cause all kinds of issues, especially when it leaves memory allocation to a user of the class.
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];
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'm getting an error regarding "disgarded qualifiers" when I use this. The Entier class is posted below.
cout << d // where d is of type dynamic_array.
The global overloaded function:
template <class T> std::ostream& operator<<(std::ostream& stream, dynamic_array<T> const& data)
{
data.print_array(stream);
return stream;
}
A public member of dynamic_array
void print_array(std::ostream &os = cout)
{
for (int i = 0; i < size; i++) os << array[i] << endl;
}
Entire Class dynamic array:
/*
Needs a reszie function added
Merge sort is better for sequential, stable(equal elements not re-arranged, or
*/
#include "c_arclib.cpp"
using namespace std;
template <class T> class dynamic_array
{
private:
T* array;
T* scratch;
void merge_recurse(int left, int right)
{
if(right == left + 1)
{
return;
}
else
{
int i = 0;
int length = right - left;
int midpoint_distance = length/2;
int l = left, r = left + midpoint_distance;
merge_recurse(left, left + midpoint_distance);
merge_recurse(left + midpoint_distance, right);
for(i = 0; i < length; i++)
{
if((l < (left + midpoint_distance)) && (r == right || array[l] > array[r]))
{
scratch[i] = array[l];
l++;
}
else
{
scratch[i] = array[r];
r++;
}
}
for(i = left; i < right; i++)
{
array[i] = scratch[i - left];
}
}
}
void quick_recurse(int left, int right)
{
int l = left, r = right, tmp;
int pivot = array[(left + right) / 2];
while (l <= r)
{
while (array[l] < pivot)l++;
while (array[r] > pivot)r--;
if (l <= r)
{
tmp = array[l];
array[l] = array[r];
array[r] = tmp;
l++;
r--;
}
}
if (left < r)quick_recurse(left, r);
if (l < right)quick_recurse(l, right);
}
public:
int size;
dynamic_array(int sizein)
{
size=sizein;
array = new T[size]();
}
void print_array(std::ostream &os = cout)
{
for (int i = 0; i < size; i++) os << array[i] << endl;
}
void print_array()
{
for (int i = 0; i < size; i++) cout << array[i] << endl;
}
int merge_sort()
{
scratch = new T[size]();
if(scratch != NULL)
{
merge_recurse(0, size);
return 1;
}
else
{
return 0;
}
}
void quick_sort()
{
quick_recurse(0,size);
}
void rand_to_array()
{
srand(time(NULL));
int* k;
for (k = array; k != array + size; ++k)
{
*k=rand();
}
}
void order_to_array()
{
int* k;
int i = 0;
for (k = array; k != array + size; ++k)
{
*k=i;
++i;
}
}
void rorder_to_array()
{
int* k;
int i = size;
for (k = array; k != array + size; ++k)
{
*k=i;
--i;
}
}
};
template <class T> std::ostream& operator<<(std::ostream& stream, dynamic_array<T> const& data)
{
data.print_array(stream);
return stream;
}
int main()
{
dynamic_array<int> d1(1000000);
d1.order_to_array();
clock_t time_start=clock();
d1.merge_sort();
clock_t time_end=clock();
double result = (double)(time_end - time_start) / CLOCKS_PER_SEC;
cout << result;
cout << d1;
}
The problem is in following lines:
template <class T>
std::ostream& operator<<(std::ostream& stream, dynamic_array<T> const& data)
^^^^^^
and
void print_array(std::ostream &os = cout) /* const */
^^^^^ missing
Since you are passing data as const& to operator <<, you have to maintain its const qualification. i.e. data cannot call any non-const member of class dynamic_array. You can solve this problem in 2 ways:
pass data as simple dynamic_array<T>& to operator <<
make print_array a const method (uncomment above)
"Discards const qualifiers", presumably...
Replace:
void print_array(std::ostream &os = cout)
{
for (int i = 0; i < size; i++) os << array[i] << endl;
}
void print_array()
{
for (int i = 0; i < size; i++) cout << array[i] << endl;
}
...with...
void print_array(std::ostream &os = cout) const
{
for (int i = 0; i < size; i++) os << array[i] << endl;
}
...or, better still ...
void print_array(std::ostream &os = cout) const
{
std::copy(array, array + size, std::ostream_iterator<T>(os, "\n"));
}
This member function can be declared const since it doesn't modify any attributes of the class. See the FAQ on Const-Correctness.
Your second print_array() method is redundant since the first takes a default argument of std::cout.