Confusion with c++ templates - c++

I am working on a homework assignment that involved converting matrix and array classes supplied by my professor into templates. I am getting an error '=': cannot convert from 'Array *' to 'int' in my line m[i] = new Array < Type >(cols);
I would assume this is because m[i] is returning an int but I don't think it should be if I wrote my templates correctly and I can't quite figure out why it is giving back an int instead of a array pointer since m is an array of array pointers here is the code to my array template minus some overloads for << not used in this code.
template
< typename Type >
class Array
{
private:
int len;
Type * buf;
public:
Array(int newLen)
: len(newLen), buf(new Type[newLen])
{
}
Array(const Array & l)
: len(l.len), buf(new Type[l.len])
{
for (int i = 0; i < l.len; i++)
buf[i] = l.buf[i];
}
int length()
{
return len;
}
int & operator [] (int i)
{
assert(0 <= i && i < len);
return buf[i];
}
}
Here is my matrix template the error occurs in minus the same << overloads
#pragma once
#include "Array.h"
template
< typename Type >
class Matrix
{
private:
int rows, cols;
Array< Array<Type> * > m;
public:
Matrix(int newRows, int newCols)
: rows(newRows), cols(newCols), m(rows)
{
for (int i = 0; i < rows; i++)
m[i] = new Array < Type >(cols);
}
int numRows()
{
return rows;
}
int numCols()
{
return cols;
}
Array < Type > & operator [] (int row)
{
return *m[row];
}
}

The [] operator overload in the array class is what's messing you up.
int & operator [] (int i)
{
assert(0 <= i && i < len);
return buf[i];
}
It clearly returns an int as its type and when you try to use it such that: m[i] = new Array < Type >(cols);
m[i] will return an int type which you're trying to assign a new Array to.

The proximal issue is that Array isn't fully templated:
int & operator [] (int i)
Indexing into an Array<T> shouldn't give you an int&, it should give you a T&!
The other issue with your code is that you have a new in your Array constructor - where's the corresponding delete? You're leaking memory!
Same for the Matrix constructor, which additionally has the potential of double deleting memory if you happen to copy it.
See Rule of Three

Related

Allocating memory in a function and returning it

