I just need to be sure I have enough memory available to the bi-dimensional array map. So I think I'd have to put a try catch bad:alloc in every row of map or perhaps with no throw would be more elegant. But I can't get with it. Any help would be appreciated...
I've read some articles about writing something like:
map[i] = new int [columns];
if (map[i] == NULL)
cout << “No enough memory”;
I don't like this solution and I've read that is not very reliable one.
fillmaze is a function called inside the constructor of maze..
void Maze::setupMaze(int r, int c, int l){
rows = r;
columns = c;
level = l;
fillMaze();
addBorders();
centerWalls();
getaway();
addWalls();
}
void Maze::fillMaze(){
map = new int* [rows];
for (int i = 0; i < rows; i++) {
map[i] = new int[columns];
}
//Inicializamos toda la tabla
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
map[i][j] = PASSAGE;
}
}
}
Also delete [] map is not enough right ? I'm doing in the destructor of the class:
Maze::~Maze(void)
{
for (int i = 0; i < rows; ++i)
delete[] map[i];
delete[] map;
}
This is why you should use std::vector<> as it will handle all the memory management for you correctly.
Issue 1: new never returns NULL (for pedants the normal new as used below). Also note in C++ we use nullptr not NULL for type safety.
map[i] = new int [columns];
if (map[i] == NULL) // This will never be NULL
cout << “No enough memory”; // So this will never print anything.
If fillmaze() is called from the constructor. Then if it throws an exception your destructor is never called. This means you have to deal with any allocation failure in place.
map = new int* [rows]; // could throw.
for (int i = 0; i < rows; i++) {
map[i] = new int[columns]; // could throw
}
So you have to handle and be able to detect what has been allocated and thus what needs to be dallocated.
try
{
map = nullptr; // Init to nullptr to make sure
// you can distinguish between valid state
// and what could have randomly been in memory.
map = new int* [rows]{nullptr}; // Initialize all elements to nullptr.
// If any throw you don't want your code
// to start releasing random pointers.
// calling delete on nullptr is fine.
for (int i = 0; i < rows; i++) {
map[i] = new int[columns]{PASSAGE};
}
}
catch(...) // catch all exceptions.
{
if (map != nullptr) { // You should only loop over
// map if it has been allocated.
for (int i = 0; i < rows; i++) {
delete [] map[i];
}
}
delete [] map; // delete the map.
throw; // rethrow exception
}
Your destructor is dine.
But you can simplify this by simply using a vector:
std::vector<std::vector<int>> maze{std::vector<int>{PASSAGE, columns}, rows};
Related
I'm trying to delete my 2D array, but I consistently get errors when I try to delete it, we have to work backwards so I delete the elements first, then the column array, then the row array. here is my code for the constructor in my class, MyMatrix:
private:
int m; //rows
int **ptr; //ptr to first dimension
int n; // columns
public:
MyMatrix() //constructor
{
m = 0;
n = 0;
ptr = new int*[m];
int *length_arr = new int[m];
for (int i = 0; i <= m-1; i++)
{
*(ptr+i) = new int[n];
*(length_arr+i) = n;
}
}
and my destructor looks like this:
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
the error I'm getting is:
assg7(2677,0x100de3d40) malloc: *** error for object 0x12d606804: pointer being freed was not allocated
I've wracked my brain for where I can fix this, for context, I'm doing an assignment with operator overloading. I specifically need a delete function to work properly for my = assignment overloading since I want to delete and again reallocate memory to equate two matrices, but the terminal is showing malloc errors and is thus not equating the matrices.
for additional info here is my = overloading code:
void operator = (const MyMatrix &obj)
{
if(n == obj.n && m == obj.m)
{
//for loop to equate elements in this-> to the elements of the passed object
}
else
{
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
// the code for assigning new memory according to the passed objects rows and colums goes here
//then for loop to equate elements in this-> to the elements of the passed object
}
}
thanks.
You have two "levels" of new, so three "levels" of delete can't be right.
Spell out your deletion loop, using indexing instead of pointer arithmetic:
First iteration:
delete ptr[0]+0;
delete ptr[0]+1;
...
delete ptr[0]+n-1;
delete [] ptr[0];
Second iteration:
delete ptr[1]+0;
delete ptr[1]+1;
...
delete ptr[1]+n-1;
delete [] ptr[1];
You're passing to delete a pointer to the first element of ptr[0], a pointer to the second element of ptr[0], a pointer to the third element of ptr[0], ...
But the things you allocated were ptr[0], ptr[1], ... ptr[m-1], not their individual elements.
Remove the innermost deletion loop.
(And don't mess around with pointer arithmetic when you can use indexing.)
I don't know how you would want to allocate memory space by m length if it is set to 0 by default.
To me it looks like you set m = 0 and then try to allocate by 0 length or how do you control the length of your dimensions?
Maybe edit your constructor to:
MyMatrix(int m, int n)
{
this->m = m;
this->n = n;
...
So for a project I have i need to create a function to 'Resize' the first dimension of a dynamically allocated 3d array of shorts, the function cant alter the original data and must only alter the first dimension of the array.
3darray[alter this][stays the same][stays the same]
The variables passed into the function are the pointer that points to the 3d array, the old size, and the new size.
Ive tried this:
void reallocShort3d(short ***&ptr, size_t oldSize, size_t newSize)
{
short *** temp;
temp = (short***) realloc(ptr,(newSize - oldSize) * sizeof(ptr));
ptr = temp;
}
but it does not seem to be working, any idea on where i went wrong and possible solutions?
Thanks
EDIT: I realise that I can't use realloc now as th 3d array was created with new, we are only given the old and new sizes of the first dimension and the array itself, we are not allowed to use vectors:
/**
* #brief reallocates/resizes a 3D array of shorts to fit into a new size.
* Size here refers to the first dimension. i.e. ptr[size][row][col].
*
* #note after the function executed, the original data in the array must
* not be altered in any way. That is to say, only the first dimension of
* ptr may be altered.
*
* #NOTE! this function must work in general
*
* #param ptr is the pointer that refers to the 3D array to be resized.
* #param oldSize is the current total number of elements in the first
* dimension of ptr. e.g. ptr[this amount here][row][col]
* #param newSize is the new size that ptr will have after the function
* has been executed. ptr[the new amount here][row][col]
*/
SECOND EDIT:
Heres the code used to allocate the 3d array:
ptr = new short**[2];
for (int i = 0; i < 2; i++)
{
ptr[i] = new short*[12];
for (int j = 0; j < 12; ++j)
{
ptr[i][j] = new short[numDaysinMonth(j)];
}
}
Given the way OP's code allocates the memory, a simple way to resize it is:
short ***tmp;
// in OP's code rows = 12 while the inner dimension is the number of days in a month
// so we can use cols = 31
tmp = new short**[newSize];
// copy the old data
for ( size_t i = 0; i < oldSize; ++i ) {
tmp[i] = ptr[i];
}
// allocate memory for the new data
for ( size_t i = oldSize; i < newSize; ++i ) {
tmp[i] = new short*[rows];
for ( size_t j = 0; j < rows; ++j ) {
tmp[i][j] = new short[cols];
}
}
delete[] ptr;
ptr = tmp;
EDIT
The comment of #PaulMcKenzie points out a major flaw in this code. In C++, operator new throws an exception when it's unable to allocate the requested memory. If this happens, our options are limited and in most cases the only thing we can do is some clean up and exit the program.
In the following snippet I'll try to rewrite the function with OP's signature (which I personally, don't like) and to avoid the possible memory leaks. This function eventually rethrows a std::bad_alloc exception and it is up to the caller to deal with it (which, I'm pretty much sure, OP's code doesn't).
I'd like to remark that a far better practice would be to stick to the Standard Library containers and/or encapsulate all the memory managment in a class, to ensure RAII.
void reallocShort3d(short ***&ptr, size_t oldSize, size_t newSize, size_t rows, size_t cols ) {
short ***tmp = nullptr;
std::bad_alloc ee;
try {
tmp = new short**[newSize];
size_t i = 0, j = 0, ii, jj, kk;
for ( ; i < oldSize; ++i ) {
tmp[i] = ptr[i];
}
for ( ; i < newSize; ++i ) {
try {
tmp[i] = new short*[rows];
for ( j = 0; j < rows; ++j ) {
try {
tmp[i][j] = new short[cols];
}
catch ( const std::bad_alloc &e ) {
for ( jj = 0; jj < j; ++jj ) {
delete[] tmp[i][jj];
}
delete[] tmp[i];
throw e;
}
}
}
catch ( const std::bad_alloc &e ) {
for (ii = oldSize; ii < i; ++ii) {
for ( jj = 0; jj < rows; ++jj ) {
delete[] tmp[ii][jj];
}
delete[] tmp[ii];
}
delete[] tmp;
throw e;
}
}
delete[] ptr;
ptr = tmp;
}
catch ( const std::bad_alloc &e ) {
std::cout << "Error: unable to reallocate.\n";
throw e;
}
}
As alluded to in the comments, the signature of the reallocate function is not sufficient for the general case as one requires knowledge of the rows, cols and slices of the original 3D array to be able to perform reallocation.
So, assuming you can fix the method signature for the general case the following is a possible solution:
void reallocate_short_3d_arr(short***& ptr, std::size_t new_rows, std::size_t old_rows,
std::size_t cols, std::size_t slices) {
// allocate memory for tmp 3d arr
short*** tmp = new short**[new_rows];
for (std::size_t i = 0; i < new_rows; ++i) {
tmp[i] = new short*[cols];
for (std::size_t j = 0; j < cols; ++j)
tmp[i][j] = new short[slices];
}
// select correct rows for contraction or expansion of ptr
std::size_t tmp_rows = (new_rows > old_rows) ? old_rows : new_rows;
// copy all entries from ptr to tmp
for (std::size_t i = 0; i < tmp_rows; ++i) {
for (std::size_t j = 0; j < cols; ++j) {
for (std::size_t k = 0; k < slices; ++k)
tmp[i][j][k] = ptr[i][j][k];
}
}
// delete original ptr memory
for (std::size_t i = 0; i < old_rows; ++i) {
for (std::size_t j = 0; j < cols; ++j) {
delete[] ptr[i][j];
}
delete[] ptr[i];
}
delete[] ptr;
// assign ptr to tmp such that ptr points to reallocated memory
ptr = tmp;
}
One could probably optimise this via using std::move to assign the contents of ptr to tmp instead fairly trivially as the original ptr contents is deleted afterwards anyway so it is safe to move it.
Of course, this is all very silly C++ though and could be easily achieved via std::vector as follows:
std::vector<std::vector<std::vector<short>>> vec_3d(rows,
std::vector<std::vector<short>>(cols,
std::vector<short>(slices))); // initialise "3D vector" of dims rows*cols*slices
vec_3d.resize(new_rows); // resize just the rows, leaving slices and columns the same
I think I got the general idea of how to create and destroy it, but I can not find the way to access each of the objects. Here's how I create it:
CCyIsoPktInfo **arrayOfPointers = new CCyIsoPktInfo*[QueueSize];
for (int i = 0; i < QueueSize; ++i)
{
arrayOfPointers[i] = new CCyIsoPktInfo[PACKETS_PER_TRANSFER];
}
Here's how I destroy it:
for (int i = 0; i < QueueSize; ++i)
{
delete[] arrayOfPointers[i];
}
delete[] arrayOfPointers;
But I need to access each nth_Object.status in the array, given the nth_Pointer to that array. So the general idea would be like this:
for (int nth_Object = 0; nth_Object < PACKETS_PER_TRANSFER; ++nth_Object)
{
var[nth_Object] = (*arrayOfPointers[nth_Pointer]).[nth_Object].status;
}
I am creating and destroying the them properly? How to access the elements?
To iterate over your 2D array, you would use a nested loop, for example
for (int nth_Object = 0; nth_Object < QueueSize; ++nth_Object)
{
for (int nth_Pointer = 0; nth_Pointer < PACKETS_PER_TRANSFER; ++ nth_Pointer)
{
std::cout << arrayOfPointers[nth_Object][nth_Pointer].status;
}
}
Although for what it's worth, I would recommend using std::vector instead of dynamically allocating your own arrays
std::vector<std::vector<CCyIsoPktInfo>> data;
Then you could iterate like
for (auto const& row : data)
{
for (auto const& element : row)
{
std::cout << element.status;
}
}
In main I can:
Node* myNodeArray2[myHeight][myWidth];//Does not call constructor
for(int i=0; i<myHeight; i++){
for(int j=0; j<myWidth; j++){
theNodeArray[i][j] = new Node("ThisIsTest", 5, 5);
}
}
So for the above code myHeight and myWidth can be user input at run time. It does not call the default constructor and I can use the new operator and go through the array creating the objects.
I want to be able to pass Node* myNodeArray2 to a function and let it create the array size and populate it. When it is created I want the elements to be pointers. I don't want to call the default constructor. I want to be able to at my choosing call the new operator with the non-default constructor.
When I try:
void Test(Node*& theNodeArray, int myHeight, int myWidth){
theNodeArray = new Node*[myHeight][myWidth];
}
int main(){
Node* myNodeArray;
Test(myNodeArray, myHeight, myWidth);
}
I get that
"myWidth is not a constant expression."
I have tried a couple of different methods but cannot get what I want. I need the creation to happen in a separate function. I need to be able to define the size at runtime. Any help?
Edit:
I don't want to use std::vector.
Edit 2:
I don't want to do this
int** ary = new int*[sizeX];
for(int i = 0; i < sizeX; ++i)
ary[i] = new int[sizeY];
As this forces the rows to be of objects of contiguous memory space. I want to allocate a 2d array of pointers. I do not want to necessarily create the objects that will be pointed to.
You may use the following:
Node*** MakeArrayNodePtr(int myHeight, int myWidth){
Node*** res = new Node**[myHeight];
for (int i = 0; i != myHeight; ++i) {
res[i] = new Node*[myWidth]();
}
return res;
}
And don't forget
void DeleteArrayNodePtr(Node*** nodes, int myHeight, int myWidth)
{
for (int i = 0; i != myHeight; ++i) {
// And probably:
/*
for (int j = 0; j != myWidth; ++j) {
delete nodes[i][j];
}
*/
delete [] nodes[i];
}
delete [] nodes;
}
Okay, so here's the context. I've been up for almost a day straight now working on the legendary 8-puzzle problem. I have my heuristics down and my A_star algorithm down. We are required by the project spec to solve it using three different heuristic values. I can solve it for any one of the three individually, but when I go to solve them in succession, I get a ridiculous loop, and it never finds the correct successor state.
I believe my problem is with my pointers. I have a class, State, as defined below that has an int** array and a pointer to a State (its parent).
EDIT: I have to use int** as defined by the project specification, otherwise I would gladly use a pointer.
State (int **bd, State* prnt);
State (const State& other);
~State ();
I am then declaring them as such:
State::State(int **bd, State* prnt) {
// allocate the board
board = new int*[3];
for (int i = 0; i < 3; i++) {
board[i] = new int[3];
}
// fill in the board
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = bd[i][j];
//board[i][j] =
}
}
// set the parent
parent = prnt;
}
State::State(const State& other) {
// allocate the board
board = new int*[3];
for (int i = 0; i < 3; i++) {
board[i] = new int[3];
State::~State() {
//std::cout << "Deconstructing " << this << endl;
for (int i = 0; i < 3; i++)
delete board[i];
delete [] board;
delete parent;
parent = other.parent;
}
State::~State() {
//std::cout << "Deconstructing " << this << endl;
for (int i = 0; i < 3; i++)
delete board[i];
delete [] board;
delete parent;
}
State& State::operator=(const State &rhs) {
if (&rhs == this) {
return *this;
}
for (int i = 0; i < 3; i++) {
delete board[i];
}
delete [] board;
// allocate the board
board = new int*[3];
for (int i = 0; i < 3; i++) {
board[i] = new int[3];
}
// fill in the board
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//board[i][j] = rhs.board[i][j];
board[i][j] = rhs.getIntAtCoor(j, i);
}
}
//delete parent;
// set the parent
parent = rhs.parent;
// set g
g = rhs.g;
f = rhs.f;
hType = rhs.hType;
return *this;
}
I don't give the exact declarations -- some of it is simple like int = int. I just can't quite figure it out. I feel like either my delete parent is wrong or my parent = other.parent is wrong (or both).
Thank you for your time and help,
Tyler
Upgrading your code-style may force the errors to evaporate. In other words new and delete are error prone and should be avoided when better alternative exists.
For management of the cells consider:
std::shared_ptr: can be used to void the delete calls
std::vector can be used to avoid the new and delete calls
Note you should use it like std::vector<int> board( 3 * 3 ) and board.at( x + y * 3 ).
And best of all just use a static array int board[3][3]. No allocation at all.
Also child states do not own their parent states. It's the other way around. So child states shouldn't delete their parents. You can still safely keep a parent pointer, but make sure you cleanup the children before you allow a parent to go out of scope (deleted or otherwise). All of this cleaning and deleting doesn't neccessarily involve new at all. Your State class looks small enough that is doesn't matter if they are copied by value. In which case just have the parent use a std::vector<State> m_children and the compiler will take care of the rest.
You don't show the full definition of the copy constructor but I assume that the parent = other.parent line is in there. In that case, wouldn't the parent be responsible for its own lifetime and the delete parent in the destructor shouldn't exist at all.
Also note that you need to at least disable (private declaration) or implement the copy assignment operator.
Better still, use a vector of vector for your 2d array and let the language work for you.
Perhaps not a direct answer, but you are going against best practices for C++.
It's easier and definitely more maintainable to use vectors for this problem.
size_t row_sz = 3;
size_t col_sz = 3;
std::vector<int> board(row_sz * col_sz, 0);
int i = 0;
for (size_t r = 0; r < 0; r++)
for (size_t c = 0; c < 0; c++)
board[ r * row_sz + c ] = i++;
Multidimensional arrays are much easier handled with the above strategy as well. It just breaks less. If you really want the row/col access, write a wrapper around it.
struct Matrix {
int &operator()(size_t r, size_t c);
const int &operator()(size_t r, size_t c) const;
private:
std::vector<int> data;
};