dynamic allocation and deallocation - c++

I am a bit confused here, suppose i am making a container that will hold some elements and those elements can be removed.
I would have a fixed array of elements for that.
Now my question is with allocating and deallocating that array and deallocatisingle elements in it.
1) Allocating
Item* data;
Container()
{
data = new Item[size];
}
Then to add I do something like that:
add(Item it)
{
data[empty++] = it;
}
Now my question is with that allocation I have created size objects of Items then when I come in the add I add another item above, so does this means there is destruction of the old and the new take over?
Should I better use allocater<T> and uninitializedfill() as I read it allocate required memory without constructing the object.
2) Deallocating:
Here comes all the confusion really , on removing a single element can I use that?
remove(Item it)
{
//index is item index
delete data[index];
//restore contiguity to array
empty--;
}
can I use delete data[index] even if Item isn't a pointer? if not how then could I do this part?!
If I can then, what if Item was a pointer so when I delete it does it deletes the object pointed by it?

When you allocate a fixed-length array with
data = new Item[size];
you have allocated all size elements of the array at once, in a contiguous block of memory. You do not allocate individual elements in the array, and you cannot deallocate individual elements with delete data[index] -- you can only deallocate the entire array with delete[] data when you are done.
If you anticipate needing to add and remove elements at the end of the array, I recommend using std::vector instead. If you expect to add and remove elements anywhere in the array, std::list probably makes more sense.

data = new Item[size];
This creates an array of Items of size length, and return a poitner to them. Those itemswill be in indexes 0..(size-1) inclusive.
data[empty++] = it;
Assuming empty is < size, this will bash one of your items over the head, repalcing it with the Item passed into add(). If empty >= size than bad things will happen.
delete data[index];
This is not legal code. You are stuck with all (size) Items until you want to delete the lot.

Use:
std::vector<Item> data(N);

You have to decide if Items are values or referred objects. In fact allocation and deallocation look incoherent:
new Item[size] actually creates size Items (that start to exist all together) and data[i] = item copies the lone item intio the ith Item addressed by data (replacing its internal value). In this way you are not "inserting" anything. the empty index (what a bad name...) just defines what to replace.
delete data[index] cannot work, because data[index] is not a pointer (its an Item itself).
The pair with data = new Item[x] is delete[] data that deletes all them together as together thay have been created.
Inserting and removing an item inside a block of Items of a given predefined size is ... nonsense (if you can do the the size is not predefined).
You have to consider reallocating the array, copy, and shifting elements. But this is nothing more than re-implementing std::vector.

Related

removing elements in an array, c++

I have an array of sockets (pfd[nfd].fd). I also have an array of pointers (event_tracking* track[10]). If there comes a point in my code where I try and receive data from a socket that is closed I would like to remove that array element in both arrays and then shift the arrays to fill the empty spot.
for(j=1; j<nfd; j++) {
if(pfd[j].revents&POLLIN) {
char* p = track.receive_datagram();
if (p == 0) {
delete track[j-1];
//Delete element in pfd[nfd].fd
//Reorder elements of track array
//Reorder elements of pfd array
}
}
}
I know you can call the delete operator to call the destructor for track but I'm not sure how to reorder the elements in the array now that one is missing? Or how to delete and reorder the pfd array?
Any help would be appreciated! I can't find any examples of deleting and reordering arrays in my text.
A C++ solution should be to use a std::vector or std::array and forget about everything (possibly storing smart pointers, eg std::unique_ptr<T>).
If you really want to go the hard way you could setup things like these:
find element to remove (index i)
if i == LENGTH_OF_ARRAY - 1 do nothing, otherwise swap element at i and at LENGTH_OF_ARRAY - 1 so that the element to be removed is in last position
call delete array[LENGTH_OF_ARRAY - 1] to destroy last element
call array = realloc(array, (LENGTH_OF_ARRAY - 1) * sizeof(array[0])) to release memory in the array for removed element, and update LENGTH_OF_ARRAY
Without changing your data structures, the solution is to copy each element after the one you remove over the previous element of the array. This is more efficient for a linked list. With an array allocated by new[], you would not reallocate anything, but you could resize a vector.

