proper memory allocation for a 2D array in a class in C++ - c++

I am writing a C++ class that uses some fixed arrays, as well as some dynamically allocated arrays.
I was wondering if anybody can guide me for the proper way to allocate memory for the dynamic arrays , probably in the constructor/deconstructor, and also if I need to explicitly call them to make sure I don't get a seg fault.
Here is a simplified version of the related part of my code:
class Network {
public:
int n_nodes;
int user_index[MAX_USERS]; //a fixed array
int adjacency_matrix[][MAX_ITEMS];
//Network(int n_node, int** adjacency); //I would rather to set the element s in a function other than the constructor
Initializer(int n_node, int** adjacency);
~Netowrk();
}
So here are my specific question for this class:
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
2 - where should I delete the 2D array? should I write it in the deconstructor? Should I call the deconstructor explicitly? Is there anything else I need to destroy in the deconstructor?

1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
Yes. The best way to do this, however, is not to use arrays at all. Instead, use std::vector, which manages the memory for you. There are two ways that you can do this. If you actually want to be able to use the [row][column] syntax to access elements, you'll need to use two dimensions of std::vectors:
std::vector<std::vector<int> > adjacency_matrix;
Once you know the dimensions, you can populate it:
adjacency_matrix.assign(rows, std::vector<int>(columns));
It is often easier to use a single-dimensional array (or a std::vector<int>) containing all of the elements and use row * row_count + column to access the element at index (row, column). This way, there are fewer dynamic allocations. You can wrap up the logic of accessing elements into a couple of helper functions.
2 - where should I delete the 2D array? should I write it in the deconstructor?
You don't have to delete anything if you use a std::vector. It cleans itself up.
Should I call the [destructor] explicitly?
No.
Is there anything else I need to destroy in the [destructor]?
Ideally, no. If you use the Standard Library containers, like std::vector and smart pointers, you shouldn't have to clean anything up. You should avoid trying to manage resources on your own in C++: there are library facilities to do this tedious task for you and you should take advantage of them.

1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
Yes you can. For example:
int* adjacency_matrix_;
int* getAdjacency(int i, int j)
{
if (!adjacency_matrix_)
return 0;
else
return adjacency_matrix_ + i*n_nodes + j;
}
Network()
: n_nodes(0),
adjacency_matrix_(0)
{}
void Initializer(int n_node, int** adjacency)
{
adjacency_matrix_ = new int[n_nodes * n_nodes];
// Copy over data.
}
As to whether you should, that depends on whether you have a reason for not using std::vector<>.
2 - where should I delete the 2D array? should I write it in the deconstructor?
Should I call the deconstructor explicitly?
Is there anything else I need to destroy in the deconstructor?
Yes, definitely free in the destructor using array operator delete:
~Network()
{
delete [] adjacency_matrix_;
}
No, your destructor will be called whenever the Network object itself goes out of scope. It is (very) rarely necessary to make an explicit destructor call.
No, all a destructor needs to explicitly release is whatever your explicitly acquire.

You may like the example matrix class I wrote in an answer to another question
The question itself was about good C++ design practices, but the chosen example was a multi-dimensional array.

There are several ways to do this.
The easiest way is to use vectors, and if you don't like to manage your own memory, this is perfect for you. However, because I like to manage my own memory, and I have found this method to be slow and cumbersome at times, I have learned of other ways.
The fastest way is to allocated a one dimensional array and treat it as you would a two dimensional array. Here is an example:
int *array = new int[width*height];
int get_array(int column, int row)
{
return array[row*width + column];
}
delete [] array;
This can be generalized to the nth-dimension:
int *array = new int[w1*w2*...*wn];
int get_array(int i1, int i2, ..., int in)
{
return array[in*(w1*w2*...*w(n-1)) + i(n-1)*(w1*w2*...*w(n-2)) + ... + i2*w1 + i1];
}
delete [] array;
If you want to be able to have different widths for each row, then you can make an array of pointers. This solution is slow to initialize and clean up, but flexible, tunable, and has relatively fast execution time. It can also be extremely dangerous if you make a mistake though.
int **array = new int*[height];
for (int i = 0; i < height; i++)
array[i] = new int[width(i)];
at which point, to access it, all you have to do is the customary
array[i][j]
however, to free this array you have to do it row by row
for (int i = 0; i < height; i++)
delete [] array[i];
delete [] array;
This can also generalize to the nth dimension.
int **....*array = new int**...*[w1];
for (int i1 = 0; i1 < w1; i1++)
{
array[i1] = new int**..*[w2];
for (int i2 = 0; i2 < w2; i2++)
{
array[i1][i2] = new int**.*[w3];
...
for (int in = 0; in < wn; in++)
array[i1][i2]...[in] = new int[wn];
}
}
for (int i1 = 0; i1 < w1; i1++)
{
for (int i2 = 0; i2 < w2; i2++)
{
...
for (int in = 0; in < wn; in++)
delete [] array[i1][i2]...[in];
...
delete [] array[i1][i2];
}
delete [] array[i1];
}
delete [] array;
This kind of setup tends to wreak havoc on memory. Just a two dimensional array of these would result in width+1 separate arrays to be malloc-ed. It would be faster to just malloc one big array and figure out the indices yourself.

