How does dynamic space allocation actually work in this algorithm? - c++

I have made for school purposes my own take on a dynamically allocated array using templates.
While what I'm about to ask works, I don't know how and why and I've reached the point where I need to know.
template <typename TElement>
DynamicArray<TElement>::ensureCapacity () {
if (capacity >= elemNumb) {
return; //we have space to store the values
}
//we need to allocate more space for the values
TElement *auxArray = myArray;
//create space to hold more numbers
capacity = capacity * 2;
myArray = new TElement[capacity];
//copy the values
for (int i = 0; i < size; i++) {
myArray[i] = auxArray[i];
}
//release the memory
delete[] auxArray;
}
I need to know: TElement *auxArray = myArray; How does this work ? is it using pointers, are elements copied one by one ? I need to understand how it works so that I can figure out the complexity of my algorithm. I don't mind if some one tells me the complexity but the real answer I'm looking for is how does that work ?
Also myArray = new TElement[capacity]; I do this before deleting the old myArray does this delete the old one ? or is it still floating somewhere in memory in one form or another ?

This
TElement *auxArray = myArray;
just means that auxArray points to whatever myArray is pointing to. There is no copying of anything else, it is just a pointer copy.
This
myArray = new TElement[capacity];
means that myArray now points to a new, dynamically allocated TElement array. The expression doesn't delete anything. But auxArray is pointing to what myArray was pointing before this assignment, so when you delete auxArray, you release the resources originally pointed to by myArray.

Related

Is it safe to use delete[] on an array that was allocated as a different type?

In order to use placement new instead of automatically attempting to call the default constructor, I'm allocating an array using reinterpret_cast<Object*>(new char[num_elements * sizeof(Object)]) instead of new Object[num_elements].
However, I'm not sure how I should be deleting the array so that the destructors get called correctly. Should I loop through the elements, call the destructor manually for each element, and then cast the array to a char* and use delete[] on that, like this:
for (size_t i = 0; i < num_elements; ++i) {
array[i].~Object();
}
delete[] reinterpret_cast<char*>(array);
Or is it sufficient if I don't call the destructor manually for each element, and simply rely on delete[] to do that since the type of the array is Object*, like delete[] array?
What I'm worried about, is that not every platform might be able to determine the amount of elements in the array correctly that way, because I didn't allocate the array using a type of the right size. An answer to a question about "how delete[] knows the size of the operand" suggests that a possible implementation of delete[] would be to store the number of allocated elements (rather than the amount of bytes).
If delete[] is indeed implemented that way, that would suggest that using just delete[] array would try to delete too many elements, because the array was created with more char elements than how many Object elements fit in it. So in that case, the only reliable way to delete the array would be to manually call the destructors, cast the array to a char*, and then use delete[].
However, another logical way to implement it would be to store the size of the array in bytes, rather than the amount of elements, and then when calling delete[], divide the size of the array by the size of the type to get the amount of elements to call the destructor of. If this method is used, then just using delete[] array where array has a type of Object* would be sufficient.
So my question is: can I rely on delete[] to correctly call the destructors of the elements in the operand array, if the array was originally not allocated with the right type?
This is the code I'm using:
template <typename NumberType>
NeuronLayer<NumberType>::NeuronLayer(size_t num_inputs, size_t num_neurons, const NumberType *weights)
: neurons(reinterpret_cast<Neuron<NumberType>*>(new char[num_neurons * sizeof(Neuron<NumberType>)])),
num_neurons(num_neurons), num_weights(0) {
for (size_t i = 0; i < num_neurons; ++i) {
Neuron<NumberType> &neuron = neurons[i];
new(&neuron) Neuron<NumberType>(num_inputs, weights + num_weights);
num_weights += neuron.GetNumWeights();
}
}
and
template <typename NumberType>
NeuronLayer<NumberType>::~NeuronLayer() {
delete[] neurons;
}
or
template <typename NumberType>
NeuronLayer<NumberType>::~NeuronLayer() {
for (size_t i = 0; i < num_neurons; ++i) {
neurons[i].~Neuron();
}
delete[] reinterpret_cast<char*>(neurons);
}
Calling delete[] on an Object* will call the destructor once for every object allocated by new[]. new Object[N] typically stores N before the actual array, and delete[] certainly knows where to look.
Your code doesn't store that count. And it can't, since it's an unspecified implementation detail where and how the count is stored. As you speculate, there are two obvious ways: element count and array size, and one obvious location (before the array). Even so, there could be alignment issues, and you can't predict what type is used for the size.
Also, new unsigned char[N] is a special case since delete[] doesn't need to call destructors of char. In that case new[] doesn't need to store N at all. So you can't even bank on that size being stored, even if new Object[N] would have stored a size.
Here is portable code that manages a dynamic array of objects. It's essentially std::vector:
void * addr = ::operator new(sizeof(Object) * num_elements);
Object * p = static_cast<Object *>(addr);
for (std::size_t i = 0; i != num_elements; ++i)
{
::new (p + i) Object(/* some initializer */);
}
// ...
for (std::size_t i = 0; i != num_elements; ++i)
{
std::size_t ri = num_elements - i - 1;
(p + ri)->~Object();
}
::operator delete(addr);
This is general pattern how you should organize dynamic storage if you want to have very low-level control. The upshot is that dynamic arrays should never have been a language feature and are much better implemented in library. As I said above, this code is pretty much identical to the existing standard library gadget called std::vector<Object>.

