Delete pointer to multidimensional array in class through another pointer - how? - c++

I have a pointer to a class, that have a pointer to a multidimensional array but I can't seem to delete it from memory when I need to or set it to NULL.
#define X 10
#define Y 10
struct TestClass
{
public:
int *pArray[X][Y];
};
// different tries, none working:
delete Pointer_To_TestClass->pArray[0][0];
delete[] Pointer_To_TestClass->pArray[0][0]
// or by simply:
Pointer_To_TestClass->pArray[0][0] = NULL;
I know the array has data because I can see the results on screen.
Also check if it's NULL already, then doesn't try to delete it.
Since I want to delete a pointer in another pointer - is this a special circumstance that works differently? Like it deletes the first pointer holding the other pointer instead of the pointer inside the pointer (pArray is the second pointer, Pointer_To_Testclass is the first pointer)
UPDATE/EXPLANATION
I want to be able to delete pArray[0][0] while pArray[0][1] still exists and if [0][0] doesn't exist it should be equal to NULL. Most because I want to access this array by [X][Y] values for easy access. If [0][0] is a pointer, it should be NULL when deleted so I can check if it is NULL.
Anyone has any ideas?

If you want a 2D array of pointers to <whatever>, create a class to handle that, then put an instance of it in your TestClass. As far as how to do that, I'd generally use something on this order:
template <class T>
class matrix2d {
std::vector<T> data;
size_t cols;
size_t rows;
public:
matrix2d(size_t y, size_t x) : cols(x), rows(y), data(x*y) {}
T &operator()(size_t y, size_t x) {
assert(x<=cols);
assert(y<=rows);
return data[y*cols+x];
}
T operator()(size_t y, size_t x) const {
assert(x<=cols);
assert(y<=rows);
return data[y*cols+x];
}
};
class TestClass {
matrix2d<int *> array(10, 10);
public:
// ...
};
Given that you're storing pointers, however, you might want to consider using Boost ptr_vector instead of std::vector.

#define X 10
#define Y 10
struct TestClass
{
public:
TestClass()
{
// Must initialize pArray to point to real int's otherwise pArray
// will have bogus pointers.
for (size_t y = 0; y < Y; ++y)
{
for (size_t x = 0; x < X; ++x)
{
pArray[x][y] = new int;
}
}
}
int *pArray[X][Y];
};
int main()
{
TestClass *Pointer_To_TestClass = new TestClass;
delete Pointer_To_TestClass->pArray[0][0];
Pointer_To_TestClass->pArray[0][0] = 0;
return 0;
}

Depends on your allocation of pArray[i][j]. If it's something like pArray[i][j] = new int; then call delete Pointer_To_TestClass->pArray[0][0];. If it's something like pArray[i][j] = new int[10] then use your second option, delete[] Pointer_To_TestClass->pArray[0][0];. I'd also highly recommend immediately following the delete with setting it to NULL and proceeding it with the check for NULL.
The third one did not compile for me delete[][] Pointer_To_TestClass->pArray[0][0]; I got the error
Line 34: error: expected primary-expression before '[' token
compilation terminated due to -Wfatal-errors.
Also, I'd highly recommend having those deletes in the destructor. Other places may be fine as well.
You may find the typedef of int* to be helpful for readability understanding you have a two-dimensional array of int*.

If you've dynamically created an array, then delete it with delete[]. You have to give delete[] a pointer to the start of the array, however, not an element of the array!
If you want the elements to be deletable, then they have to be dynamically allocated separately.
So you have to have a multi-dimensional array of pointers;
int *(*pArray)[X][Y];
Then dynamically assign each one, which yes is a pain.
It is interesting, however, that you are even attempting to do this, why do you want to delete single elements?

Related

C++ : Using a int pointer to point to a vector created inside a function