int** transpose(int** matrix,int row, int column)
{
int** new_mat = new int*[column];
for(int i = 0; i < column; i++)
{
new_mat[i] = new int[row];
}
for(int i = 0; i < row; i++ )
{
for(int j = 0; j < column; j ++)
{
new_mat[j][i] = matrix[i][j];
}
}
return new_mat;
}
I have written this function but something feels wrong I couldn't decide whether should I delete new_mat somehow basically function returns this value how should I manage with memory without using any smart pointers or something?
The caller would use the returned matrix.
Moreover, it could acquire ownership. As a result, when the matrix would be no longer needed, it could delete it.
Another option, is for you, to provide another function, that will delete the matrix. The caller then, must call that function to de-allocate the dynamically allocated memory.
However, smart pointers is a nice C++ feature, and I encourage you to give them a shot.
Furthermore, since this C++, you could use a std::vector<std::vector<int>> for the type of your matrix. That way, you don't have to worry about memory management, since everything about it, will happen automatically.
To answer the question as asked, the caller would need to release the returned pointer. For every usage of operator new in the function, there needs to be a corresponding usage of operator delete in the caller. The caller would do this when the matrix returned is no longer needed i.e. anything that is deleted should not subsequently be used.
A better approach - in many respects, including no potential to forget to release memory - is to avoid using pointers directly, avoid using operator new (or variants) or operator delete directly. Instead, use a standard container, such as std::vector(std::vector<int> >. If used carefully, standard containers manage their own elements, and keep a record of their own size, so there is no possibility of memory leak (when a standard container ceases to exist, any dynamically allocated memory it uses also is released).
In principle, you should be able to simplify your function to something that is declared as
std::vector<std::vector<int> > transpose(const std::vector<std::vector<int> > &matrix);
rather than needing to pass numbers of rows and columns as separate arguments (the vectors will keep track). I'll leave implementing that function as an exercise, since you'll learn more of use that way.
You really should think about your matrix representation:
int** matrix = ...; // create matrix of 10x12
// doing quite a lot of stuff
delete[] matrix[7]; // possibly even forgotten -> memory leak
matrix[7] = new int[7];
and you now have a jagged array. Although std::vector will relieve you from all the memory management stuff, you still won't be able to prevent jagged arrays with:
std::vector<std::vector<int>> matrix = ...; // create matrix of 10x12
// doing quite a lot of stuff
matrix[7].resize(7);
Safest thing you can do is create your own class wrapping around the data; I'll be using std::vectors to hold the data, this will make the whole memory management stuff much easier:
template <typename T> // more flexibility: you can use arbitrary data types...
class Matrix // (but you don't _need_ to make a template from)
{
std::vector<std::vector<T>> data;
public:
Matrix(size_t rows, size_t columns)
: data(rows)
{
for(auto& d : data)
d.resize(columns);
}
// the nice thing about using std::vector as data container is
// that default generated move/copy constructors/assignment
// operators and destructor are fine already, so you can forget
// about rule of three or five respectively
// but you need ways to access your data:
size_t rows() { return data.size(); }
size_t columns() { return data.empty() ? 0 : data[0].size(); }
??? operator[](size_t index);
??? operator[](size_t index) const;
};
Well, the index operators... What you actually want to achieve is something that you can access the matrix just like you did with your arrays:
Matrix<int> m(10, 12);
m[7][7] = 7;
But what should we return? A reference to an inner vector would again allow to modify its size and to create a jagged array this way. Solution: A wrapper class around!
template <typename T>
class Matrix
{
// all we had so far...
template <typename Data>
class Row
{
Data& data;
friend class Matrix;
Row(std::vector<T>& data)
: data(data)
{ }
public:
// default constructed constructors/operators/destructor
// themselves and being public are fine again...
auto& operator[](size_t index) { return data[index]; }
};
auto operator[](size_t index) { return Row(data[index]); }
auto operator[](size_t index) const { return Row(data[index]); }
};
Why Row a template? Well, we need different Row types (mutable and immutable access to data) as return types for the two different index operators...
Finally: If you implement yourself, I'd reorder the private/public sections such that public comes first. This improves readability for users of your Matrix class, as they are interested in public interface only (normally) unless they intend to inherit from. But that (currently) is not a good idea here anyway as this class is not intended for, just as std::vector is not either. If you want that: make the destructor virtual:
virtual ~Matrix() = default;
If you feel more comfortable with, you could make the rule of three/five explicit:
Matrix(Matrix const& other) = default; // rule of three
Matrix& operator=(Matrix const& other) = default; // rule of three
Matrix(Matrix&& other) = default; // rule of five
Matrix& operator=(Matrix&& other) = default; // rule of five
Analogously for Row class. Be aware that if you insist on using raw arrays inside then you will have to write all of these explicitly!
Transposing matrices could then be done via a free function again:
Matrix transpose(Matrix const& m)
{
Matrix t(m.columns(), m.rows());
// loops as you had
return t;
}
You could even provide a member function that transposes the matrix itself, best: use above transpose function:
template <typename T>
class Matrix
{
public:
void transpose()
{
Matrix t(transpose(*this));
t.data.swap(data); // cleanup of previously owned data done in t's destructor...
}
If you don't want to use any smart pointers and vectors, then try like this.
matrix - is a wrapper for 2D-dynamic array with size [col][row].
#include <iostream>
#include <algorithm>
using namespace std;
class matrix
{
private:
unsigned int m_row;
unsigned int m_col;
int **m_data;
public:
matrix(unsigned int row, unsigned int col) : m_row(row), m_col(col), m_data(nullptr)
{
alloc();
}
matrix(const matrix &m) : m_row(m.get_rows_count()), m_col(m.get_cols_count()), m_data(nullptr)
{
alloc();
for(unsigned int i = 0; i < m_row; i++)
for(unsigned int j = 0; j < m_col; j++)
m_data[i][j] = m[i][j];
}
~matrix()
{
free();
}
unsigned int get_rows_count() const { return m_row; }
unsigned int get_cols_count() const { return m_col; }
const int* operator[](unsigned int ind) const
{
return m_data[ind];
}
int* operator[](unsigned int ind)
{
return m_data[ind];
}
matrix& operator=(const matrix &m)
{
free();
m_row = m.get_rows_count();
m_col = m.get_cols_count();
alloc();
for(unsigned int i = 0; i < m_row; i++)
for(unsigned int j = 0; j < m_col; j++)
m_data[i][j] = m[i][j];
return *this;
}
// you need move-operations:
//matrix(matrix&& other) = delete; // move constructor (rule of 5)
//matrix& operator=(matrix&& other); // move assignment (rule of 5)
void print()
{
for(unsigned int i = 0; i < m_row; i++)
{
for(unsigned int j = 0; j < m_col; j++)
cout << m_data[i][j] << " ";
cout << endl;
}
}
private:
void alloc()
{
if(m_data)
return;
m_data = new int*[m_row];
for(unsigned int i = 0; i < m_row; i++)
{
m_data[i] = new int[m_col];
std::fill(m_data[i], m_data[i] + m_col, 0);
}
}
void free()
{
if(!m_data)
return;
for(unsigned int i = 0; i < m_row; i++)
delete[]m_data[i];
delete[]m_data;
m_data = nullptr;
}
};
matrix transpose(const matrix matrix_in)
{
unsigned int M = matrix_in.get_rows_count();
unsigned int N = matrix_in.get_cols_count();
matrix out(N, M);
for(unsigned int i = 0; i < M; i++)
for(unsigned int j = 0; j < N; j++)
out[j][i] = matrix_in[i][j];
return out;
}
int main(int argc, char* argv[])
{
matrix m1(5, 7);
m1[0][1] = m1[0][2] = m1[0][3] = 7;
auto m2 = transpose(m1);
m1.print();
cout << endl;
m2.print();
}
In any case, it is better to free the memory in the same place where it was allocated. If you do not want to use some classes, you can do it like this:
void transpose(int **matr_in, int **matr_out, int M, int N)
{
for(int i = 0; i < M; i++)
for(int j = 0; j < N; j++)
matr_out[j][i] = matr_in[i][j];
}
int **create_matrix(int M, int N)
{
int **m = new int*[M];
for(int i = 0; i < M; i++)
m[i] = new int[N];
return m;
}
void delete_matrix(int **m, int M)
{
for(int i = 0; i < M; i++)
delete []m[i];
delete []m;
}
int main()
{
int M = 5, N = 4;
int **m1 = create_matrix(M, N);
// fill matrix m1
int **m2 = create_matrix(N, M);
transpose(m1, m2, M, N);
delete_matrix(m1, M);
delete_matrix(m2, N);
return 0;
}
you provide a function return a pointer array which holds seperated memory blocks (each represents one row). then you must also provide the free (or delete) function at the same time, and in the same module (to ensure the memory managerment functions matches exactly).
int** transpose(int** matrix, int row, int column)
{
int** new_mat = new int*[column];
...
return new_mat;
}
//when free the mat, cols is not concerned;
void free_mat(int** matrix, int rows)
{
int i;
for(i= 0; i< rows; i++)
delete[] matrix[i];
delete[] matrix;
}
//use the function as:
int** m2 = transpose(m1, rows, cols);
...
free_mat(m2, cols);
//after free_mat(), m2 still holds the address.
//so make it nullptr.
m2 = NULL;
also you can allcate one plane continuous memory block to present 2-dimention matrix:
int* mat = new int[rows * cols];
//transfer mat[iRow][iCol] to mat[iRow * cols + iCol];
return mat;

how to copy Int array to int pointer using constructor in C++

I am trying to insert int array x to int *v. here is my code . please provide me with optimal solutions and the reason behind it.
there is an error in this line. Instead of copying array value its taking garbage value. line v1=x;
class vector
{
int *v;
int size;
public:
vector(int m)
{
v = new int[size = m];
for (int i = 0; i < size; i++)
v[i] = 0;
}
vector(int *a)
{
for (int i = 0; i < size; i++)
v[i] = a[i];
}
int operator *(vector &y)
{
int sum = 0;
for (int i = 0; i < size; i++)
sum += v[i] * y.v[i];
return sum;
}
void disp()
{
for (int i = 0; i < size; i++)
cout << v[i] << " ";
cout << "\n";
}
};
int main()
{
clrscr();
int x[3] = { 1,2,3 };
int y[3] = { 4,5,6 };
vector v1(3);
//v1.disp();
vector v2(3);
v2.disp();
v1 = x;
v1.disp();
//v2=y;
v2.disp();
int r = v1 * v2;
cout << "R = " << r;
getch();
return 0;
}
You forgot to add the assignment operator in your vector class:
vector & operator=(int *a)
{
for (int i = 0; i < size; i++)
v[i] = a[i];
return *this;
}
In the the line
v1=x;
May be, you are expecting it to invoke the second constructor which takes int* as argument. But it won't happen.
It can be seen as Type Conversion from Basic type to Class type. where we expect appropriate constructor will get invoked.
see http://www.hexainclude.com/basic-to-class-type-conversion/
But remember, Constructor will be invoked only once after the creation of object.
Here, in the line
vector v1(3);
the first constructor was already invoked. Then the line
v1=x;
won't invoke the second constructor now.
For every class, = operator is default overloaded . That is the reason why we can easily assign objects to one another.
Therefore, the line v1=x invokes default overloaded assignment = operator.
Here, it treats address of array x i.e., &x[0] as address of class object. As it is not address of vector class object
=> it results a Segmentation fault.
YOUR ANSWER
To assign int array to int pointer i.e., to the member variable int* v of the vector class,
overload assignment operator = inside the class .
or
Initialize the class object to array in first line itself. i.e.,
vector v1=x; // modify the class constructor to have size as a constant.

Initialize the element of multidimensional array

I've problem with Initialize the element of multidimensional array.
Here's my code:
class A{
int *const e;
const int row, column;
public:
A::A(int r, int c) : row(r), column(c), e(new int[r*c])
{
for (int i = 0; i < r*c; i++)
{
e[i] = 0;
}
}
A(const A &matrix) : row(matrix.row), column(matrix.column) ,e(new int[matrix.row*matrix.column])
{
for (int i = 0; i < matrix.row*matrix.column; i++)
{
e[i] = matrix.e[i];
}
}
virtual ~A() //destructing a A
{
delete[] e;
}
};
But when I'm trying Initialize the element of multidimensional array I've got a error:
int main(int argc, char* argv[])
{
A c(2, 5);
c[0][0] = 1;
A a(c);
return 0;
}
1 IntelliSense: no operator "[]" matches these operands operand types are: MAT [ int ]
Edit:
According to comments I try to write operator []
virtual int *const operator[ ](int r)
{
return e[r][0];
}
It should get first element of the r row. But I've got a error:
1 IntelliSense: expression must have pointer-to-object type
You're trying to apply the [] to the class A, C++ only knows how to use the operator [] on arrays. In order to use them for A you have to tell how [] works for A, so inside your class definition you should put:
int *operator[](int x){
return &e[x*row];
}
It basically receives the number you have put between brackets, and returns the corresponding row(an array), so you can apply [] again easily, so for example:
c[0] returns the first row
c[0][1] access the second element of the first row

Declare a multidimentional array without the size

I want to declare an array of arrays or multidimensional array without knowing the size.
I want to do something similar to what I did in this cases with simple arrays:
int *array;
cin >> size;
array = new int[size];
Maybe I can loop to initialize a pointer of pointers like this:
int **array;
cin >> rows >> col;
array = new *int[rows]
for (int i = 0; i < rows; ++i)
array[i] = new int[col];
But I would prefer to not do this if a better solution exists.
Why not use std::vector?
std::vector<std::vector<int> > array;
If you don't want to use an array of pointers, you could use one large array that you allocate dynamically after you get the size and access it as an array of rows.
int rows = 10;
int columns = 20;
int* array = new int[rows * columns];
for (int count = 0; count < rows; count++)
{
int* row = &array[count * columns];
for (int inner_count = 0; inner_count < columns; inner_count++)
{
int* element = &row[inner_count];
//do something
}
}
delete [] array;
You're pretty much going to have to go with the loop version. You can make one slight improvement, which is to allocate one big block and then build your own int* index into it:
int **array;
int *storage;
cin >> rows >> col;
array = new *int[rows];
storage = new int[rows*col];
for (int i = 0; i < rows; ++i)
array[i] = storage + col * i;
This has the nice property that you can still use array[i][j] syntax for accessing the array.
You could use a single std::vector to contain the entire two dimensional array and wrap it in a class to hide the details. Here's an example, it uses a data( row, col ) member function that returns a reference to the element at row and col. I included an example 2 dimensional matrix of int where each entry in the array is initialized to the product of its row and col. When an instance of this class goes out of scope, the default destructor will get called and release the memory, that way you don't have to remember to call delete[] to release the memory. All elements of the matrix will be contiguous in memory, this is cache friendly and should give you good performance.
#include <iostream>
#include <vector>
#include <stdexcept>
template <typename T>
class matrix {
std::vector<T> data_;
public:
size_t const rows_;
size_t const cols_;
matrix(size_t rows, size_t cols)
: rows_(rows)
, cols_(cols)
, data_( rows * cols )
{}
T& data( size_t row, size_t col ) {
if (row > rows_ || col > cols_) throw std::out_of_range("matrix");
return data_[ row * cols_ + col ];
}
};
int main( int argc, char** argv )
{
matrix<int> array(100,100);
for(size_t r=0; r < array.rows_; ++r) {
for(size_t c=0; c < array.cols_; ++c) {
array.data(r,c) = r * c;
}
}
std::cout << "8 x 7 = " << array.data(8,7) << std::endl;
return 0; // array goes out of scope here, memory released automatically
}
When you run this you will get
8 x 7 = 56
If you care, you can have a little bit more convenience by have a helper
template <typename T>
struct C3DArray
{
vector<vector<vector<T>>> m;
C3DArray(int size_x, int size_y, int size_z)
: m(make(T(), size_z, size_y, size_x))
{ }
template <typename U> static std::vector<U> make(U v, size_t n) {
return { n, std::move(v) };
}
template <typename U, typename... Dim> static auto make(U v, size_t n, Dim... other)
-> std::vector<decltype(make(v, other...))> {
return { n, make(v, other...) };
}
};
This uses variadics. Use it like this:
C3DArray<int> arr(3,4,20);

Memory loss when passed as an argument to a class in C++

I defined a class with a template that defines a generic array type T number of elements N. I have another class that has an instance of this array as a member. When I try using the setString function, the array I pass goes from 15 elements, to 4 elements, arbitrarily.
// testClassArraySize.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <istream>
#include <ostream>
using namespace std;
template<class T, int N>
class CArray {
public:
T arr[N];
CArray(void) {/*arr=(T *)malloc(sizeof(T)*N);*/
if (arr == NULL) {
cout << "allocation error\n";
}
}
;
//CArray (int n) {arr=new T [n]; if(arr==NULL){exit(0); cout<<"allocation error\n";}};
CArray operator=(const T *);
T operator[](const int i) {
return arr[i];
}
;
};
template<class T, int N>
CArray<T, N> CArray<T, N>::operator=(const T *srce) {
size_t x = sizeof(arr);
size_t y = sizeof(srce);
for (int j = 0; j < sizeof(arr); j++) {
if (j > sizeof(srce)) {
arr[j] = 0;
break;
}
arr[j] = srce[j];
}
return *this;
}
class myTestClass {
private:
CArray<char, 15> myString;
public:
myTestClass setString(char set[15]) {
myString = set;
size_t x = sizeof(set);
return *this;
}
;
};
int main() {
myTestClass myObject;
myObject.setString("helloWorld");
return 0;
}
Does anyone have any idea why?
This has a couple of issues, but the one you'll probably see is the line
CArray<T, N> CArray<T, N>::operator= (const T *srce)
Note: const T* source is a pointer, therefore sizeof(srce) is the size of the pointer. I guess you're using a 32 bit system?
sizeof gives you the size of an object (i.e. a "region of storage"). For arrays, that is the size of the whole array in bytes. sizeof( int[10] ) == sizeof(int) * 10. A pointer is itself an object, with a size depending on the C++ implementation (OS, compiler and so on). On 32 bit systems, it typically is 4 byte. sizeof( char* ) therefore is 4 byte, not the length of the array you passed to the function, that is sizeof( (char*)(char[10]) ) still is 4 byte, not 10.
Another issue you may see (but only by debugging / tracing) is that setString(char set[15]) is resolved to setString(char* set). Therefore x = sizeof(set) resolves to x = sizeof(char*) which is typically 4.
You pass "helloWorld" to setString, which is expecting a 15-item char arraychar*; I would say this is not a good idea since "helloWorld" has type char const[10] (note the const).
The correct syntax for taking a 15-char array is char (&set)[15].
You can do this more elegantly if you add a template member function like:
// in class CArray
template < std::size_t length >
CArray& operator= (const T (&srce)[length]); // note I return a reference, so no copying
This way, you'll get the array size as a template argument. Note: since I used const T here in the assignment op, you'll need to enforce const also in setString.
template < class T, int N >
template < std::size_t srce_length >
CArray < T, N >& CArray < T, N > :: operator= (const T (&srce)[srce_length])
{
for (int j = 0; j < N; j++) { // N is the own length
if (j >= srce_length) { // note the >= instead of >, and srce_length instead of sizeof
arr[j] = 0;
break;
}
arr[j] = srce[j];
}
return *this;
}