Checking if char out of not fully filled array is empty

As you may know, if you want to delete any type of dynamically allocated array (that you used the operator new[]on), you should use delete[] to get rid of it.
Now, I would like to know if there was any way I'd be able to delete a single object of a dynamically allocated array.
char* someNewArray = new char[someInt];
//Add values to the array
delete &someNewArray[2] //or maybe delete[] instead of just delete
No you cannot.
Operator new in its array form allocates one single memory element able to contain the number of elements you asked. You can the only deallocate the whole block with delete[].
If you want to deallocate blocks one by one, you will have to allocate them with same granularity, that is one by one.
EDIT :
It would have little sense for object of size 1 because the overload of allocating a block will be large facing sizeof(char). In that case it is more efficient to allocate a new block of size someInt -1, use memcpy and then free initial block with delete[]
char * tmp = new char[someInt -1];
memcpy(tmp, someNewArray, 2);
memcpy(tmp+2, someNewArray + 3, someInt - 3);
delete[] someNewArray;
someNewArray = tmp;
But it you add an array of larger objects say LObj, instead of
LObj * newArray = new LObj[someInt];
you could use :
LObj ** newArray = new (LObj *)[someInt];
for (i=0; i<someInt; i++) {
newArray[i] = new LObj;
}
Then is makes sense to use :
delete newArray[2];
newArray[2] = NULL;

Proper way to delete an array of pointers

I have an array of pointers (that I created by calling new ptr*[size]). All of these pointers point to an object that was also put on the heap.
What is the proper way to delete the array and all new'd ptr's?
This is what I do now:
for (int i = 0; i < size; i++) delete array[i];
delete[] array; // Not sure since this double deletes array[0]
Does this do what I think it should?
Thanks
Every pointer allocated with new gets a corresponding delete. Every pointer allocated with new [] gets a corresponding delete []. That's really all you need to know. Of course, when you have a dynamically allocated array which contains dynamically allocated pointers the deallocation must occur in reverse order.
So it follows that the correct idiom would be...
int main()
{
int **container = new int*[n];
for(int i = 0; i < n; ++i)
container[i] = new int[size];
// ... and to deallocate...
for(int i = 0; i < n; ++i)
delete [] container[i];
delete [] container;
}
And then of course I say "stop doing that" and recommend you use a std::array or std::vector (and the template type would be unique_ptr<int>).
Yes, that does what you think it should. Since you did new for each element, you have to delete each element. And since you did new[] for the entire array, you need to delete[] the entire array.
As #djechlin rightly says in the comments, there's not really enough information to go on, but I'm presuming your prior code is something like this:
int** array = new int*[5];
for (int i = 0; i < 5; i++) {
array[i] = new int;
}
Note that array is not actually an array type. It is a "pointer to pointer to int" and the array of pointers it points to was allocated with new[]. That's why you need to delete[] it.
Yes. First you have to free the object each pointer in the array points to, then you have to free the array itself. In that order. If you reverse the order you'll have no reference to the objects and will leak a lot of memory.
Yes, first you delete each object to which elements of array point, and then you delete array of pointers itself. If you want to check your memory management, you can use tools like valgrind, they will be able to spot most errors.

Delete a pointer array without deleting the pointed objects in memory?