Dynamically allocating memory for changing array size starting with unknown size C++

How do I dynamically allocate an array where the size will be changing because the stuff stored in the array will be read from a file. There are lots of suggestions on using a vector, but I want to know how to do it the array way.
I know for memory allocation it is
int count;
int *n = new int[count];
Say the variable count is going to increment in a loop. How would I change the size of the array?
Also, what if we did it using malloc?
Don't try to make the array allocation exactly follow the continual changing size requirements of what you are going to store. Consider using the traditional 2*N multiple. When array is full, reallocate by growing by 2*N (allocate a new array twice as large), and copy items over. This amortizes the reallocation cost logarithmically.
Keep in mind that this logic you are setting out to implement with low level arrays is exactly why vector exists. You are not likely to implement your own as efficiently, or as bug free.
But if you are set on it, keep count a multiple of 2, starting with something realistic (or the nearest multiple of 2 rounded up)
You may keep two pointers, p and q(placeholder), when count changes, you need to do a fresh allocation for p, before that earlier allocations need to be deallocated, even before that the contents of earlier p should be transferred to new p as well.
int count, oldcount;
int *p = NULL;
int *q;
p = new int[count];
oldcount = count;
when you need to re-allocate:
q = new int[count];
memcpy(q, p, oldcount * sizeof(int)); // OR for (int i = 0; i < oldcount; i++) q[i] = p[i];
delete [] p;
p = q;
oldcount = count; // for use later
If you use malloc, calloc then you need to use as number of bytes to pass in malloc. but not needed with new and delete operators in C++
How would I change the size of the array?
Using new: You can't. The size of an object (here, an array object) can't change at runtime.
You would have to create a new array with the appropriate size, copy all elements from the old into the new array and destroy the old one.
To avoid many reallocations you should always allocate more than you need. Keep track of the size (the amount of elements currently in use) and the capacity (the actual size of the allocated array). Once you want to increase the size, check whether there is still some memory left (size<capacity) and use that if possible; otherwise, apply the aforementioned method.
And that's exactly what vector does for you: But with RAII and all the convenience possible.

How do i remove a pointer to an object in c++ from a vector dynamically?

