I am working on code which implements a Multilevel Feedback Queue Scheduler. There is something not clear in a part of the code:
void Scheduler_MFQS :: fill_queue(int clk) {
list<Process>::iterator itr;
for(itr = processes.begin(); itr != processes.end(); itr++) {
if((itr -> has_arrived(clk)) && (!queues[0].contains(*itr))) {
Process tmp (*itr);
queues[0].add_process(tmp);
remove(processes.begin(), processes.end(), *itr);
}
}
}
What this basically does is just put the process into the base queues under some condition. But i don't know what Process tmp (*itr); means? However, it compiles legally. Does that mean create a Process object called tmp? But what is the next, iterator (*itr) mean in c++?
"Process tmp (*itr);" mean?
It calls Process(const Process& &) copy constructor to create tmp object;
what is the next, iterator (*itr) mean in c++?
itr is std::list::iterator type, it's a pointer to current list node. *itr is getting the content of itr, which is a Process.
Your code can enhance a bit, demo as below:
// list<Process>::iterator itr; // move this into for loop, narrow variable scope and lifetime
/*auto if C++11*/
processes.unique(); // you actually only want unique processes from list
for(list<Process>::iterator itr = processes.begin(); itr != processes.end(); ++itr)
^^ call preincrement, faster
{
if((itr -> has_arrived(clk)) /*&& (!queues[0].contains(*itr))*/) {
^^ process list contains unique item only, no need to compare
//Process tmp (*itr); comment out this line, save one object copy
queues[0].add_process(*itr);
//remove(processes.begin(), processes.end(), *itr);
// You don't need to clear item in the loop
}
}
processes.clear(); // or swap with an empty list
// std::list<Process> p2;
// p2.swap(ps);
itr is the iterator which points to some container element(list in your case). When you use asterisk(*) on iterator you gain access to its content i.e. to the actual element of the list. In your case it is a Process object.
Related
In my application I need the ability to traverse a doubly linked list starting from any arbitrary member of the list and continuing past the end(), wrapping around to the begin() and continue until the traversal reaches where it started.
I decided to use std::list for the underlying data structure and wrote a circulate routine to achieve this. However it's showing certain unexpected behavior when it's wrapping around from end() to begin(). Here's my implementation
template <class Container, class BiDirIterator>
void circulate(Container container, BiDirIterator cursor,
std::function<void(BiDirIterator current)> processor)
{
BiDirIterator start = cursor;
do {
processor(cursor);
cursor++;
if (cursor == container.end()) {
cursor = container.begin(); // [A]
}
} while (cursor != start);
}
// ...
typedef int T;
typedef std::list<T> TList;
typedef TList::iterator TIter;
int count = 0;
TList l;
l.push_back(42);
circulate<TList, TIter>(
l, l.begin(),
[&](TIter cur) {
std::cout << *cur << std::endl;
count++;
}
);
The output is:
42
-842150451
When I step through the code I see that the line marked [A] is never reached. The cursor is never equal to container.end(). Surprisingly, invoking ++ on that cursor, takes it to container.begin() in next pass automatically. (I suppose that's specific to this STL implementation).
How can I fix this behavior?
The issue here is that you are taking Container by value. This causes a copy so the iterators returned by container.end() and container.begin() are not that same as the iterator passed to the function. Instead if you pass Container by reference then the code works correctly.
Live Example
I have a map of key/value pointers :
std::map<A*, B*> myMap;
What would be the proper way to liberate the memory of the key only?
I was thinking about doing this :
for (auto itr = _myMap.begin(); itr != _myMap.end(); itr++)
{
if (certainCondition == true)
{
delete itr->first;
itr->first = nullptr;
}
}
Is it the correct way of doing it? Will my map keep nullptr as a key and future iteration will include nullptr?
You cannot modify the key of the container because it is used to define the ordering and changing it in place could invalidate the ordering. Furthermore, each key needs to be unique. Therefore, you need to remove the item from the map then clean up the memory.
If you already have the key:
myMap.erase(key);
delete key;
If you already have an iterator within the map:
A* keyCopy = itr->first;
myMap.erase(itr);
delete keyCopy;
Edit
Per your updated question:
auto itr = myMap.begin();
while (itr != myMap.end())
{
if (certainCondition == true)
{
A* keyCopy = itr->first;
itr = myMap.erase(itr);
delete keyCopy;
}
else
{
++itr;
}
}
erase() the element from the map, then delete the pointer that was acting as the key (if necessary, cached the pointer before the erase, if it does not exist anywhere else)
A map can only have one occurrence of each unique key. Even if it were possible - what would happen if you wanted to nullptr out more than one of the elements' keys? Nothing useful!
The key is const. You should not be able to change it.
http://www.cplusplus.com/reference/map/map/
A family object contains a linked list of Person objects, and as such, a function exists within the Family class to insert Person objects into a ListedList called people.
I’m having some trouble where only certain Person objects are being added to the people linked list. I have omitted a number of other functions, as I was (hopefully) able to determine the problem is occurring within the insertPerson() function in the Family class.
The for loop within insertPacket() is looping through each ‘Person’ object as intended (refer to commented ‘cout’). However, things break down in the if statement..
if (person_id < itr->get_person_id())
{
Person *psn = new Person(person_id, name);
people.insert(itr, *psn);
break;
}
If a person_id is less than the get_person_id() in the linked list, it executes and inserts it at the beginning of the list, however if it is not, it just skips it entirely...
You're fundamental bug is here, in insertPerson:
for(itr = people.begin(); itr != people.end(); itr++)
{
if (id < itr->get_person_id())
{
people.insert(itr, Person(id, text));
break;
}
}
What if the person's id is greater than all of the current list members? Then the insert will never happen as you will reach end() and break the loop. This should be used to find the insertion point, which can include end().
You can find the proper insertion point doing this:
for(itr = people.begin(); itr != people.end(); itr++)
{
if (itr->get_person_id() < id)
break;
}
people.insert(itr, Person(id, text));
Note that this will allow duplicate insertions for a given id. Not sure if you care about that. Finally, the same problem exists for insertion of a Family, so you probably want to fix that after this.
Best of luck.
Try
if (input_id < itr->get_familyid())
{
Family *fam = new Family(input_id);
families.insert(itr, *fam);
break;
}
std::list insert according to this link is
iterator insert (iterator position, const value_type& val);
I couldn't find an instance of how to do this, so I was hoping someone could help me out. I have a map defined in a class as follows:
std::map<std::string, TranslationFinished> translationEvents;
TranslationFinished is a boost::function. I have a method as part of my class that iterates through this map, calling each of the functions like so:
void BaseSprite::DispatchTranslationEvents()
{
for(auto it = translationEvents.begin(); it != translationEvents.end(); ++it)
{
it->second(this);
}
}
However it's possible for a function called by it->second(this); to remove an element from the translationEvents map (usually itself) using the following function:
bool BaseSprite::RemoveTranslationEvent(const std::string &index)
{
bool removed = false;
auto it = translationEvents.find(index);
if (it != translationEvents.end())
{
translationEvents.erase(it);
removed = true;
}
return removed;
}
doing this causes a debug assertion fail when the DispatchTranslationEvents() tries to increment the iterator. Is there a way to iterate through a map safely with the possibility that a function call during the iteration may remove an element from the map?
Thanks in advance
EDIT: Accidently C/Pd the wrong Remove Event code. Fixed now.
map::erase invalidates the iterator being deleted (obviously), but not the rest of the map.
This means that:
if you delete any element other than the current one, you're safe, and
if you delete the current element, you must first get the next iterator, so you can continue iterating from that (that's why the erase function for most containers return the next iterator). std::map's doesn't, so you have to do this manually)
Assuming you only ever delete the current element, then you could simply rewrite the loop like this:
for(auto it = translationEvents.begin(); it != translationEvents.end();)
{
auto next = it;
++next; // get the next element
it->second(this); // process (and maybe delete) the current element
it = next; // skip to the next element
}
Otherwise (if the function may delete any element) it may get a bit more complicated.
Generally speaking it is frowned upon to modify the collection during iteration. Many collections invalidate the iterator when the collection is modified, including many of the containers in C# (I know you're in C++). You can create a vector of events you want removed during the iteration and then remove them afterwards.
After reading all other answers, I am at an advantage here... But here it goes.
However it's possible for a function called by it->second(this); to remove an element from the translationEvents map (usually itself)
If this is true, that is, a callback can remove any element from the container, you cannot possibly resolve this issue from the loop itself.
Deleting the current callback
In the simpler case where the callback can only remove itself, you can use different approaches:
// [1] Let the callback actually remove itself
for ( iterator it = next = m.begin(); it != m.end(); it = next ) {
++next;
it->second(this);
}
// [2] Have the callback tell us whether we should remove it
for ( iterator it = m.begin(); it != m.end(); ) {
if ( !it->second(this) ) { // false means "remove me"
m.erase( it++ );
} else {
++it;
}
}
Among these two options, I would clearly prefer [2], as you are decoupling the callback from the implementation of the handler. That is, the callback in [2] knows nothing at all about the container in which it is held. [1] has a higher coupling (the callback knows about the container) and is harder to reason about as the container is changed from multiple places in code. Some time later you might even look back at the code, think that it is a weird loop (not remembering that the callback removes itself) and refactor it into something more sensible as for ( auto it = m.begin(), end = m.end(); it != end; ++it ) it->second(this);
Deleting other callbacks
For the more complex problem of can remove any other callback, it all depends on the compromises that you can make. In the simple case, where it only removes other callbacks after the complete iteration, you can provide a separate member function that will keep the elements to remove, and then remove them all at once after the loop completes:
void removeElement( std::string const & name ) {
to_remove.push_back(name);
}
...
for ( iterator it = m.begin(); it != m.end(); ++it ) {
it->second( this ); // callback will possibly add the element to remove
}
// actually remove
for ( auto it = to_remove.begin(); it != to_begin.end(); ++it ) {
m.erase( *it );
}
If removal of the elements need to be immediate (i.e. they should not be called even in this iteration if they have not yet been called), then you can modify that approach by checking whether it was marked for deletion before executing the call. The mark can be done in two ways, the generic of which would be changing the value type in the container to be a pair<bool,T>, where the bool indicates whether it is alive or not. If, as in this case, the contained object can be changed you could just do that:
void removeElement( std::string const & name ) {
auto it = m.find( name ); // add error checking...
it->second = TranslationFinished(); // empty functor
}
...
for ( auto it = m.begin(); it != m.end(); ++it ) {
if ( !it->second.empty() )
it->second(this);
}
for ( auto it = m.begin(); it != m.end(); ) { // [3]
if ( it->second.empty() )
m.erase( it++ );
else
++it;
}
Note that since a callback can remove any element in the container, you cannot erase as you go, as the current callback could remove an already visited iterator. Then again, you might not care about leaving the empty functors for a while, so it might be ok just to ignore it and perform the erase as you go. Elements already visited that are marked for removal will be cleared in the next pass.
My solution is to first create a temporary container, and swap it with the original one. Then you can iterator through the temporary container and insert the ones you want to keep to the original container.
void BaseSprite::DispatchTranslationEvents()
{
typedef std::map<std::string, TranslationFinished> container_t;
container_t tempEvents;
tempEvents.swap(translationEvents);
for(auto it = tempEvents.begin(); it != tempEvents.end(); ++it)
{
if (true == it->second(this))
translationEvents.insert(it);
}
}
And the TranslationFinished functions should return true if it want to be keeped and return false to get removed.
bool BaseSprite::RemoveTranslationEvent(const std::string &index)
{
bool keep = false;
return keep;
}
There should be a way for you to erase a element during your iteration, maybe a little tricky.
for(auto it = translationEvents.begin(); it != translationEvents.end();)
{
//remove the "erase" logic from second call
it->second(this);
//do erase and increase the iterator here, NOTE: ++ action is very important
translationEvents.erase(it++);
}
The iterator will be invalid once the element is removed, so you can not use that iterator to do increase action anymore after you remove it. However, remove an element will not affect other element in map implementation, IIRC. So suffix ++ will copy the iter first and increase the iterator right after that, then return the copy value, which means iterator is increased before erase action, this should be safe for you requirement.
You could defer the removal until the dispatch loop:
typedef boost::function< some stuff > TranslationFunc;
bool BaseSprite::RemoveTranslationEvent(const std::string &index)
{
bool removed = false;
auto it = translationEvents.find(index);
if (it != translationEvents.end())
{
it->second = TranslationFunc(); // a null function indicates invalid event for later
removed = true;
}
return removed;
}
protect against invoking an invalid event in the loop itself, and cleanup any "removed" events:
void BaseSprite::DispatchTranslationEvents()
{
for(auto it = translationEvents.begin(); it != translationEvents.end();)
{
// here we invoke the event if it exists
if(!it->second.empty())
{
it->second(this);
}
// if the event reset itself in the map, then we can cleanup
if(it->second.empty())
{
translationEvents.erase(it++); // post increment saves hassles
}
else
{
++it;
}
}
}
one obvious caveat is if an event is iterated over, and then later on deleted, it will not get a chance to be iterated over again to be deleted during the current dispatch loop.
this means the actual deletion of that event will be deferred until the next time the dispatch loop is run.
The problem is ++it follows the possible erasure. Would this work for you?
void BaseSprite::DispatchTranslationEvents()
{
for(auto it = translationEvents.begin(), next = it;
it != translationEvents.end(); it = next)
{
next=it;
++next;
it->second(this);
}
}
I have a really strange problem with stl vectors in which the wrong destructor is called for the right object when I call the erase method if that makes any sense.
My code looks something like this:
for(vector<Category>::iterator iter = this->children.begin(); iter != this->children.end(); iter++)
{
if((*iter).item == item)
{
this->children.erase(iter);
return;
}
-------------------------
}
It's just a simple function that finds the element in the vector which has some item to be searched, and removes said element from the vector. My problem is than when the erase function is called, and thus the object which the iterator is pointing at is being destroyed, the wrong destructor is being called. More specific the destructor of the last element in the vector is being called, and not of the actual object being removed. Thus the memory is being removed from the wrong object, which will still be an element in the vector, and the actual object which is removed from the vector, still has all of it's memory intact.
The costructor of the object looks like this:
Category::Category(const Category &from)
{
this->name = from.name;
for(vector<Category>::const_iterator iter = from.children.begin(); iter != from.children.end(); iter++)
this->children.push_back((*iter));
this->item = new QTreeWidgetItem;
}
And the destructor
Category::~Category()
{
this->children.clear();
if(this->item != NULL)
{
QTreeWidgetItem* parent = this->item->parent();
if(parent != NULL) parent->removeChild(this->item);
delete this->item;
}
}
When you erase your element from the vector, each element after it is copied (using the assignment operator) to the previous spot in the vector. Once this is complete, the last element in the vector is destructed. This could be why you're seeing your last element get destructed. Rule number one when using the STL is to ensure the copy semantics for your object are correct.
You should consider writing an assignment operator:
Category & operator =(const Category & other);
Although this may not be as simple as it sounds, considering objects will be copied and destructed many times in the vector.
You probably should use standard algorithms.
The main issue I see is that your destructor for Category asks its parent vector to remove it. That cannot be right, the destructor happens only when the vector is already removing it.
std::vector uses placement-new so will be calling your destructor directly. I do not know what the effect will be to go back to the vector at this point.
Remove the line if (parent != NULL ) parent->removeChild(this->item) from the destructor. It is not what you want.
This is expected behavior. On my implementation (and I am guessing, on yours) when erasing an element from a vector, elements from n+1 to the end are assigned into it and the very last element is destructed.
Use std::list if you don't want this to happen.
Demo:
#include <iostream>
#include <vector>
struct Category
{
int item;
Category(int n=0) : item(n) {}
~Category() { std::cout << "Category " << item << " destroyed\n"; }
};
int main()
{
std::vector<Category> children(3);
children[0] = Category(0);
children[1] = Category(1);
children[2] = Category(2);
int item = 0;
std::cout << " beginning the loop \n";
for( std::vector<Category>::iterator iter = children.begin();
iter != children.end(); ++iter)
{
if(iter->item == item)
{
children.erase(iter); // prints "Category 2 destroyed"!
break;
}
}
std::cout << " loop done \n";
} // this will print "Category 1 destroyed" and "Category 2 destroyed"
And yes, explicit erase/remove_if is more readable than the loop.