Is this extra step necessary when freeing dynamically allocated memory - c++

During the expansion of a dynamically allocated array, I find myself writing this :
void HPQueue::expandCapacity() {
char **prevArray = array;
capacity *= 2;
array = new char*[static_cast<size_t>(capacity)];
for (int i = 0; i < capacity; i++) {
array[i] = new char;
}
for (size_t i = 0; i < count; i++) {
array[i] = prevArray[i];
LINE XX: delete prevArray[i]; <----------- This line seems to be the problem, Since it also deletes array[i]
}
delete[] prevArray;
}
But this line is necessary if initially the constructor looks something like this:
HPQueue::HPQueue::() {
capacity = INITIAL_CAPACITY;
array = new char*[static_cast<size_t>(logSize)];
for (int i = 0; i < logSize; i++) {
array[i] = new char;
}
count = 0;
}
Note :
/* instances variables */
char **array;
size_t count;
Is this LINE XX: not necessary ?

No, you shouldn't be calling new char for the first count elements of array. You should be copying from the first count elements of prevArray.
You don't need to call new char at all. If you use nullptr instead, you can still safely delete[] array[i] when you remove an element.
But you shouldn't be doing this. In order of preference:
Use std::vector<std::string> array, it does all this for you.
Use std::unique_ptr<std::unique_ptr<char[]>[]> array; std::size_t capacity; and reassign with array = std::make_unique<std::unique_ptr<char[]>[]>(capacity); and move with std::move(prevArray.get(), prevArray.get() + count, array.get());
Use char **array; std::size_t capacity;, reassign with array = new char*[capacity]; and move with std::copy_n(prevArray, count, array);
So if you are required to go with the last one, you get
HPQueue::HPQueue()
: capacity(INITIAL_CAPACITY),
array(new char*[INITIAL_CAPACITY]),
count(0)
{
std::fill_n(array, capacity, nullptr);
}
void HPQueue::expandCapacity() {
char **prevArray = array;
capacity *= 2;
array = new char*[capacity];
auto pos = std::copy_n(prevArray, count, array);
std::fill_n(pos, capacity - count, nullptr);
delete[] prevArray;
}

Related

Creating a custom vector class. Push_back function only working for the first value