Related

Dynamic 2D array without using new

I've been posed with creating a dynamic 2D array in C++ without using new in C++. I have been trying for a while to make something work but I'm clueless as to what I'm supposed to do.
Edit: Sorry, should have been more specific. Just to be transparent, yes it is homework, and no I don't want it solved I just want to be pointed (no pun intended) in the right direction to code it myself.
The order, for reference, is as follow: Develop a console application to create a type int matrix of size m x n using pointers. The user must input the values for the size of the matrix from the keyboard and its contents must be randomly generated (1 - 100). Then, the transpose of the matrix must be calculated and shown (it's necessary to create classes).
We can't use new, nor vector, as we have to do it just via pointers with uni-dimensional arrays. So far I created a class that represent the "rows", and another class which represents the "columns". The columns go into the rows and the rows go into another class called matrix. That was the idea but was having trouble implementing it.
new is the only way to create dynamic objects or arrays in standard C++. So, depending on how you interpret the task, it could be considered impossible.
If we assume that it is OK for you to call a standard function that internally calls new, then the problem is solvable. A commonly used way to create a dynamic array in C++ is to use std::vector. Elements of std::vector may not be arrays however, so a 2D dynamic array is not technically possible using it. One workaround is to wrap the array within a class, and use the class as element of the vector. There is a standard template for such array wrapper: std::array. An example of a vector of array wrappers:
std::vector<std::array<type_of_element, 10>> name_of_vector(number_of_arrays);
The elements of the arrays within the dynamic array managed by the vector will have effectively the same layout as a 2D array would.
malloc did the trick. Here is the code I used to test it. It was a bit convoluted to figure out how to write the matrix loop but once I got it down I realized how obvious it was.
Matriz::Matriz(int numFil, int numCol)
:numFil(numFil), numCol(numCol)
{
mat = (int *)malloc(numFil * numCol * sizeof (int));
int c = 0;
for(int i = 0; i < numFil; i++)
{
for(int j = 0; j < numCol; j++)
{
*(mat + i * numCol + j) = ++c;
}
}
}
void Matriz::printMat()
{
for(int i = 0; i < numFil; i++)
{
for(int j = 0; j < numCol; j++)
{
std::cout << *(mat + i*numCol + j);
}
std::cout << std::endl;
}
}

Creating a temporary array with pointers C++

I was wondering if this is the proper way create a temporary array using pointers in a class. Part of my problem says this:
getMedian – returns the median value of the array. See Chapter 10 Programming Challenge 6 (p. 693) for a discussion of the term median. Taking the median will require a sorted array. You will need to create a temporary array to sort the values (to preserve the ordering of numbers). Do not sort the private member numbers array. Dynamically allocate/deallocate a temporary array in your getMedian function to determine the median.
My code:
double Statistics::getMedian() const
{
int tempArray[length];
for (int k = 0; k < length; k++){
tempArray[k] = numbers[k];
}
bubbleSort(tempArray);
return 0;
}
Before obviously doing the median part and a proper return statement, is this.
How you properly copy over a temporary array to alter for this problem? I don't think it is because I'm not properly allocating or deallocating anything, but I don't understand how to create a temporary array without altering the original.
Your assignment says you are to allocate/deallocate the array dynamically. That means (in C++) using new and delete. Since you want an array, you should use array space allocator operators new[] and delete[].
double Statistics::getMedian() const
{
int *tempArray = new int[length];
for (int k = 0; k < length; k++){
tempArray[k] = numbers[k];
}
// work with tempArray
delete[] tempArray;
return 0; // or the median
}
EDIT:
As suggested in the comment below, modern (C++11 and newer) way is to use smart pointers. That would mean your code could look like this.
#include <memory>
double Statistics::getMedian() const
{
std::unique_ptr<int[]> tempArray (new int[length]);
for (int k = 0; k < length; k++){
tempArray[k] = numbers[k];
}
// work with tempArray like you would with an old pointer
return 0; // or the median
// no delete[], the array will deallocate automatically
}
Check unique_ptr template class for more details. Note that this solution might not be what your professor wants, especially when the assignment talks about deallocation.

How do I deallocate this in C++?

I create a 2D array of Nodes (Node class is in a separate file) and i'm wondering how to deallocate exactly this (below). I've tried many ways and mem leaks still appear.
board = new Node * [r];
//creats a column for each element in the row
for(int i = 0; i < r; i++) {
board [i] = new Node [c];
}
(r is the rows and c is the cols)
I've done this:
for(int i = 0; i < r; i++) {
delete [] board[i];
}
delete [] board;
But apparently it's not enough
The code you have is correct and sufficient. However, it would be better to use RAII so that you do not need to explicitly call delete at all (perhaps not even new). For example, you could create a std::vector<std::vector<Node>>, or better still, some sort of matrix class (not in the standard library, unfortunately).
Your solution is the correct way to free two dimensional array. However you may still get a memory leak if Node uses dynamic memory and it's destructor is not properly defined.
As others have said, you're correctly pairing up all your new[]s and delete[]s: assuming no errors occur, the memory allocated by this code will be correctly deallocated.
The only issue is that errors may occur, and in particular exceptions may be thrown:
new[] can throw an exception if it fails to allocate memory (doesn't normally happen on desktop OSes, but you should still write code as if it does.)
Node's constructor may throw. Even if you've designed the constructor not to throw you generally shouldn't take advantage of that knowledge. Just write code as if throws.
In fact, you should just generally write code as if pretty much anything can throw. For more detailed info on writing exception safe code, and on what the exceptions to this rule are you can read the info at http://exceptionsafecode.com
The best way to make this code exception safe is to use RAII. For example use a vector instead of new[]/delete[].
Using an array of pointers and a separate allocation for each row makes sense for 'ragged' arrays, where each row can be a different length. In your case you have rectangular array, so you can use a single allocation for the whole thing.
std::vector<Node> board(rows*columns);
board[row_index*columns + column_index] // replaces board[row_index][column_index]
You can hide the implementation by putting this in a class:
class Board {
std::vector<Node> board_data;
public:
const int rows;
const int columns;
Board(int rows_, int columns_)
: board_data(rows_*columns_)
, rows(rows_)
, columns(columns_)
{}
struct board_index { int row, column; };
Node &operator[](board_index i) {
assert(0 <= i.row && i.row < rows);
assert(0 <= i.column && i.column < columns);
return board_data[i.row * columns + i.column];
}
};
Board board(r, c);
with the above implementation you replace board[i][j] with board[{i, j}].
board[{i, j}] = ... // assign to a place on the board
board[{i, j}].foo(); // call a Node method
std::cout << board[{i, j}]; // print a Node
// etc.

creating an array of object pointers C++

I want to create an array that holds pointers to many object, but I don't know in advance the number of objects I'll hold, which means that I need to dynamically allocate memory for the array. I have thought of the next code:
ants = new *Ant[num_ants];
for (i=1;i<num_ants+1;i++)
{
ants[i-1] = new Ant();
}
where ants is defined as Ant **ants; and Ant is a class.
Will it work?
Will it work?
Yes.
However, if possible, you should use a vector:
#include <vector>
std::vector<Ant*> ants;
for (int i = 0; i < num_ants; ++i) {
ants.push_back(new Ant());
}
If you have to use a dynamically allocated array then I would prefer this syntax:
typedef Ant* AntPtr;
AntPtr * ants = new AntPtr[num_ants];
for (int i = 0; i < num_ants; ++i) {
ants[i] = new Ant();
}
But forget all that. The code still isn't any good since it requires manual memory management. To fix that you could to change your code to:
std::vector<std::unique_ptr<Ant>> ants;
for (auto i = 0; i != num_ants; ++i) {
ants.push_back(std::make_unique<Ant>());
}
And best of all would be simply this:
std::vector<Ant> ants(num_ants);
std::vector<Ant> ants(num_ants);
ants.resize(new_num_ants);
Yes that's the general idea. However, there are alternatives. Are you sure you need an array of pointers? An array of objects of class Ant may be sufficient. The you would only need to allocate the array:
Ant *ants = new Ant[num_ants];
In general, you should prefer using std::vector to using an array. A vector can grow as needed, and it will handle the memory management for you.
In the code you have posted, you would have to delete each element of ants in a loop, and then delete the array itself, delete [] ant. Keep in mind the difference between delete and delete [].
One more point, since array indices in C++ are 0-based, the following convention is used to iterate over the elements:
for (i=0; i<num_ants; i++)
{
ants[i] = new Ant();
}
This makes code much more readable.
Do you really need to hold pointers to the items? If you can use objects by value, a far simpler approach is to use a vector: std::vector<Ant> ants(num_ants);. Then not only do you not have to write looping, but you don't have to worry about memory leaks from raw pointers and other object management items.
If you need object pointers to say satisfy an API you can still use vector for the outer container and allocate the objects manually.
struct CreateAnt
{
Ant* operator()() const { return new Ant; }
};
std::vector<Ant*> ants(num_ants); // Create vector with null pointers.
std::generate(ants.begin(), ants.end(), CreateAnt());
std::vector<Ant*> ants( num_ants );
for ( int i = 0; i != num_ants; ++ i ) {
ants[i] = new Ant;
}
Or if you don't know how many in advance:
std::vector<Ant*> ants;
while ( moreAntsNeeded() ) {
ants.push_back( new Ant );
}
On the other hand, I think you need to ask yourself whether
Ant is an entity type or a value. If it's a value, you'll
probably want to skip the pointers and the dynamic allocation;
if it's an entity type, you'll have to consider the lifetime of
the object, and when and where it will be deleted.

How do you delete (or fill with specific values) a static n-dimension array?

const int ROWS = 3;
const int COLUMNS = 4;
void fillArray(double a[ROWS][COLUMNS], double value);
void deleteArray(double a[ROWS][COLUMNS]);
int main () {
double a[ROWS][COLUMNS];
fillArray(a, 0);
deleteArray(a);
}
In C++, how do you delete (or fill with specific values) a static n-dimension array?
In C++ we generally do not use arrays. We use std::vector.
You can use memset or std::fill to fill the array with specific values.
BTW you can use delete on dynamically allocated arrays not on static ones.
memset( a, 0 ,ROWS * COLUMNS * sizeof( double ));
or
std::fill(&a[0][0], &a[0][0]+sizeof(a)/sizeof(double), 0);
You can delete only an object created by new (and that object will be allocated in the heap). What do you mean by "deleting a static POD variable"? It has no sense:
1) It doesn't have any destructor to perform additional tasks before freeing the memory,
2) The stack memory will be "freed" as you exit the current block.
And to set it: either loop, either simple memset(a, 0, sizeof(a)); .
Also, the array in your example is not static.
std::vector is what is generally used for C++ arrays (especially when you're new at it). One of vector's constructors will fill it for you to:
std::vector<type> myVector(initialSize, defaultValue);
If you want multidimensional, you could do a vector of vectors, or boost::multi_array:
boost::multi_array<type, numberOfDimensions> myArray(boost::extents[firstSize][secondSize][thirdSize]);
In that case, you'll need to use the multiple-for-loops approach, because it doesn't seem to have a constructor that does that.
EDIT: Actually you can use std::vector to make a multidimensional array with default values:
std::vector<std::vector<double> > a(3, std::vector<double>(4, 0));
Where 3 is the number of rows, 4 is the number of columns and 0 is the default value.
What it's doing is create a vector of vectors with 3 rows, where the default value for each row is a vector with 4 zeroes.
Filling arrays in C++ is the same as filling them using C, namely nested for loops
int i, j;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
a[i][j] = 0
Arrays aren't "deleted" but they can use free if they've been allocated on the heap (if they've been allocated on the stack within a function, this is unnecessary).
int i;
for (i = 0; i < ROWS; i++)
free(a[i]);
free(a);
Firstly, the code you posted seems confused. What is it that you think "deleteArray" is supposed to do? 'a' is an auto variable and therefore cannot be deleted or freed.
Secondly, wrap your array in a class. There is a nice one in the FAQ that you can start with, but it can be improved. The first improvement is to use a vector rather than newing a block of memory. Then std::fill can be used to fill the array.
Use std::fill
#include <algorithm>
And then your implementation is simply:
std::fill(&a[0][0], &a[0][0]+sizeof(a)/sizeof(a[0][0], value);
You don't delete the array since it is stack allocated.