Okay, so i'm doing this game like a project where i have 3 different objects.
void Character::shoot(){
Shot* s = new Shot(blablabla);
shots.push_back(s);
}
This happens dynamically, and currently i dont delete the pointers so it has to be loads of pointers to shots in that vector after a little while.
I use Bot, Character and Shot, and as i said i need help with storing and removing a pointer to the shot dynamically, preferably from a vector. I've got it to work like i put all the shot objects in a vector, but they never disappear from there. And i want to delete them permanently from my program when they collide with something, or reaches outside my screen width.
You can use std::remove and std::erase on any std container to remove content:
Shot* to_be_removed = ...;
std::vector<Shot*>::iterator i = std::remove(shots.begin(),shots.end(),to_be_removed);
std::erase(i,shots.end());
delete (to_be_removed);//don't forget to delete the pointer
This works when you know the element you want to remove. If you don't know the element you must find a way to identify the elements you want removed. Also if you have a system to identify the element it could be easier to use the container iterator in order to do the removal:
std::vector<Shot*>::iterator i = ...;//iterator the the element you want to remove
delete (*i);//delete memory
shots.erase(i);//remove it from vector
Lastly if you want to remove all pointers from the container and delete all the items at the same time you can use std::for_each
//c++ 03 standard:
void functor(Shot* s)
{
delete(s);
}
std::for_each(shots.begin(),shots.end(),functor);
shots.clear();//empty the list
//or c++11 standard:
std::for_each(shots.begin(),shots.end(),[] (Shot * s){ delete(s); } );
//the rest is the same
Using simple vector methods
You can iterate trough std::vector and use erase() method to remove current shot:
std::vector<cls*> shots; // Your vector of shots
std::vector<cls*>::iterator current_shot = shots.begin(); // Your shot to be deleted
while( current_shot < shots.end()){
if((*current_shot)->needs_to_be_deleted()){
// Remove item from vector
delete *current_shot;
current_shot = shots.erase(current_shot);
} else {
(*current_shot)->draw();
++current_shot; // Iterate trough vector
}
}
erase() returns iterator to next element after removed element so while loop is used.
Setting values to null and calling std::remove()
Note that std::vector::erase() reorganize everything after delete items:
Because vectors use an array as their underlying storage, erasing
elements in positions other than the vector end causes the container
to relocate all the elements after the segment erased to their new
positions. This is generally an inefficient operation compared to the
one performed for the same operation by other kinds of sequence
containers (such as list or forward_list).
This way you may end up with O(n^2) complexity so you may rather set values to null and use std::remove() as suggested by juanchopanza in comment, Erase-Remove idiom:
int deleted = 0;
for( current_shot = shots.begin(); current_shot < shots.end(); ++current_shot){
if((*current_shot)->needs_to_be_deleted()){
// Remove item from vector
delete *current_shot;
*current_shot = null;
++deleted;
}
}
if( deleted){
shots.erase( std::remove(shots.begin(), shots.end(), null));
}
Using std::list
If you need large amount of shot creations and deletions std::vector may not be the best structure for containing this kind of list (especially when you want to remove items from the middle):
Internally, vectors use a dynamically allocated array to store their
elements. This array may need to be reallocated in order to grow in
size when new elements are inserted, which implies allocating a new
array and moving all elements to it. This is a relatively expensive
task in terms of processing time, and thus, vectors do not reallocate
each time an element is added to the container.
See link from Raxvan's comment for performance comparison.
You may want to use std::list instead:
List containers are implemented as doubly-linked lists; Doubly linked
lists can store each of the elements they contain in different and
unrelated storage locations. The ordering is kept by the association
to each element of a link to the element preceding it and a link to
the element following it.
Compared to other base standard sequence containers (array, vector and
deque), lists perform generally better in inserting, extracting and
moving elements in any position within the container for which an
iterator has already been obtained, and therefore also in algorithms
that make intensive use of these, like sorting algorithms.
The main drawback of lists and forward_lists compared to these other
sequence containers is that they lack direct access to the elements by
their position;
Which is great for removing items from the middle of the "array".
As for removing, use delete and std::list::erase():
std::list<cls*> shots;
std::list<cls*>::iterator current_shot;
// You have to use iterators, not direct access
for( current_shot = shots.begin(); current_shot != shots.end(); current_shot++){
if( (*current_shots)->needs_to_be_deleted()){
delete *current_shot;
shots.erase(current_shot); // Remove element from list
}
}
Using std::shared_ptr
If you have more complex program structure and you use the same object on many places and you can simply determine whether you can delete object already or you need to keep it alive for a little bit more (and if you are using C++11), you can use std::shared_ptr (or use different kind of "smart pointers" which delete data where reference count reaches zero):
// Pushing items will have slightly more complicated syntax
std::list< std::shared_ptr<cls>> shots;
shots.push_back( std::shared_ptr( new cls()));
std::list< std::shared_ptr<cls>>::iterator current_shot;
// But you may skip using delete
shots.erase(current_shot); // shared_ptr will take care of freeing the memory
Simply use "delete" to deallocate the memory:
vector<Shot*>::iterator i;
for(i = shoot.begin(); i != shoot.end(); ++i)
{
delete (*i);//delete data that was pointed
*i = 0;
}
shoot.clear();
This will delete all elements from the heap and clear your vector.

How to remove elements from dynamically allocated array?