In my Comp Sci class, we are learning how to make our own vector class. We will eventually store our custom made string class objects in a custom made vector class. I wanted to try and build a vector class of integers beforehand for simplicity.
So far, I have a default constructor that initializes my pointer to an empty array and sets the size to 0. Then I try to append some values using my push_back function and then check to make sure it was done correctly.
When I do std::cout << v[0] << std::endl;
I get the correct output (10). However, if I call push_back again and then call v[1] I get 0.
I feel like I am not allocating memory correctly in my push_back function but I am not sure.
Thanks for any advice!
[part 1][1]
[part 2][2]
sorry if my formatting is wrong I am new to posting here.
class:
class myVector
{
private:
int *data; //will point to an array of ints
size_t size; //determins the size of array
public:
myVector(); // default constructor
void push_back(int); // appends an integer to the vector
int operator[](size_t);
size_t sizeOf();
};
main:
int main()
{
myVector v;
v.push_back(10);
std::cout << v.sizeOf() << std::endl;
v.push_back(14);
std::cout << v.sizeOf() << std::endl;
std::cout << v[1] << std::endl;
return 0;
}
member functions:
size_t myVector::sizeOf()
{
return size;
}
int myVector::operator[](size_t location)
{
return this->data[location]; //this will return the value at data +
//location
}
myVector::myVector()
{
this->data = new int[0]; //initialize the data to an empty array of
//ints
size = 0; //initialize the size to 0
}
void myVector::push_back(int val)
{
if(size == 0) //if size == 0, create a new array with 1 extra index
{
++size;
delete [] this->data;
this->data = new int[size];
this->data[0] = val;
}
else
{
++size;
int *temp = new int[size - 1];
for(int i = 0; i != (size - 1); i++)
{
temp[i] = this->data[i];
}
delete [] this->data;
this->data = new int[size];
for(int i = 0; i != (size - 1); i++)
{
this->data[i] = temp[i];
}
this->data[size] = val;
delete [] temp;
}
}
In your code:
this->data[size] = val;
you are going outside of the allocated array.
Same in the previous loop (in its last iteration):
for(int i = 0; i != (size - 1); i++)
{
this->data[i] = temp[i];
}
There are a few problems.
It does not look like you need a special case for 0 sized vector
you do not allocate enough memory:
Example, if size is one, you hit this case, then size becomes 2, and you allocate a buffer of ... 1.
else
{
++size;
int *temp = new int[size - 1];
for(int i = 0; i != (size - 1); i++)
{
temp[i] = this->data[i];
}
Tip: use ```for (int i = 0; i < size; ++i)``` and ```new int[size]```
you go out of bounds after your loop. If you allocate [size] bytes, then (size-1) is the last valid index.
you copy data into temp, then copy temp into ANOTHER allocation. You don't need to do that. Just assign this->data = temp; The whole second loop is needless, and don't delete temp at the end.
Its not necessary to a lot of new and delete operations and loops. I fixed and cleaned your two functions.
myVector::myVector()
{
this->data = new int[1]; //initialize the data to an empty array of
//ints
size = 0; //initialize the size to 0
}
void myVector::push_back(int val)
{
if(size == 0) //if size == 0, create a new array with 1 extra index
{
++size;
this->data[0] = val;
}
else
{
++size;
int *temp = new int[size];
for(int i = 0; i != (size-1); ++i)
{
temp[i] = this->data[i];
}
delete [] this->data;
this->data = temp;
this->data[size-1]=val;
}
}
in push_back function allocate a new array with new size and copy data from existing array. After deleting existing array and we see this->data can't point to valid location. Assign the new array's address to this->data and we access existing data and size increased +1. Last we assign parameter val to end of array(size-1).

How to delete the last element from array with pointers in C++?

I try to build a function which deletes the last element of an array. So I need an input array and its dimension, then delete the last term and obtain a new output array. I don't want that. My goal is to somehow make the output array the new input array. In other words, I want to overwrite the input array with the output array.
So if dimension is 4, I don't want to have a 4-dim array in the memory but only 3-dim table after the deletion.
void del (int* ptr_array, int dim) {
int* temp = ptr_array; //Hold the very first address of the input array.
ptr_array = new int[dim - 1]; // Let the address of the input array be
// the address of new output array. Overwritting.
for (int i = 0; i < dim - 1; i++) {
ptr_array = (temp+i); // Will it remember what is temp+1 if I have
// already overwritten the arrays?
ptr_array++;
}
//delete[] ptr_array; - this one is out of the questions - deletes now the input table.
}
Can you tell me what is wrong with this code? - in fact it doesn't change anything
in you function
for (int i = 0; i < dim - 1; i++) {
ptr_array = (temp+i); // Will it remember what is temp+1 if I have
// already overwritten the arrays?
ptr_array++;
}
does nothing, you wanted
for (int i = 0; i < dim - 1; i++) {
ptr_array[i] = temp[i];
}
Note the delete in your comment is invalid because you do not delete the result of a new[] but a pointer inside the allocated array
If the call is like
int * v = ...;
del(v);
// here v is unchanged
probably you wanted to modify v, in that case you can return the new array or to use an input-output variable using a reference
First possibility :
int* del (int* ptr_array, int dim) {
int* new_array = new int[dim - 1];
for (int i = 0; i < dim - 1; i++) {
new_array[i] = ptr_array[i];
}
delete[] ptr_array;
return new_array;
}
with
int * v = ...;
v = del(v);
Second possibility
void del (int*& ptr_array, int dim) {
int* new_array = new int[dim - 1];
for (int i = 0; i < dim - 1; i++) {
new_array[i] = ptr_array[i];
}
delete[] ptr_array;
ptr_array = new_array;
}
with
int * v = ...;
del(v);
// here v is the new array
Warning these codes suppose the input array has at least one element
However the use of an std::vector<int> does all of that for you and is more practical to use
std::vector<int> v;
...
v.resize(v.size() - 1);
or
std::vector<int> v;
...
v.pop_back();

Doubling the Size of a C++ Array

The following snippet of code is my attempt to increase the size of an array by a factor of two. I am having several problems with it. Most importantly, should I be calling delete on my original array?
void enlarge(int *array, int* dbl int size) {
for (int i = 0; i < size; i++)
dbl[i] = array[i];
delete array;
array = dbl;
}
You have a few problems:
Modifying array only modifies the local copy of the pointer. You need to take a reference-to-pointer if you want the modification to be observed by the calling code.
You need to use delete[] when deleting things allocated with new[].
You attempt to copy too many items, and in so doing you overrun the original array.
void enlarge(int *& array, int size) {
// ^
// Use a reference to a pointer.
int *dbl = new int[size*2];
for (int i = 0; i < size; i++) {
// ^
// Iterate up to size, not size*2.
dbl[i] = array[i];
}
delete[] array;
// ^
// Use delete[], not delete.
array = dbl;
}
However, I would strongly suggest using std::vector<int> instead; it will automatically resize as necessary and this is completely transparent to you.
keyword double cannot be used as variable name, and previous array must be deleted before new allocation get assigned to same pointer, and loop should copy size no of items from prev array (not 2 * size)
void enlarge(int **array, int size) {
int *d = new int[size*2];
for (int i = 0; i < size; i++)
d[i] = *array[i];
delete [] *array;
*array = d;
}
if previous array was int *arr, and size is the currentsize of the array arr, call should be as: enlarge(&arr, size)

C++ pointer to int in loops?

Ok, so I'm quite new to C++ and I'm sure this question is already answered somewhere, and also is quite simple, but I can't seem to find the answer....
I have a custom array class, which I am using just as an exercise to try and get the hang of how things work which is defined as follows:
Header:
class Array {
private:
// Private variables
unsigned int mCapacity;
unsigned int mLength;
void **mData;
public:
// Public constructor/destructor
Array(unsigned int initialCapacity = 10);
// Public methods
void addObject(void *obj);
void removeObject(void *obj);
void *objectAtIndex(unsigned int index);
void *operator[](unsigned int index);
int indexOfObject(void *obj);
unsigned int getSize();
};
}
Implementation:
GG::Array::Array(unsigned int initialCapacity) : mCapacity(initialCapacity) {
// Allocate a buffer that is the required size
mData = new void*[initialCapacity];
// Set the length to 0
mLength = 0;
}
void GG::Array::addObject(void *obj) {
// Check if there is space for the new object on the end of the array
if (mLength == mCapacity) {
// There is not enough space so create a large array
unsigned int newCapacity = mCapacity + 10;
void **newArray = new void*[newCapacity];
mCapacity = newCapacity;
// Copy over the data from the old array
for (unsigned int i = 0; i < mLength; i++) {
newArray[i] = mData[i];
}
// Delete the old array
delete[] mData;
// Set the new array as mData
mData = newArray;
}
// Now insert the object at the end of the array
mData[mLength] = obj;
mLength++;
}
void GG::Array::removeObject(void *obj) {
// Attempt to find the object in the array
int index = this->indexOfObject(obj);
if (index >= 0) {
// Remove the object
mData[index] = nullptr;
// Move any object after it down in the array
for (unsigned int i = index + 1; i < mLength; i++) {
mData[i - 1] = mData[i];
}
// Decrement the length of the array
mLength--;
}
}
void *GG::Array::objectAtIndex(unsigned int index) {
if (index < mLength) return mData[index];
return nullptr;
}
void *GG::Array::operator[](unsigned int index) {
return this->objectAtIndex(index);
}
int GG::Array::indexOfObject(void *obj) {
// Iterate through the array and try to find the object
for (int i = 0; i < mLength; i++) {
if (mData[i] == obj) return i;
}
return -1;
}
unsigned int GG::Array::getSize() {
return mLength;
}
I'm trying to create an array of pointers to integers, a simplified version of this is as follows:
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
Now the problem is that the same pointer is used for j in every iteration. So after the loop:
array[0] == array[1] == array[2];
I'm sure that this is expected behaviour, but it isn't quite what I want to happen, I want an array of different pointers to different ints. If anyone could point me in the right direction here it would be greatly appreciated! :) (I'm clearly misunderstanding how to use pointers!)
P.s. Thanks everyone for your responses. I have accepted the one that solved the problem that I was having!
I'm guessing you mean:
array[i] = &j;
In which case you're storing a pointer to a temporary. On each loop repitition j is allocated in the stack address on the stack, so &j yeilds the same value. Even if you were getting back different addresses your code would cause problems down the line as you're storing a pointer to a temporary.
Also, why use a void* array. If you actually just want 3 unique integers then just do:
std::vector<int> array(3);
It's much more C++'esque and removes all manner of bugs.
First of all this does not allocate an array of pointers to int
void *array = new void*[2];
It allocates an array of pointers to void.
You may not dereference a pointer to void as type void is incomplete type, It has an empty set of values. So this code is invalid
array[i] = *j;
And moreover instead of *j shall be &j Though in this case pointers have invalid values because would point memory that was destroyed because j is a local variable.
The loop is also wrong. Instead of
for (int i = 0; i < 3; i++) {
there should be
for (int i = 0; i < 2; i++) {
What you want is the following
int **array = new int *[2];
for ( int i = 0; i < 2; i++ )
{
int j = i + 1;
array[i] = new int( j );
}
And you can output objects it points to
for ( int i = 0; i < 2; i++ )
{
std::cout << *array[i] << std::endl;
}
To delete the pointers you can use the following code snippet
for ( int i = 0; i < 2; i++ )
{
delete array[i];
}
delete []array;
EDIT: As you changed your original post then I also will append in turn my post.
Instead of
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
there should be
Array array;
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject( new int( j ) );
}
Take into account that either you should define copy/move constructors and assignment operators or define them as deleted.
There are lots of problems with this code.
The declaration void* array = new void*[2] creates an array of 2 pointers-to-pointer-to-void, indexed 0 and 1. You then try to write into elements 0, 1 and 2. This is undefined behaviour
You almost certainly don't want a void pointer to an array of pointer-to-pointer-to-void. If you really want an array of pointer-to-integer, then you want int** array = new int*[2];. Or probably just int *array[2]; unless you really need the array on the heap.
j is the probably in the same place each time through the loop - it will likely be allocated in the same place on the stack - so &j is the same address each time. In any case, j will go out of scope when the loop's finished, and the address(es) will be invalid.
What are you actually trying to do? There may well be a better way.
if you simply do
int *array[10];
your array variable can decay to a pointer to the first element of the list, you can reference the i-th integer pointer just by doing:
int *myPtr = *(array + i);
which is in fact just another way to write the more common form:
int *myPtr = array[i];
void* is not the same as int*. void* represent a void pointer which is a pointer to a specific memory area without any additional interpretation or assuption about the data you are referencing to
There are some problems:
1) void *array = new void*[2]; is wrong because you want an array of pointers: void *array[2];
2)for (int i = 0; i < 3; i++) { : is wrong because your array is from 0 to 1;
3)int j = i + 1; array[i] = *j; j is an automatic variable, and the content is destroyed at each iteration. This is why you got always the same address. And also, to take the address of a variable you need to use &

Delete a dynamic array but keep a pointer

I have made a function for expanding array, and this function is inside a class.
Because this function creates new_arr and copies all the numbers of array into the new_arr and at the end sets pointer of array with new_arr, I wold like to know how to delete numbers in array becuse I dont need it any more
void Array::bigger() {
int new_size = size * 2;
int *new_arr = new int[new_size];
for (int f1=0; f1<last; f1++) {
new_arr[f1] = array[f1];
}
this->size = new_size;
array = new_arr;
}
Thanks
Assuming this is an exercise, then delete the array before re-assigning to the new one:
delete [] array;
array = new_arr;
In real code, use an std::vector<int> instead of the dynamically allocated array.
free memory before lose pointer to it:
void Array::bigger() {
int new_size = size * 2;
int *new_arr = new int[new_size];
for (int f1=0; f1<last; f1++) {
new_arr[f1] = array[f1];
}
this->size = new_size;
delete[] array; //free memory
array = new_arr;
}