I am still perfecting the art of posting here so bear with me, I will edit and fix anything suggested!
I have a homework that requires me to create functions that manipulate vectors. The "catch" is that all the data passed to the function is passed by reference to this struct:
struct Vector { // this struct must stay as is
int sze = 0; // "size" took out i for compatability
int capacity = 0;
int * data = nullptr ;
}a,b,c;
i.e.
void construct_vector ( Vector& v, int size= 0, int initVal= 0);
The problem that I am having is in the function construct_vector() I have to, you guessed it, construct a vector and use int* data to point to the vector on the heap? I am not positive about that last part). I just know I have to use the int pointer to point to the vector created within the construct function, and cannot for the life of me figure out how to do that.
An example of what I am trying:
void construct_vector ( Vector &v, int size, int initVal){
std::vector<int> t(size,initVal);
*v.data = &t ; // ERROR: Assigning to 'int' from incompatible type 'std::vector<int> *'
v.capacity = size; //
v.sze = size;
for (int i=0; i < t.size(); i++){
/* I originally tried to implement a
dynamic int pointer here but I cannot change int* data
to int*data[sze] within the struct*/
}
}
The reason int * data must point to the vector is because the data is passed to the subsequent functions by reference to struct member v:
void destroy_vector ( Vector & v );
void copy_data ( Vector & v );
Edit: My problem was that I misunderstood the objective of my assignment but I think the answers I received can really help people understand dynamic memory and how it should be used within functions. So I am going to leave everything as is!
You have two problems here:
std::vector<int> t(size,initVal);
*v.data = &t ; // ERROR: Assigning to 'int' from
First, *v.data and &t are different types, one is int, the other is a pointer to a vector of ints.
You can get it compile with (but you SHOULD NOT, see the second problem)
v.data = t.data();
The other problem is the vector is local to the function. As soon as the function returns, your pointer will dangle.
So the right solution for your problem is using a dynamic array:
v.data = new int[size];
Don't forget to delete[] it in the struct's destructor when you are done using it:
delete [] data;
Instead of
std::vector<int> t(size,initVal);
*v.data = &t ;
You need
v.data = new int[size];
To fill up the object with the input value, use
for ( int i = 0; i < size; ++i )
{
v.data[i] = initVal;
}
You can use std::fill to make your code a bit simpler.
std::fill(v.data, v.data+size, initVal);
Make sure to follow The Rule of Three when you manage dynamic memory yourself.

Choose at runtime array or vector in C++