I have a dynamically allocated array :
myRectangle lastRectanglesArray = new myRectangle[lastMaxLabel];
I would like to loop through all elements in this array and remove these that will meet my condition (e.g. too big rectangle).
I have been thinking that I can loop through this array and get the number of elements that would satisfy my condition and then allocate a new array. But how can I 'transfer' these 'wanted' elements into my new array ?
Just for the record: I cannot use STL containers.
myRectangle * lastRectanglesArray = new myRectangle[lastMaxLabel];
// initialize the entries in the lastRectanglesArray
// create a temporary array which contains info about each individual
// entry. namely, it only holds info about whether the entry should
// be kept, or deleted.
// we also use the 'entries' value, which is the number of entries
// in the new array
bool * entriesToKeep = new bool[lastMaxLabel];
int entries = 0;
// check each entry, and mark whether it should be kept or deleted
for (int i = 0; i != lastMaxLabel; ++i) {
// check whether the entry should be kept or deleted...
// here, i just put a function with signature like:
// bool shouldKeepRectangle(const myRectangle &);
entriesToKeep[i] = shouldKeepRectangle(lastRectanglesArray[i]);
if (entriesToKeep[i]) ++entries;
}
// create a new array that will contain the entries that should be kept
myRectangle * rectanglesArray = new myRectangle[entries];
// assign the entries in the new array
for (int i = 0, j = 0; i != lastMaxLabel && j != entries; ++i) {
if (entriesToKeep[i])
rectanglesArray[j++] = lastRectanglesArray[i];
}
// free the memory held by the temp array
delete [] entriesToKeep;
// if the old array is not needed anymore, delete it
delete [] lastRectanglesArray;
// and here you have rectanglesArray, a brand new array that contains
// only the elements that you need.
Just move the next array location over the one that needs to be deleted, and shift everything over til the end of the array.
Yours look like the perfect case for using a Linked List. You would however have to do away with the new myRectangle[lastMaxLabel] part as you would have to implement it as pert of your Insert() function.
This way you would not require to transfer the wanted elements into a new array, but just delete the unwanted element.
Any more light on your use-case would help us to think of better alternatives.
I agree with Michael Chinen - use std::vector instead. You'll avoid lots of other potential problems this way. If you really want to use dynamic arrays, see this question: Remove an array element and shift the remaining ones
if you have a big amount of data in array that will be a problem for shifting using loop
maybe you should build your own array management class (find,add,deleteAt,etc).
my suggestion use link list node method.. it will be faster rather then you use loop for shifting.

How to expand an array dynamically in C++? {like in vector }

Lets say, i have
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
Now I want to add a 6th element to the array. How do I do it?
You have to reallocate the array and copy the data:
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
// realloc
int* temp = new int[6];
std::copy(p, p + 5, temp); // Suggested by comments from Nick and Bojan
delete [] p;
p = temp;
You cannot. You must use a dynamic container, such as an STL vector, for this. Or else you can make another array that is larger, and then copy the data from your first array into it.
The reason is that an array represents a contiguous region in memory. For your example above, let us say that p points to address 0x1000, and the the five ints correspond to twenty bytes, so the array ends at the boundary of 0x1014. The compiler is free to place other variables in the memory starting at 0x1014; for example, int i might occupy 0x1014..0x1018. If you then extended the array so that it occupied four more bytes, what would happen?
If you allocate the initial buffer using malloc you can use realloc to resize the buffer. You shouldn't use realloc to resize a new-ed buffer.
int * array = (int*)malloc(sizeof(int) * arrayLength);
array = (int*)realloc(array, sizeof(int) * newLength);
However, this is a C-ish way to do things. You should consider using vector.
Why don't you look in the sources how vector does that? You can see the implementation of this mechanism right in the folder your C++ include files reside!
Here's what it does on gcc 4.3.2:
Allocate a new contiguous chunk of memory with use of the vector's allocator (you remember that vector is vector<Type, Allocator = new_allocator>?). The default allocator calls operator new() (not just new!) to allocate this chunk, letting himself thereby not to mess with new[]/delete[] stuff;
Copy the contents of the existing array to the newly allocated one;
Dispose previously aligned chunk with the allocator; the default one uses operator delete().
(Note, that if you're going to write your own vector, your size should increase "M times", not "by fixed amount". This will let you achieve amortized constant time. For example, if, upon each excession of the size limit, your vector grows twice, each element will be copied on average once.)
Same as others are saying, but if you're resizing the array often, one strategy is to resize the array each time by doubling the size. There's an expense to constantly creating new and destroying old, so the doubling theory tries to mitigate this problem by ensuring that there's sufficient room for future elements as well.