Constructing an array of class attribute in a different class C++ - c++

I have to do a project where one class Row has an array of integers int* OneArray and then another class Array has an array of the first class Row* TwoDArray. In essence the class has a 2D array on integers, and I can easily do the construction of the 2D array when it is in one class. However, now I am completely stumped.
The construction of the Row is simple enough:
//set length of array
numOfRows = intRows;
//Create space for array
OneArray = new int[intRows];
//populate array with random numbers
for(int i=0; i<intRows; i++)
{
OneArray[i] = GenerateRandom(9,0);
}
This is where I am stuck (Construction of Array):
//Set Number of Cols
NumOfCol = intCols;
//create length for each row
int intLength = 4;
for(int i=0; i<NumOfCol; i++)
{
//create space and call row constructor with length
TwoDArray = new Row(intLength);
//increase length for jagged array
intLength++;
}
As it is now it writes over the current array after each for loop (which is expected). So, I need to index TwoDArray like TwoDArray[i], but as soon as I try to do that then I get this error:
"invalid user-defined conversion from 'Row*' to 'const Row&'."
Note: If I take the line out of the for loop only the first array is made and not until intCol. intLength is increasing because I technically need a jagged array which has got different sizes in each array.
My classes look like this:
class Row
{
public:
//Constructors
Row();
Row(int intRows);
Row(const Row& objPrev);
//Accessors
int getNumOfRows();
int getRowArray(int intRow);
//Mutators
void setRowArray(int intRow, int intChange);
//Destructor
~Row();
private:
int* OneArray;
int numOfRows;
}
and
class Array
{
public:
//Constructors
Array();
Array(int intRows, int intCols);
Array(const Array& objPrev);
//Accessors
int getNumOfCol();
Row getTwoDArray(int intCol, int intRow);
//Mutators
void setTwoDArray(int intCol, int intRow, int intChageTo);
//Destructor
~Array();
private:
Row* TwoDArray;
int NumOfCol;
}
Any Help or suggestions are appreciated.

With your loop in Array you allocate a single Row object multiple times, overwriting the pointer in each loop. That leads to a memory leak as only the last will be available through the variable TwoDArray. Also, at the end of the loop all you will have is an "array" of only a single element, the last allocated Row object.
The problem is that you can't do the array allocation using new[] at the same time as you call a specific constructor. You can not do e.g.
TwoDArray = new Row[NumOfCol](intLength);
Instead you have to split the allocation and initialization into two parts:
TwoDArray = new Row[NumOfCol]; // Allocates memory, default constructed Row objects
for (int i = 0; i < NumOfCol; ++i)
{
TwoDArray[i] = Row(intLength); // Initialize each element
}
This of course requires you follow the rules of three or five (or zero) for the copying in the loop to work.

Related

Why do I have to free 2D array twice to avoid memory leak?

