allocating extra memory for a container class - c++

Hey there, I'm writing a template container class and for the past few hours have been trying to allocate new memory for extra data that comes into the container (...hit a brick wall..:| )
template <typename T>
void Container<T>::insert(T item, int index){
if ( index < 0){
cout<<"Invalid location to insert " << index << endl;
return;
}
if (index < sizeC){
//copying original array so that when an item is
//placed in the middleeverything else is shifted forward
T *arryCpy = 0;
int tmpSize = 0;
tmpSize = size();
arryCpy = new T[tmpSize];
int i = 0, j = 0;
for ( i = 0; i < tmpSize; i++){
for ( j = index; j < tmpSize; j++){
arryCpy[i] = elements[j];
}
}
//overwriting and placing item and location index
elements[index] = item;
//copying back everything else after the location at index
int k = 0, l = 0;
for ( k =(index+1), l=0; k < sizeC || l < (sizeC-index); k++,l++){
elements[k] = arryCpy[l];
}
delete[] arryCpy;
arryCpy = 0;
}
//seeing if the location is more than the current capacity
//and hence allocating more memory
if (index+1 > capacityC){
int new_capacity = 0;
int current_size = size();
new_capacity = ((index+1)-capacityC)+capacityC;
//variable for new capacity
T *tmparry2 = 0;
tmparry2 = new T[new_capacity];
int n = 0;
for (n = 0; n < current_size;n++){
tmparry2[n] = elements[n];
}
delete[] elements;
elements = 0;
//copying back what we had before
elements = new T[new_capacity];
int m = 0;
for (m = 0; m < current_size; m++){
elements[m] = tmparry2[m];
}
//placing item
elements[index] = item;
}
else{
elements[index] = item;
}
//increasing the current count
sizeC++;
my testing condition is
Container cnt4(3);
and as soon as i hit the fourth element (when I use for egsomething.insert("random",3);) it crashes and the above doesnt work. where have I gone wrong?

Several things don't make too much sense to me:
if (index+1 > capacityC){
shouldn't that be:
if (index >= capacityC){
Also, when you grow the array I don't see why you are doing two lots of copying. shouldn't:
delete[] elements;
elements = 0;
be:
delete[] elements;
elements = tmparray2;

Note that new T[n] is probably not what you actually want in a container of T, because this already creates n objects of type T. What you really want is to reserve memory, and then at some later point in time construct objects of type T in that memory.
T* data = static_cast<T*>(operator new[](n * sizeof(T)); // allocate memory
// ...
new(&data[size]) T(arguments); // construct T object in-place
++size;
In order to destruct the container, you have to reverse the process: destruct the objects one by one and then release the memory.
while (size) data[--size].~T(); // destruct T object in-place
operator delete[](data); // release memory

Related

Deleting a number from an array that is being pointed to?

I'm having a hard time with this little project of mine; can someone help me out? I am trying to take a pointer to an array, a number, and remove the number if it is present in the array. If the number is removed, the array shrinks. Please note at the time of running removeNumber size = 6.
main
{
int size = 5; // setting array size
int *a = new int[size]; // allocating dynamic array
// initializing array
a[0] = 0; a[1] = 10; a[2] = 20; a[3] = 30; a[4] = 40;
removeNumber(a, 10, size);
}
And now the prototype:
void removeNumber(int *& arrayPtr, int number, int &size)
{
int index = check(arrayPtr, number, size);
int *newArray = new int[size - 1];
if (index != -1)
{
for (int i = number; i <= size; ++i)
newArray[i] = *&arrayPtr[i + 1];
delete[] arrayPtr;
arrayPtr = newArray;
size -= 1;
}
}
Check for reference:
int check(int *arrayPtr, int number, int size)
{
for (int i = 0; i < size; i++)
{
if (arrayPtr[i] == number) return i;
}
return -1;
}
The function is wrong. First of all it has a memory leak in case when the target value is not found in the array.
void removeNumber(int *& arrayPtr, int number, int &size)
{
int index = check(arrayPtr, number, size);
int *newArray = new int[size - 1];
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
if (index != -1)
{
//...
}
}
Secondly there is used incorrect range of indices
for (int i = number; i <= size; ++i)
^^^^^^ ^^^^^^^^^
newArray[i] = *&arrayPtr[i + 1];
^^^^^^
And you could write this expression *&arrayPtr[i + 1] simpler just like arrayPtr[i + 1].
You forgot to copy the elements of the original array before the index index. number is not a valid index.
Also it would be better if the function returned a Boolean value saying whether the operation was successful or not. You can change the size of the array in the calling function if the call was successful.
So I would write the function like
bool removeNumber( int * &arrayPtr, int n, int value )
{
int index = check( arrayPtr, number, size );
if ( index != -1 )
{
int *tmp = new int[size - 1];
int i = 0;
for ( ; i < index; ++i ) tmp[i] = arrayPtr[i];
for ( ; i < size - 1; i++ ) tmp[i] = arrayPtr[i+1];
delete [] arrayPtr;
arrayPtr = tmp;
}
return index != -1;
}
It is ok to reinvent the wheel in order to learn. However you should be aware of the standard way to handle this: using std::vector along with std::remove/std::remove_if (defined in #include <algorithm>) would make your life much simpler, with the benefit of a performant implementation.
void removeNumber(std::vector<int>& vec, int number) {
vec.erase(std::remove(std::begin(vec), std::end(vec), number),
std::end(vec));
// If you really want to shrink the vector, you can call...
vec.shrink_to_fit();
}
I also made a little demo to show you that it works as intended.
Your problem is here:
for (int i = number; i <= size; ++i)
First of all you start the iteration from the value of the number that you searched(in your case 10) and as a result you will not enter the for loop.So the correct starting value of i is the first number of the array which is 0.Then this line of code here:
newArray[i] = *&arrayPtr[i + 1];
doesn't even make sense(as a thought process not syntactically), but what i think you want to do here is just copy the correct element from the old array to the new one.
A correct implementation of the previous is the following code:
void removeNumber(int *& arrayPtr, int number, int &size)
{
int index = check(arrayPtr, number, size);
if (index != -1)
{
int *newArray = new int[size - 1];
int i = 0,j=0; //i for the old array and j for the new
while(i < size)//while we are in bounds
{
if(i==index)//if the index is the index of the given element
{ //skip this number
i++;
continue;
}
newArray[j++] = arrayPtr[i++];//copy the correct number to the correct position
}
delete[] arrayPtr;
arrayPtr = newArray;
size -= 1;
}
}

Thinking I should be allowed to `delete` a pointer but an error is thrown `block in use`

Consider this function:
bool RemoveElement(const T2& e2)
{
bool match = false;
for (int i = 0; i < _trenutno; i++)
{
if (*_elementi2[i] == e2){
match = true;
for (int j = i; j < _trenutno - 1; j++)
{
_elementi1[j] = _elementi1[j + 1];
_elementi2[j] = _elementi2[j + 1];
// SOLUTION: The two lines above are not correct.
// Instead of assigning addresses, I should have assigned
// values, ie. dereference them like below:
// *_elementi1[j] = *_elementi1[j + 1];
// *_elementi2[j] = *_elementi2[j + 1];
}
}
}
if (match)
{
_trenutno--;
//delete _elementi1[_trenutno];
_elementi1[_trenutno] = nullptr;
//delete _elementi2[_trenutno];
_elementi2[_trenutno] = nullptr;
}
return match;
}
FYI, the pointers themselves (see below). I'm trying in the above function delete values behind this particular pair of pointers (last element) using delete because otherwise I believe memory leak would occur?
template<class T1, class T2, int max>
class Kolekcija
{
T1* _elementi1[max];
T2* _elementi2[max];
int _trenutno;
public:
Kolekcija()
{
for (int i = 0; i < max; i++)
{
_elementi1[i] = nullptr;
_elementi2[i] = nullptr;
}
_trenutno = 0;
}
// ...
~Kolekcija()
{
for (int i = 0; i < _trenutno; i++){
delete _elementi1[i]; _elementi1[i] = nullptr;
delete _elementi2[i]; _elementi2[i] = nullptr;
}
}
// ....
Why is this happening, I'd like to learn more and better understand pointers.
If your class is the data owner and you want to remove some element:
Find index of element (_elementi1[nFound] == searchValue)
Delete this element from heap delete _elementi1[nFound];
Set element's value to nullptr _elementi1[nFound] = nullptr;
Only then move trailing elements in place of removed item.
This sequence will protect you against memory leaks in Remove method.
Destructor will clean other heap allocated values (assuming _trenutno is actual count):
for (int i = 0; i < _trenutno; i++)
{
delete _elementi1[i]; _elementi1[i] = nullptr;
delete _elementi2[i]; _elementi2[i] = nullptr;
}
Deleting nullptr is safe.
So my version of Remove():
bool RemoveElement(const T2& e2)
{
for (int i = 0; i < _trenutno; i++)
{
if (*_elementi2[i] == e2)
{
delete _elementi1[i];
_elementi1[i] = nullptr;
delete _elementi2[i];
_elementi2[i] = nullptr;
for (int j = i; j < _trenutno - 1; j++)
{
_elementi1[j] = _elementi1[j + 1];
_elementi2[j] = _elementi2[j + 1];
}
_trenutno--;
return true; //found
}
}
return false; //not found
}
I'm assuming that your collection is the data owner. So you have to delete all pointers that was passed to it.
Simple example (we'r adding 3 values):
int* elements[max] = {0};
elements[0] = new int(4); //0x00FF1F
elements[1] = new int(5); //0x00FF2F
elements[2] = new int(6); //0x00FF3F
_trenutno = 3;
We have to delete all 3 int*
If no Remove was called destructor will handle it (delete from 0 to 2).
If we call Remove(5):
Found index of 5 value i == 1
Call delete elements[1] that means releaze memory at address 0x00FF2F
Make shift: elements[1] = elements[2]
Now our array is:
elements[0]; //0x00FF1F
elements[1]; //0x00FF3F
elements[2]; //0x00FF3F
And _trenutno = 2;
So destructor will remove pointers from '0' to '1'.
That is all 3 pointers where deleted!
Here you have many problems, at first you need to delete item , and then set nullptr value for that position in array, and if I want to use array of T1 and T2 like in your case , than I would use vector instead of simple array

How to delete completely 2D pointer array

I have a 2D pointer matrix in C++ such as,
typedef unsigned char U8;
typedef unsigned int U32;
int M=10;
int m_L=8;
U8** A = new U8*[M];
for (U32 i = 0; i < M; ++i)
{
A[i] = new U8[m_L];
}
After setting value in A0, I will write a function which decide delete or not delete M-2 rows in A, depends on the random number is 0 or 1
void delete_or_not(U8** A,int M)
{
if (rand_num==1){
for (U32 index = M-2; index < M; ++index){
delete[] A[index];
}
}
}
Now, in main function (which contains A memory allocation), I want to free/delete the memory which allocated for A. I can use the code
//free A matrix
for (U32 i = 0; i < M; ++i)
{
if (i < m_L)
{
delete[] A[i];
A[i] = NULL;
}
}
delete[] A;
A = NULL;
My problem is that, I don't know that A is delete (M-2) rows or not. Hence, above code does clearly delete all memory, if my random number is 0. That means, above code only delete correct memory if M-2 rows is deleted in the delete_or_not function. How can delete the A matrix perfectly. Thanks
Finaly, my full code is
typedef unsigned char U8;
typedef unsigned int U32;
int M=10;
int m_L=8;
U8** A = new U8*[M];
for (U32 i = 0; i < M; ++i)
{
A[i] = new U8[m_L];
}
delete_or_not(A,M);
//free A matrix
//Way 1: will miss M-2 row if delete_or_not function did not delete 2 rows.
// It only correct if rand_num=1
for (U32 i = 0; i < M; ++i)
{
if (i < m_L)
{
delete[] A[i];
A[i] = NULL;
}
}
delete[] A;
A = NULL;
//Way 2- It will correct if the size of A is M by M
for (U32 i = 0; i < M; ++i)
{
delete[] A[i];
A[i] = NULL;
}
delete[] A;
A = NULL;
Just set deleted elements to NULL and everything will work fine:
void delete_or_not(U8** A,int M)
{
if (rand_num==1){
for (U32 index = M-2; index < M; ++index){
delete[] A[index];
A[index] = NULL;
}
}
}
Also, this is not very useful:
for (U32 i = 0; i < M; ++i)
{
if (i < m_L)
{
delete[] A[i];
A[i] = NULL;
}
}
There's no point advancing i from 0 to M if you then only "do work" when i is smaller then m_L.
But really, in C++ you should probably use std::vector<std::vector<U8>> instead and simply erase or pop_back to get rid of "rows".
In void delete_or_notyou shall set deleted elements to NULL as already proposed by another answer by Amit.
Then Way 2 of your posted code is correct in both cases.
Calling delete on a NULL is perfectly legal and doesn't hurt at all.
Way 1 is not working and should be removed.
In summary:
void delete_or_not(U8** A,int M)
{
if (rand_num==1){
for (U32 index = M-2; index < M; ++index){
delete[] A[index];
A[index] = NULL; // Add this to your code
}
}
}
// In main somewhere...
// free A
for (U32 i = 0; i < M; ++i)
{
delete[] A[i]; // Not a problem if the element has already been deleted
// because the pointer will be NULL and calling
// delete with NULL is OK (and changes nothing)
A[i] = NULL;
}
delete[] A;
A = NULL;

Problems changing numbers

looking for some homework help. Not for an answer just for a nudge in the right direction. We are given an array with some numbers, the size of the array and the number of times we are to double it. We are to double the size, copy the same numbers over and then multiply the second halves numbers by 2.
So if the array was {0,1} with number 2. The last array would be {0,1,0,2,0,2,0,4}.
My code compiles properly and is returning some very strange number, which for the original array {0,1} and number 3 is giving me a bunch of 0's and a random 135057 in the middle.
Heres my code:
int *ArrayDynamicAllocation(int array[], int size, int number)
{
for (int runs = 1;runs < number; runs++) {
int new_size = size * 2;
int *new_array = new int[new_size];
for (int x = 0;x < size; x++) {
new_array[x] = array[x];
}
for (int y = size+1; size < new_size; size++) {
new_array[y] = array[y];
}
size = new_size;
array = new_array;
delete [] new_array;
}
return array;
}
As #Elvisjames said in comment, array = new_array; means you are assigning the pointer to the memory of the newly created new_array to array and delete [] new_array; means you are deleting both new_array and array from the memory. Because of previous assignment, array is pointed to the new_array and deleting new_array means deleting array.
So better you delete the old array first then assign the newly created array to the old array.
In your this loop:
for (int y = size+1; size < new_size; size++)
{
new_array[y] = array[y];
}
As #Elvisjames said in comment, new_array[y] = array[y]; where there is no array[y]
You should define your ArrayDynamicAllocation function as following:
int *ArrayDynamicAllocation(int array[], int& size, int number)
{
for (int runs = 1;runs < number; runs++)
{
int new_size = size * 2;
int *new_array = new int[new_size];
for (int x = 0;x < size; x++)
{
new_array[x] = array[x];
new_array[x+size]=2*array[x];
}
size = new_size;
// Here you should delete the old array first then assign the newly created array to the old array.
//array = new_array;
//delete [] new_array;
delete [] array;
array = new_array;
}
return array;
}
I've change the int size to int& size for knowing the new size.

Insert element in array

void insert(int*arr, int element,int index)
{
if (index < SIZE)
{
arr[index] = element;
}
else
{
int* new_array = new int[SIZE + 1];
int i = 0;
for (i = 0; i < SIZE; i++)
{
new_array[i] = arr[i];
}
new_array[i] = element;
SIZE++;
printArray(new_array);
}
}
I have made an insert function in C++ that will insert values at specific indices of the array.After index gets increased I made a new array and copied values from the smaller array into it.
Problem is that printArray function which is just looping to print the array does well when it is called inside the insert function otherwise when I called printArray from the main last value of the array was garbage why is that?
You need to delete the old array and return the new array in its place, e.g.:
void insert(int* &arr, int element, int index) // <<< make `arr` a reference so that we can modify it
{
if (index < SIZE)
{
arr[index] = element;
}
else
{
int* new_array = new int[SIZE + 1];
for (int i = 0; i < SIZE; i++)
{
new_array[i] = arr[i];
}
new_array[SIZE] = element;
SIZE++; // <<< NB: using a global for this is not a great idea!
delete [] arr; // <<< delete old `arr`
arr = new_array; // <<< replace it with `new_array`
}
}
LIVE DEMO
Note that all this explicit low level management of your array goes away if you start using proper C++ idioms, such as std::vector<int> instead of C-style int * arrays.