I have a problem described as below ::
class datad {
private:
int *a;
int _size;
vector<int> v;
public:
datad(int arr[], int size) {
_size = size;
for (int i = 0; i < size; i++)
a[i] = arr[i];
}
datad(vector<int> ve)
{
v = ve;
_size = ve.size();
}
void printdata()
{
// print data which the object has been initialized with
// if object is initialized with vector then print vector
// array print array
}
};
int main()
{
// print only vector data
int a[] = { 9,4,8,3,1,6,5 };
datad d(v1);
d.printdata();
// print only array data
datad d1(a, 7);
d1.printdata();
}
I need to find the way the object is initialized and then based on the same should be able to printdata accrodingly.
Can someone help me understand if it is possible at all?
Add a bool usesVector to your class and set it to true or false in each constructor as appropriate. Then, in printdata, simply check the value of the boolean.
Or you can set size to -1 in the vector case (as it's otherwise unused) and just check for that.
By the way, your array implementation is broken, because you never allocate any memory for it. You'd be much better off using only the vector version. You can still initialise that vector from array data if you wish.
You can set a flag in respective constructor and check that flag during the printing method.
I hope this is for learning purposes, otherwise as noted you maybe better of using just the vector version. When using dynamic memory management in class you need to be aware of things like rule of three and I guess there is also rule of five.

Is new int[][] a valid thing to do in C++?

I have come across some code which allocates a 2d array with following approach:
auto a = new int[10][10];
Is this a valid thing to do in C++? I have search through several C++ reference books, none of them has mentioned such approach.
Normally I would have done the allocation manually as follow:
int **a = new int *[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
If the first approach is valid, then which one is preferred?
The first example:
auto a = new int[10][10];
That allocates a multidimensional array or array of arrays as a contiguous block of memory.
The second example:
int** a = new int*[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
That is not a true multidimensional array. It is, in fact, an array of pointers and requires two indirections to access each element.
The expression new int[10][10] means to allocate an array of ten elements of type int[10], so yes, it is a valid thing to do.
The type of the pointer returned by new is int(*)[10]; one could declare a variable of such a type via int (*ptr)[10];.
For the sake of legibility, one probably shouldn't use that syntax, and should prefer to use auto as in your example, or use a typedef to simplify as in
using int10 = int[10]; // typedef int int10[10];
int10 *ptr;
In this case, for small arrays, it is more efficient to allocate them on the stack. Perhaps even using a convenience wrapper such as std::array<std::array<int, 10>, 10>. However, in general, it is valid to do something like the following:
auto arr = new int[a][b];
Where a is a std::size_t and b is a constexpr std::size_t. This results in more efficient allocation as there should only be one call to operator new[] with sizeof(int) * a * b as the argument, instead of the a calls to operator new[] with sizeof(int) * b as the argument. As stated by Galik in his answer, there is also the potential for faster access times, due to increased cache coherency (the entire array is contiguous in memory).
However, the only reason I can imagine one using something like this would be with a compile-time-sized matrix/tensor, where all of the dimensions are known at compile time, but it allocates on the heap if it exceeds the stack size.
In general, it is probably best to write your own RAII wrapper class like follows (you would also need to add various accessors for height/width, along with implementing a copy/move constructor and assignment, but the general idea is here:
template <typename T>
class Matrix {
public:
Matrix( std::size_t height, std::size_t width ) : m_height( height ), m_width( width )
{
m_data = new T[height * width]();
}
~Matrix() { delete m_data; m_data = nullptr; }
public:
T& operator()( std::size_t x, std::size_t y )
{
// Add bounds-checking here depending on your use-case
// by throwing a std::out_of_range if x/y are outside
// of the valid domain.
return m_data[x + y * m_width];
}
const T& operator()( std::size_t x, std::size_t y ) const
{
return m_data[x + y * m_width];
}
private:
std::size_t m_height;
std::size_t m_width;
T* m_data;
};

I allocate memory for a Pair object but fail to place the object there

I would like to have a dynamic array of pointers to pointers to Pair elements;
int m_size = 0;
Pair** ar = new Pair*[++m_size];
*ar[0] = Pair(key, data);
Here I get:
Unhandled exception at 0x013729db in lab3.exe: 0xC0000005: Access violation writing location 0xcdcdcdcd.
It happened in the overloaded operator for MyString (HERE marks when the exception threw):
MyString & MyString::operator = (const MyString & refMyString){
HERE: this->m_pStr = refMyString.m_pStr;
return *this;
}
My classes (a bit simplified for our purpose):
class Pair{
MyString m_key;
Data* m_data;
}
class MyString
{
char* m_pStr;
}
And here is what I get in the debugger:
http://sdrv.ms/ZwkZ9P
http://sdrv.ms/17eoGp6
Well, as far as I can see, when I did Pair** ar = new Pair*[++m_size], a new pointer to pointer to a space for a Pair instance was created. But it is just space in memory. And when I try to operate it, I fail.
And what to do is a mystery to me. Could you help me?
You allocate an array of Pair* but :
1) You never initialize the pointers in that array
2) You dereference those uninitialized pointers (which point to who-knows-where) and overwrite the memory there.
No wonder you get a segfault since you're writing to unallocated memory.
What you (probably?) want to do is:
ar[0] = new Pair(...)
Or better yet, use a standard container (vector, list, deque, ...) instead of C arrays, that will either contain plain objects or smart pointers (unique_ptr or shared_ptr) so that you don't have to manage the memory yourself.
When creating a two dimensional array using a double pointer, you need to allocate both dimensions:
// allocates an array of 10 int* objects
int** p = new int*[10];
for(int x = 0; x < 10; ++x)
{
// Allocates an array of 3 integers
p[0] = new int[3];
}
You would need to ensure that all of the objects you are creating are deleted:
// later
for(int x = 0; x < 10; ++x)
delete [] p[x];
delete [] p;
I would suggest however, just using std::vector so you don't need to manage the memory yourself:
std::vector<std::vector<int>> p;
p.resize(10);
for(int x = 0; x < 10; ++x)
{
p[x].resize(3);
}

Deleting in C++

struct item
{
unsigned int a, b, c;
};
item* items[10];
delete items[5];
items[5] = NULL;
The above code works
But the below method is not working
int * arr1[30];
delete (arr1+5);
I am a beginner, Please tell me why I am able to delete in case of structure pointer but not in case of int
pointer
You're seemingly misunderstanding what delete is for: it's purely and simply to release memory allocated by new, not to 'delete' elements of arrays.
So you might use it like this:
int *p = new int;
//...
delete p;
When you allocate arrays, you must instead use delete[], like this:
int *q = new int[23];
//...
delete [] q;
But at no point should you try and delete something that hasn't been new'ed, or use the non-matching version of delete, e.g. delete [] p; or delete q; above.
If what you really want is some sort of 'array' from which you can remove elements, try this:
#include <vector>
struct item
{
unsigned int a, b, c;
};
int main()
{
std::vector<item> items(10);
items[5].a = 23;
items.erase(items.begin() + 5);
return 0;
}
Are you allocating heap memory anywhere? You are not doing so in the code above. You are lucky that the first delete does not crash.
When using the (arr1+5) approach, you are passing the memory address of the array slot itself at index 5, not the int* that the slot contains. To delete the int* that is contained in the slot at index 5, you have to dereference the pointer value, eg:
delete *(arr1+5);