I am running into a memory leak problem when allocating a 2D array.
But I could not understand why the memory leaks.
My reasoning is that at Note A, I have already freed allocated memory, since data_[0] == data_, why do I have to do the free at Note B?
class Matrix {
public:
Matrix(int r, int c) {
this->rows = r;
this->cols = c;
data_ = new int*[r];
for (int i = 0; i < r; i++) {
data_[i] = new int[c];
}
}
~Matrix() {
for (int i = 0; i < this->rows; i++) {
delete [] data_[i]; // Note A;
}
delete[] data_; // Note B; <-- not doing this line will leak memory, but why?
}
private:
int rows;
int cols;
int **data_;
};
What you post there isn't really a 2D array, it's a 1D array-of-pointers (data_), and then you allocate a separate array-of-ints for each element of the first array (so data_[0] is an array of c ints, data_[1] is an array of c ints, and so on).
Given that, it's natural that you'll have to do one delete[] in your destructor for each new that you performed earlier in your constructor.
A graphical diagram of your memory allocations and how they point to each other might look like this (if c==6 and you have set all of your arrays' integers to 0):
A real 2D array allocation would look like this: int * array2D = new int[6][8];, but of course C++ only supports 2D arrays if the array-dimenions are compile-time constants, so that probably wouldn't solve the problem your Matrix class is meant to solve.
When you have created 2D array (for example 3x3), you have created 1 array with 3 elements, where each element is pointer to separate array. So to clear memory for this matrix you need to clear 4 arrays (3 rows and 1 array containing pointers).
You can check how many times in your code you are calling new operator
it will be r+1 times
data_ = new int*[r];// 1 time
for (int i = 0; i < r; i++ {
data_[i] = new T[c]; // r times
}
Part I:
The line data_ = new int*[r]; allocates and default initializes a dynamic array of int* through new, so you would need to provide a corresponding delete [] data_; for this line.
Part II:
The line data_[i] = new int[c]; dynamically allocates and default initializes an int array and then the pointer to that first element is returned and stored as the data_[i] element. So here again you would need a corresponding delete [] data_[i]; to get rid of the memory leak.
So these were the reasons why you need two separate delete []. The process is as shown in the screenshot. Also note that the important thing is the default initialization. So the int array elements will not all have a value 0 as wrongly shown in the answer by #Jeremy Friesner.

Adding two array objects with operator overloading resulting in segmentation fault

I'm setting up a class in c++ that will have array objects and a function to add them together (by adding their individual components). Each of these objects has a pointer to a 'new' array of floats which will be added together. I believe that either because these are pointers or are assigned to 'new' arrays, there is some sort of memory issue when accessing their components through the overloaded + operator, but I'm not sure what specifically is the issue. The file compiles without any issues but simply says "Segmentation fault (core dumped)" when run. Also I'm aware I should be using a min value rather than max in the for loop but right now all my arrays are the same size so I'm just testing it this way.
If I comment out the actual addition of the arrays in main(), the error message completely disappears, but I'm not quite sure why.
#include <iostream>
using namespace std;
class Array
{
private:
int size, location;
float value;
public:
float *arrayptr;
Array(int size)
{
arrayptr = new float[size];
}
void setValue(int location, float value)
{
arrayptr[location] = value;
}
Array operator+(Array a)
{
int max;
if (a.size >= size)
{
max = a.size;
}
else
{
max = size;
}
Array tmparray(max);
for(int i=0; i<max; i++)
{
tmparray.arrayptr[i] = a.arrayptr[i] + arrayptr[i];
}
return tmparray;
}
};
main()
{
Array a1(3);
a1.setValue(0, 1.0);
a1.setValue(1, 22.0);
a1.setValue(2, 12.2);
Array a2(3);
a2.setValue(0, 3.3);
a2.setValue(1, 44.5);
a2.setValue(2, 21.7);
Array tmp(3);
// Source of the error (parenthesis doesn't seem to affect it):
tmp = (a1 + a2);
}
You don't set size in the constructor, so when if (a.size >= size) happens, you get undefined behavior. Probably gets set to some ludicrous value and you walk off the array.
m_size = size Set the member size value to the size value passed into the constructor.
The + operator also doesn't watch out for walking off the array when the arrays are not the same size.
You had not Initialize size variable.
You need to Initialize it.
Array(int _size)
{
size = _size;
arrayptr = new float[size];
}
And your size variable is private.
So, it can't reference. So size variable need to declare as public.

C++ Set 2d array sizes of class member array in constructor

I only found solutions for 1d arrays, but couldn't apply them to 2d arrays.
The possible solutions included "vectors", "templates", and "pointers to arrays".
I know I can get vectors to work, but I would rather use either of the other 2. Preferably templates because I don't want to manually destruct, but pointers work too. (the pointer would be pointed to an array created in the constructor).
The class contains an empty 2d array called screen. The constructor is supposed to set its size. I tried too many things for me to list them all here, but I'll show what I currently have. (last thing i tried were pointers to arrays created in the constructor. in this case screen was a char pointer)
Screen::Screen(const int w, const int h) : screen(new char[h][w]) {} {
width = w;
height = h;
}
array size in new-expression must be constant
I failed implementing either of those strategies and received many kinds of errors while trying to make it work. How would I solve this problem? (primarily I want to know how to do this with templates. if not possible then with pointers to arrays created in the constructor)
The question was a little ambiguous, but it sounds like you want to dynamically allocate an array given some input.
Edit I changed the answer to match the code you provided. This creates a 2d array of chars given the height and width.
class Screen {
private:
char **data;
int rows;
int columns;
public:
Screen(int num_rows, int num_cols);
};
Screen::Screen(int num_rows, int num_cols) {
data = new char * [num_rows];
for (int i = 0; i < num_rows; ++i) {
data[i] = new char[num_cols];
}
rows = num_rows;
columns = num_cols;
}
This creates an empty 2D array of chars.
Explanation: All arrays in c are just pointers to the first block in memory of the type you have declared. By having the member variable as double pointer, you have an array of char pointers, which each point to the first value in each of their respective arrays.
BUT be careful, you WILL need to free the data variable to avoid memory leaks, by declaring a destructor.
Screen::~Screen() {
for (int i = 0; i < rows; ++i) {
delete[] data[i];
}
delete[] data;
}

push a 2D array into a vector and delete the array, but cause segmentation fault

I have a class named Matrix. There is a 2D array in the class to save the data.
template <class Type>
class Matrix{
public:
Matrix(int row, int col){
rows = row; cols = col;
data = new Type*[rows];
for(int i = 0; i < rows; i++){
data[i] = new Type[cols];
}
}
public:
int rows;
int cols;
Type **data;
};
And I have a vector to save the Matrix. Every time I have a Matrix, I will push back the matrix in this vector for future calculation. In order to avoid memory leak, I want to delete the Matrix after pushing it back to the vector. But if I don't delete it, the program works; if I delete it (as shown in the code below), the program will show the segmentation fault when I want to do some calculation for this vector. The code I used is shown below
vector<Matrix<int>> v;
for(int i = 0; i < 10; ++i){
Matrix<int> a(3,3);
...... // I fill the elements of a.data
v.push_back(a);
for(int j = 0; j < a.rows; ++j)
delete[] a.data[j];
delete[] a.data;
}
Hope I have explained my problem clearly. If anything makes you confuse, please comment me.
Thanks for help!!!
I see multiple problems in your code:
it's C++ and you are manually allocating memory for the matrix, why?
even if you have access to destructors you don't implement it but you delete data for the matrix manually in the main code
your approach doesn't manage memory clearly, when you push_back by value, the Matrix is copied inside the vector, who owns the pointers for the data at this point? The copy on stack or the copy inside the vector?
You should take care of carefully manage memory by implementing a correct copy constructor, copy assignment operator and destructor for the class.
But this is irrelevant since you can just use C++ features and forget about these problems, some solutions:
Store pointers in the vector
class Matrix{
public:
Matrix(int row, int col){
rows = row; cols = col;
data = new Type*[rows];
for(int i = 0; i < rows; i++){
data[i] = new Type[cols];
}
}
~Matrix() { // you need a destructor
for (int i = 0; i < rows; ++i)
delete[] data[i];
delete data;
}
public:
int rows;
int cols;
Type **data;
};
std::vector<std::unique_ptr<Matrix>> v;
Matrix* matrix = new Matrix(3,3);
v.push_back(std::unique_ptr<Matrix>(matrix));
Now matrices become persistent but they'll get automatically released when v goes out of scope (thanks to unique_ptr and destructor)
Use a std::vector / std::array for matrix elements
You are using them to store multiple matrices, why don't you use them also for matrix itself?
template<size_t ROWS, size_t COLS, class TYPE>
class Matrix
{
std::array<std::array<COLS, TYPE>, ROWS> data;
...
}
Now everything is automatically managed, you don't need to release memory and you don't need a destructor for Matrix at all.
std::vector<Matrix<3,3,float>> v;
Matrix<3,3,float> m;
v.emplace_back(m);
m.data[0][0] = 1;
If you want to have different sizes of matrices in same vector or if you want to keep stack usage low (since std::array is not dynamically allocated) then use a std::vector instead that an std::array so that you can remove the template arguments.
Your Matrix class doesn't have a proper copy constructor so when you push the new matrix to the vector all the fields are copied to a new created Matrix inside the vector.
AND Matrix::data is also copied as a pointer. Which means that the new Matrix inside the vector points to the same Matrix a that you created in the for loop. Thus, when you delete a you actually make the Matrix inside the vector invalid.
OP's problem is a classic Rule of Three violation.
The class uses raw pointers to memory allocated by the constructor
Matrix(int row, int col)
{
rows = row; cols = col;
data = new Type*[rows];
for(int i = 0; i < rows; i++)
{
data[i] = new Type[cols];
}
}
The destructor deletes all of the memory so there will be no leak.
~Matrix()
{ // you need a destructor
for (int i = 0; i < rows; ++i)
delete[] data[i];
delete data;
}
However, there are no copy or move constructors or assign or move operators, so the defaults will simply copy the pointers, resulting in two objects pointing to the same memory.
Not only are both copies modified when one is changed, but when one is deleted, the other copy's pointers are rendered invalid.
This is generally seen as bad.
Solution one is create copy and move constructors and assignment and move operators, but that is a bit of work to get right.
Thankfully, std::vector gets it right out of the box.
template<class Type>
class Matrix{
public:
Matrix(int row, int col):rows(row), cols(col), data(rows, std::vector(cols))
{
// does nothing. All of the heavy lifting was in the initializer
}
// no longer need a destructor.
public:
int rows;
int cols;
std::vector<std::vector<type>> data;
};
The next bit I suggest as a performance enhancement. Because the vector of vectors is literally a vector containing other vectors, it's not all in one memory block. Having to jump around in RAM to find the next bit of data can be costly. Look up Cache Miss and Spatial locality to see why.
template<class Type>
class Matrix{
public:
Matrix(int row, int col):rows(row), cols(col), data(rows*cols)
{
// does nothing. All of the heavy lifting was in the initializer
}
// no longer need a destructor.
//add a convenience method for easy access to the vector
type & operator()(size_t row, size_t col)
{
return data[row*cols+col];
}
type operator()(size_t row, size_t col) const
{
return data[row*cols+col];
}
private: // note change of access to private Best to keep ones data to one's self
int rows;
int cols;
std::vector<type> data;
};
Now your're safe for stuff like:
std::vector<Matrix<float>> v;
Matrix<float> m(3,3);
v.emplace_back(m);
m(0,0) = 1;

C++ Pointer of Array of Ints Initialization

I want to have an array accessible by all functions of a class.
I put the array as private variable in the header file.
private:
int* arrayName;
In the .cpp file where I implement the class, the constructor takes in an int value (size) and creates the array. The goal is to fill it up
ClassName::ClassName(int numElements){
arrayName = new int[numElements]; //make arrays the size of numElements
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
}
I feel like this is quite inefficient. I know you can do int array[5] = {0}; but how do you do it when you don't initially know the size.
If you want to zero-initialize a newed array, just do value-initialize it. This has the effect of zero-initializing its elements:
arrayName = new int[numElements]();
// ^^
But you really want to be using an std::vector<int>.
private:
std::vector<int> vname;
and
ClassName::ClassName(int numElements) : vname(numElements) {}
This way you don't have to worry about deleting an array and implementing copy constructors and assignment operators.
You can use the memset function:
memset(arrayName,0,sizeof(int)*numElements);
This void * memset ( void * ptr, int value, size_t num ); function sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).
To use it you must include the string.h header file.
For more information: http://www.cplusplus.com/reference/cstring/memset/
What you want to do is progressively expand the array on demand.
arrayName = new int[numElements];
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
The above code (what you gave) will give you an array of size numElements, and THEN the for loop will fill it. This is allocated now, and can't, as I understand it, be simply or easily resized (memset will overwrite previously held values in the array).
You could copy the whole array over every time you want to resize it:
int * oldarr = new int[OldSize];
//fill your old array
int * newarr = new int[NewSize];
for(int i = 0; i<OldSize; i++)
newarr[i] = oldarr[i];
Other than that, you could make the array much larger, or you could use various STLs, such as std::vector. Vector can be increased with a simple push_back function, and allows [] operator access (like arr[5] and whatnot).
Hope this helps!