Accessing pointers after erasing from Map - c++

The sample scenario in my code implementation is as follows
I have a map defined as map<int,map<int,object*>*> . The inner map which is in heap has a object pointer.
The scenario is,
After using(processing) all the elements in the inner map. I will erase the inner map contents using iterator. But the object* will not be deleted. I will use the object pointer further after erasing the key from the map.
My question is will that object* exist even after erasing it's presence in the map. As far as my understanding , yes the object is in heap and it can be used even after the erase in map. But i am facing random crash in the process after few minutes of execution. This makes me to post the question here.
multimap<ULONG, Class*>::iterator it_top3 = InnerMap->begin();
if (InnerMap->size() >= classLimit)
{
if (it_top3->first <= ClassObj->m_classSize)
{
if (it_top3->second != NULL)
{
delete it_top3->second;
it_top3->second = NULL;
}
InnerMap->erase(it_top3);
InnerMap->insert(pair<ULONG, Class*>(ClassObj->m_classSize, ClassObj));
}
Secondly , On analyzing debug diag the line it_top3->second = NULL; points as the crash point with access violation exception. What would be possible reason for the crash here.?

You don't just erase from map, the line
delete it_top3->second;
it_top3->second = NULL;
deallocates the pointer, which may cause your crashes.
Just the InnerMap->erase() call would do what you'd expect.

Related

Am I deleting my vector of pointers to objects correctly?

i am currently working on a programm, where i read Information from various CAN signals and store them in 3 different vectors.
For each signal, a new pointer to an object is created an stored in two vectors.
My question is, when i am deleting the vectors, is it enough, when i delete the pointers to the objects in one vector and just clear the other one.
Here is my code:
Declaration of vectors an iterator:
std::vector <CAN_Signal*> can_signals; ///< Stores all CAN signals, found in the csv file
std::vector <CAN_Signal*> can_signals_rx; ///< Stores only the Rx CAN signals, found in the csv file
std::vector <CAN_Signal*> can_signals_tx; ///< Stores only the Tx CAN signals, found in the csv file
std::vector <CAN_Signal*>::iterator signal_iterator; ///< Iterator for iterating through the varoius vectors
Filling the vectors:
for (unsigned int i = 0; i < m_number_of_lines; ++i)
{
string s = csv_file.get_line(i);
CAN_Signal* can_signal = new CAN_Signal(s, i);
if (can_signal->read_line() == false)
return false;
can_signal->generate_data();
can_signals.push_back(can_signal);
if (get_first_character(can_signal->get_PDOName()) == 'R')
{
can_signals_rx.push_back(can_signal);
}
else if (get_first_character(can_signal->get_PDOName()) == 'T')
{
can_signals_tx.push_back(can_signal);
}
else
{
cout << "Error! Unable to detect whether signal direction is Rx or Tx!" << endl;
return false;
}
}
Deleting the vectors:
File_Output::~File_Output()
{
for (signal_iterator = can_signals.begin(); signal_iterator != can_signals.end(); ++signal_iterator)
{
delete (*signal_iterator);
}
can_signals.clear();
//for (signal_iterator = can_signals_rx.begin(); signal_iterator != can_signals_rx.end(); ++signal_iterator)
//{
// delete (*signal_iterator);
//}
can_signals_rx.clear();
//for (signal_iterator = can_signals_tx.begin(); signal_iterator != can_signals_tx.end(); ++signal_iterator)
//{
// delete (*signal_iterator);
//}
can_signals_tx.clear();
cout << "Destructor File_Output!" << endl;
}
When i uncomment the commented for-loops and run the Programm, it crashes, when the destructor is called.
So my guess is, that this is the correct way of doing so, because the pointers are allready deleted and it is enough to just clear remaining two vectors.
But i am not really sure and would really like to hear the opinion of an expert on this.
Thank you very much.
when i am deleting the vectors, is it enough, when i delete the pointers to the objects in one vector and just clear the other one.
Since the pointers in the other vectors are copies, not only is it sufficient to delete them only in the one vector, but deleting the copies would in fact have undefined behaviour. You don't ever want your program to have undefined behaviour.
Clearing any of the vectors in the destructor of File_Output seems to be unnecessary, assuming the vectors are members of File_Output. This is because the members are about to be destroyed anyway.
Am I deleting my vector of pointers to objects correctly?
With the assumption that you didn't make copies of the pointers that you delete elsewhere: Yes, that is the correct way to delete them.
Your code has a memory leak:
CAN_Signal* can_signal = new CAN_Signal(s, i);
if (can_signal->read_line() == false)
return false;
If that condition is true, then the newly allocated CAN_Signal will be leaked since the pointer is neither deleted nor stored anywhere when the function returns.
Your code is not exception safe: If any of these lines throws, then the pointer is leaked.
if (can_signal->read_line() == false)
return false;
can_signal->generate_data();
can_signals.push_back(can_signal);
It is unclear, why you would want to use explicit memory management in the first place. Unless there is a reason, I recommend that you don't do that and instead use std::vector <CAN_Signal> can_signals. This would fix your problems with memory leaks and exception safety, remove the need to implement a custom destructor, and make the implementation of copy/move constructor/assignment of File_Output simpler.
Note that if you do that, you must reserve the memory for the elements for can_signals to prevent reallocation because the pointers in other vectors would be invalidated upon reallocation. As a side-effect, this makes the program slightly faster.

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 do you change a std::map element while iterating?

I have a large array of object pointers (lets call it A), and a smaller map of object pointers (M) keyed with the index of A.
While iterating M, I want to swap the mapped pointer (second) with the pointer that is currently at that index (first) in A.
I have something like this:
map<LONG, Object*>::iterator mit;
for (mit = M.begin(); mit != M.end(); mit++)
{
if ((*mit).first != NO_ID)
{
Object* pTmp = pA->ReplaceObject((*mit).first, (*mit).second);
if (pTmp != NULL)
{
M.at((*mit).first) = pTmp;
}
}
}
Here ReplaceObject first gets A[(*mit).first] for return, then changes A[(*mit).first] to (*mit).second.
My mapped pointer is staying stubbornly unchanged - though the debugger, appears to show the change happens correctly.
What am I doing wrong?
A great 'wood-for-the-trees' moment - I was simply negelcting to copy my altered undo operation back to the undo stack. Once I stopped looking for the "error" and just read my code, it was obvious! D'oh!

Vector iterators incompatible: runtime error

I'm currently having trouble with a destructor of a class which contains a vector of objects. The application runs fine, however upon freeing the heap it throws an error.
Here is the code of my destructor:
~StaticNetwork(void) { // clear memory
for(vector<Node*>::iterator iter = nodes.begin(); iter != nodes.end(); )
nodes.erase(iter++);
}
And nodes are being added to the network as follows:
if((temp = is_already_added(regex_d[1])) >= 0) // check if the src node has already been added
{
if((temp1 = is_already_added(regex_d[2])) >= 0) // check if the next_hop has already been added
{
nodes[temp]->add_n_vchannels(regex_d[5]);
nodes[temp]->add_next_hop(nodes[temp1]);
}
else // the next_hop has not been added
{
Node *anext_hop = new Node(regex_d[2]);
nodes[temp]->add_next_hop(anext_hop);
nodes[temp]->add_n_vchannels(regex_d[5]);
nodes.push_back(anext_hop); // add next hop
param.n_of_nodes++;
}
}
The network is comprised of pointers to the actual nodes.
Any help/suggestion/reference/(constructive)criticism will be greatly appreciated.
Your iteration over the container is wrong. If the node is a member of the class, then ignore it as the destructor of the vector will take care of it. If it is not a member and you really want to remove all elements, the simplest thing is calling node.clear() (Note both are equivalent to your code, but they will leak the pointed memory if it should be managed by your class)
If the pointers are managed by your class, consider using smart pointers or specific pointer containers. Else the simplest loop to free all memory would be:
for ( std::vector<Node*>::iterator it = nodes.begin(); it != nodes.end(); ++it )
delete *it;
Note that I did not modify the container itself, just the contained elements.
You do not need to delete elements of vector manually, it will be done by vector itself. This is how destructors work: they call destructors of member objects of deleted object, so you don't have to worry about it.
erase doesn't work as you expect: it removes the elements from the container, i.e. the pointers and not the pointed object. So you are leaking memory here.
Moreover, erase invalidates the iterators following the erased element(s), thus the test iter != nodes.end(); causes the error, as you increment the pointer past it.
Anyway, you can write the code as shown by David Rodríguez - dribeas.

Why is this vector iterator not incrementable?

I'm trying to delete the vector's content and I'm getting an error - vector iterator is not incrementable, why is that?
This is my destructor:
City::~City()
{
vector <Base*>::iterator deleteIterator;
for (deleteIterator = m_basesVector.begin() ; deleteIterator != m_basesVector.end() ; deleteIterator++)
m_basesVector.erase(deleteIterator);
}
thanks.
erase invalidates the iterator. You can't use it any more. Luckily for you, it returns an iterator that you can use:
vector <Base*>::iterator deleteIterator = m_basesVector.begin();
while (deleteIterator != m_basesVector.end()) {
deleteIterator = m_basesVector.erase(deleteIterator);
}
Or:
m_basesVector.clear();
Are you responsible for freeing the memory referred to by the pointers in the vector? If that's the reason that you're iterating (and your real program has more code that you haven't shown, that frees those objects in the loop), then bear in mind that erasing from the beginning of a vector is a slow operation, because at each step, all the elements of the vector have to be shifted down one place. Better would be to loop over the vector freeing everything (then clear() the vector, although as Mike says that's not necessary if the vector is a member of an object that's being destroyed).
The problem is that you are trying to use an iterator while using the erase() function. erase(), push_back(), insert(), and other modifying functions invalidate iterators in STL.
Just use the clear() function:
City::~City()
{
m_basesVector.clear();
}
If you are trying to free the data in the vector, do this:
for (std::vector<Base*>::iterator it = v.begin(), e = b.end(); it != e; ++it)
delete *it;
Posting this just incase anyone else has this this problem and attempts this solution wondering why it's not working here's an actual solution/explanation.
#Steve Jessop - Your code is flawed and you've also got it written here... ( I've also edited his post to fix the issue as soon as it's approved it'll be fixed in the original post )
http://techsoftcomputing.com/faq/3779252.html
I don't see how this is a "Solution" to the issue when it create an new issue by making an endless loop there should be a deleteIterator++ within the while loop so that it actually reaches the end of the vector.
Also I've ran into this problem and my solution was inside the while loop checking whether the iterator was equal to the end or if the vector size was 0 and breaking before attempting to incrementing the iterator.
Ex.
std::vector<RankPlayer*>::iterator Rank_IT = CurrentPlayers.begin();
while ( Rank_IT != CurrentPlayers.end() )
{
RankPlayer* SelPlayer = (*Rank_IT);
if( strstr( SelPlayer->GamerTag, this->GamerTag ) != NULL )
{
delete[] SelPlayer->PlayerData;
delete[] SelPlayer;
Rank_IT = CurrentPlayers.erase( Rank_IT );
}
if( Rank_IT == CurrentPlayers.end() || CurrentPlayers.size() == 0 )
{
break;
}
++Rank_IT;
}
This is not relevant to the original problem posted above, but Google search on the error takes me to this page so I am posting it here for anyone to see.
I ran into this error message recently and all lines of codes checked out (there was no 'erase' or anything alike; the vector was merely read).
Eventually, I realized that there is a problem with nested loops.
For example, consider something like this:
`for (it=begin(); it!=end();i++)
{
for (; it!=end();i++)
{
}
}`
When you are done with the nested loop, it will increment the iterator - and then, the parent loop will increment it again(!), ultimately making the iterator step over the end(). I.e. it would be "end()+1" if there were such a thing.
Consequently, the parent loop throws this error at the next check.
To get around this, I ended up insert this line after the child loop:
`if (it == vStringList.end()) --it;`
Dirty, but works :D
I know it may be obvious to some, but I've been scratching my head over this for a while, lol
Any iterator pointing to the deleted element or to the elements after the one that is deleted gets invalidated when the vector's erase method is called. Erase method returns a valid iterator pointing to the next element in the vector. You should use that iterator to continue your looping & not increment the invalidated iterator. You may also use the clear method to remove all the elements in the vector. However, you will need to remember to explicitly de-allocate any allocated memory for the elements.
This code leaks all the contents of the vector - you have to delete *deleteIterator in the loop too. You can avoid all of this by using Base instead of Base* as the vector contents, then clear() will destruct them for you. Or use boost::ptr_vector which automates destruction if you do need raw pointers.
Calling erase() in a forward iteration like this can be very costly if the vector is large, as every element above the current position has to be moved down to ensure elements remain contiguous. Avoid manual erase of the type you propose, for this and other reasons.
Vector iterators are incrementable, but if you delete elements, the vector contents are modified and thus the iterator is invalid.
So, if you delete objects, you should use the return value of erase() that gives you the next valid iterator.