I would like to know if there is a way to delete a pointer array without touching the pointed objects in memory.
I'm writing a restriction routine for a HashSet I implemented a couple of days ago, so when the hash table is full it gets replaced by another double sized table. I'm representing the hash table using an array of pointers to an object (User), and the array itself is declared dynamically in my HashSet class, so it can be deleted after copying all its content to the new table using a hash function.
So basically I need to:
Declare another table with a size that equals the double of the original array size.
Copy every pointer to User objects from my original array to the new one applying my hash function (it gets the User object from memory and it calculates the index using a string that represents the user's name).
After inserting all the pointers from the original array to the new one, I will have to free the allocated memory for the original array and replace the pointer in my HashSet class (member private userContainer) with the location of the new one (array).
The problem is that if I use delete[] userContainer to free the allocated memory for it, it will also delete every object in memory so the newly created replacement array will point to freed positions in memory!
What you describe does not sound right.
Let's say you have a class A and you create an array of As with:
A** array1 = new A*[32];
Then fill it:
for(int i = 0; i < 32; ++i)
array1[i] = new A();
Doing a delete[] array1 does not free the elements of array1.
So this is safe:
A** array1 = new A*[32];
for(int i = 0; i < 32; ++i)
array1[i] = new A();
A** arary2 = new A*[64];
for(i = 0; i < 32; ++i)
array2[i] = array1[i];
delete [] array1;
for(i = 0; i < 32; ++i)
// do something with array2[i]
In general, when you delete an array of pointers, whatever objects the pointers pointed to remain in existence. In fact, this is a potential source of large memory leaks.
But in some sort of reference-counted environment (eg, Objective-C or Qt), when you delete an array OBJECT (vs a simple [] array) then the reference counts are decremented and the objects will be deleted if the count goes to zero.
But if you're restructuring a hash table you'd better have somehow saved the pointer values before you delete the array, or else all the addressed objects will be lost. As you save them you can increment their reference counts (if you do it right).
(It would help to know what language you're dealing with, and what you mean by "array".)
I don't think your problem exists. Here's a baby example to show that there's nothing to worry about:
Foo * brr[10];
{
Foo * arr[10];
// This is not touching the objects!
for (Foo * it = arr; it != arr + 10; ++it) *it = new Foo;
std::copy(arr, arr + 10, brr);
} // no more arr
for (Foo * it = brr; it != brr + 10; ++it) delete *it; // fine
You can copy the pointers around freely as much as you like. Just remember to delete the object to which the pointers point when they're no longer needed.
A perhaps trivial reminder: Pointers don't have destructors; in particular, when a pointer goes out of scope, nothing happens.
Do you know the difference between malloc/free, new/delete and new[]/delete[]?
I figure that you might want to not use new[]/delete[] in your situation, as you don't want destructors to be called I guess?

possible problems after resizing dynamic array

Got little problem here.
I created dynamic array:
m_elements = new struct element*[m_number_of_elements];
for(int i = 0; i < m_number_of_elements; i++)
{
m_elements[i] = new struct element[m_element_size];
}
then I tried to resize existing array:
m_elements[m_number_of_elements] = create_more_elements();
m_number_of_elements++;
create_more_elements() is a function:
struct index* create_more_elements()
{
struct element* tmp = new struct element[m_number_of_elements]
return tmp;
}
In general, this piece of code works, but sometimes I get segfaults in different places.
Are segfaults connected with resizing?
Any thoughts?
You should use std::vector for it, then you can with new allocate memory for new struct and push her pointer to vector, if you deleting you should delete on pointer.
Try this:
std::vector<element> m_elements;
m_elements.resize(m_number_of_elements);
Don't go the route of manually managing an array unless absolutely necessary - std::vector will do a far better job, is better tested, proven, standardized and understood by legions of C++ programmers. See my code example - not even a single new or delete statement, yet this code also contains all required memory management.
P.S.: Since this question is tagged as C++, you don't have to write struct element whereever you use it as a type, just element will suffice. This suggests you are coming from C, so my advice: learn about the STL before you continue what you're doing, a single hour spent learning how to use the standard container classes can save you many days of manual tweaking, debugging and bug-fixing. Especially since once you've learnt one, you already know like 80% about all the others. :)
m_elements[i] = new struct element[m_element_size];
This creates an array of element of size m_element_size
To dynamically create a struct, just use new struct element or new element.
If don't have to initialize values in your array, you may even be better not storing pointers but actual objects in your array:
m_elements = new element[m_number_of_elements];
To "resize" an array, you actually have to allocate a new bigger array, copy the content of current array in the new one, and delete the old array.
// Allocate new array
element* newArray = new element[m_number_of_elements + 1];
// Copy old array content into new one
memcpy(newArray, m_elements, m_number_of_elements * sizeof(element)];
// Delete old array
delete[] m_elements;
// Assign new array
m_elements = newArray;
// Keep new size
m_number_of_elements += 1;
But you should definitely use std::vector which is simpler and smarter than that:
std::vector<element> elements;
// Add an element
Element element;
...
elements.push_back(element);
It is a wonder that you code even works. Basically what you are doing is overwriting memory after your initially allocated array. In C++ you can't resize the array, you can only delete it and new up a new one.
element** tmp = new element*[m_number_of_elements];
for(int i = 0; i < m_number_of_elements; i++)
{
tmp[i] = m_elements[i]
}
delete m_elements;
m_elements = tmp;
m_elements[m_number_of_elements] = create_more_elements();
m_number_of_elements++;
But, that is really crufty. As Svisstack points out, you should use std::vector or any other suitable standard container.
std::vector<element*> m_elements;
// ...
m_elements.push_back(create_more_elements());