https://github.com/gameprogcpp/code/blob/master/Chapter02/Game.cpp
std::vector<Actor*> deadActors;
for (auto actor : mActors)
{
if (actor->GetState() == Actor::EDead)
{
deadActors.emplace_back(actor);
}
}
// Delete dead actors (which removes them from mActors)
for (auto actor : deadActors)
{
delete actor;
}
how is it okay?
when pointers in deadActors are deleted, their is no memory loss in mActors?
// Delete dead actors (which removes them from mActors)
This is incorrect; deleting the Actors does not modify the original vector. It only results in dereferencing the pointers to those Actors to be undefined behaviour.
You'd need an additional step removing the pointers from the original vector for this reason.
You could simply iterate through the vector removing the dead elements in one go though:
auto writePos = std::find_if(mActor.begin(), mActor.end(), [this](Actor* actor) {return actor->GetState() == Actor::EDead; });
if (writePos != mActor.end())
{
delete *writePos; // delete first
// move actors and delete dead ones
for (auto readPos = writePos + 1, end = mActor.end(); readPos != end; ++readPos)
{
if ((**readPos).GetState() == Actor::EDead)
{
delete *readPos;
}
else
{
// move non dead actor
*writePos = *readPos;
++writePos;
}
}
// remove unneeded space from the end
mActor.erase(writePos, mActor.end());
}
Note that this becomes much simpler, if you use an element type for the mActor vector that manages the lifetime of the Actor object. std::unique_ptr<Actor> would do the trick. This way any element erased from the vector automatically results in the deletion of the Actor object:
std::vector<std::unique_ptr<Actor>> actors = ...;
// remove all dead actors moving the remaining actors to the front
auto removeEnd = std::remove_if(actors.begin(), actors.end(), [](std::unique_ptr<Actor> const& actor) { return actor->GetState() == Actor::EDead; });
// remove extra space
std::actors.erase(removeEnd, actors.end());
Or with C++20:
std::vector<std::unique_ptr<Actor>> actors = ...;
std::erase_if(actors.begin(), actors.end(), [](std::unique_ptr<Actor> const& actor) { return actor->GetState() == Actor::EDead; });
Related
I have a server that puts 2 players together on request and starts a game Game in a new thread.
struct GInfo {Game* game; std::thread* g_thread};
while (true) {
players_pair = matchPlayers();
Game* game = new Game(players_pair);
std::thread* game_T = new std::thread(&Game::start, game);
GInfo ginfo = {game, game_T}
_actives.push_back(ginfo); // std::list
}
I am writing a "Garbage Collector", that runs in another thread, to clean the memory from terminated games.
void garbageCollector() {
while (true) {
for (std::list<Ginfo>::iterator it = _actives.begin(); it != _actives.end(); ++it) {
if (! it->game->isActive()) {
delete it->game; it->game = nullptr;
it->g_thread->join();
delete it->g_thread; it->g_thread = nullptr;
_actives.erase(it);
}
}
sleep(2);
}
}
This generates a segfault, I suspect it is because of the _active.erase(it) being in the iteration loop.
For troubleshooting, I made _actives an std::vector (instead of std::list) and applied the same algorithm but using indexes instead of iterators, it works fine.
Is there a way around this?
Is the algorithm, data structure used fine? Any better way to do the garbage collection?
Help is appreciated!
If you have a look at the documentation for the erase method it returns an iterator to the element after the one that was removed.
The way to use that is to assign the returned value to your iterator like so.
for (std::list<Ginfo>::iterator it = _actives.begin(); it != _actives.end();) {
if (! it->game->isActive()) {
delete it->game; it->game = nullptr;
it->g_thread->join();
delete it->g_thread; it->g_thread = nullptr;
it = _actives.erase(it);
}
else {
++it;
}
}
Since picking up the return value from erase advances the iterator to the next element, we have to make sure not to increment the iterator when that happens.
On an unrelated note, variable names starting with underscore is generally reserved for the internals of the compiler and should be avoided in your own code.
Any better way to do the garbage collection?
Yes, don't use new,delete or dynamic memory alltogether:
struct Players{};
struct Game{
Game(Players&& players){}
};
struct GInfo {
GInfo(Players&& players_pair):
game(std::move(players_pair)),g_thread(&Game::start, game){}
Game game;
std::thread g_thread;
};
std::list<GInfo> _actives;
void someLoop()
{
while (true) {
GInfo& ginfo = _actives.emplace_back(matchPlayers());
}
}
void garbageCollector() {
while (true) {
//Since C++20
//_active.remove_if([](GInfo& i){ return !i.game.isActive();});
//Until C++20
auto IT =std::remove_if(_actives.begin(),_actives.end(),
[](GInfo& i){ return !i.game.isActive();});
_active.erase(IT,_active.end());
//
sleep(2);
}
}
There might be a few typos, but that's the idea.
I'm trying to find all the processes in the blockedProcess list with the specified event number, copy them into a transferList, and then remove them. Copying and moving the Process objects works fine, but I can't figure out how to remove those Process objects from blockedProcess afterwards.
ProcessQueue findEventFlag(int eventnum)
{
ProcessQueue transferProcess;
Process process;
list<Process>::iterator it;
for (it = blockedProcess.begin(); it != blockedProcess.end(); it++)
{
process = *it;
if (process.getEvent() == eventnum)
{
process.setState("READY");
process.setEvent(-1);
transferProcess.enqueue(process);
}
}
return transferProcess;
}
Building on the comments, try this (which relies on the fact that std::list::erase conveniently returns an iterator to the next item in the list):
ProcessQueue findEventFlag(int eventnum)
{
ProcessQueue transferProcess;
Process process;
list<Process>::iterator it = blockedProcess.begin();
while (it != blockedProcess.end())
{
process = *it;
if (process.getEvent() == eventnum)
{
process.setState("READY");
process.setEvent(-1);
transferProcess.enqueue(process);
it = process.Erase (it);
}
else
it++;
}
return transferProcess;
}
You can also transfer an element from one list to another with std::list::splice which would avoid copying your process object and might therefore be more efficient, something like:
ProcessQueue findEventFlag(int eventnum)
{
ProcessQueue transferProcess;
Process process;
list<Process>::iterator it = blockedProcess.begin();
while (it != blockedProcess.end())
{
process = *it;
list<Process>::iterator next = std::next (it);
if (process.getEvent() == eventnum)
{
process.setState("READY");
process.setEvent(-1);
transferProcess.splice(transferProcess.begin (), blockedProcess, it);
}
it = next;
}
return transferProcess;
}
I have a struct called Node with 3 members, one of which acts as an id for the objects:
struct Node {
string mem1;
string mem2;
int id;
}
And a list containing pointers to Node objects:
list<Node*> g_node;
The problem comes when trying to erase a specific object from that list (localized by the id). I have this code but doesn't work:
list<Node>::iterator it = g_node.begin();
while (it != g_node.end()){
if (it->id == iden)
{
g_node->erase(it);
}
}
} else if (iden != 0) {
"iden" is the id of an object to be deleted, and is input by the user.
What's going wrong?
Why not use std::list::remove_if?
g_node.remove_if([iden](const Node *n){return n->id == iden;});
Note that this will not delete the Node object (neither does your original code). With containers holding pointers, you might want to consider smart pointers.
remove_if is a great idea, but if you want to have a function that you can easily reuse and customize at your will, you can do it like this:
bool remove_from_list(int id, list<Node*> &g_node)
{
auto it = g_node.begin();
while (it != g_node.end())
{
if ((*it)->id == id)
{
// free memory... if you allocated those pointers
delete (*it);
g_node.erase(it);
return true;
}
else
it++;
}
return false;
}
list<Node*> g_node;
g_node.push_back(new Node { "a", "b", 5 });
g_node.push_back(new Node { "ee", "77", 6 });
remove_from_list(5, g_node);
To begin: I have read many posts about the occurence of this error (e.g. boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed ) and as I can see they do not apply in my case.
Additionally I can not use RAII as often suggested in those posts.
Futher I can not give a "minimum compiling example" since this error does not occur there.
My Problem:
I have two mutexes in a class representing a FIFO-List the mutexes are used to lock the anchor-pointer and the back-pointer.
At that moment when the class is destroyed the destruction of the back_mutex fails after the anchor_mutex is already destroyed. This is the error mesage:
boost::mutex::~mutex(): Assertion `!posix::pthread_mutex_destroy(&m)' failed.
POSIX-Spec says the only two cases where pthread_mutex_destroy fails are EINVAL, if the mutex is invalid and EBUSY, if the mutex is locked or referenced.
Due to that knowledge i changed my Destructor to the following for testing:
template<class T>
Fifo_Emut<T>::~Fifo_Emut()
{
this->clear();
anchor_mutex.lock();
back_mutex.lock();
anchor_mutex.unlock();
back_mutex.unlock();
}
Despite that the error still constists at the same position.
As I would suggest the locking and unlocking of the mutex should fail if one of the two cases EINVAL or EBUSY is relevant. Also I can gurantee that the Thread calling the Destructor is the last living Thread all others joined before.
As an additional test I wrote a return in the first line of push_back and pop_front, then the error does not occur. It also occurs when only using push_back
For 'kind of' completeness the code using the mutexes in push_back and pop_front mehtods:
/**
* #brief appends a new list element to the back end of the list
* #param[in] data the data to be copied into the list_element
**/
template<class T>
void Fifo_Emut<T>::push_back(const T const& data)
{
back_mutex.lock();
if(back == NULL)
{
if(!anchor_mutex.try_lock())
{
//if we cannot aquire anchor_mutex we have to release back_mutex and try again to avoid a deadlock
back_mutex.unlock();
return this->push_back(data);
}
if(anchor == NULL)
{
MutexListElement<T>* tmp;
tmp = new MutexListElement<T>(data);
anchor = tmp;
back = tmp;
boost::interprocess::ipcdetail::atomic_write32(&number_of_elements, 1);
anchor_mutex.unlock();
back_mutex.unlock();
}
//else error normally handled
}
else
{
MutexListElement<T>* tmp;
back->lock();
tmp = new MutexListElement<T>(back, data);
boost::interprocess::ipcdetail::atomic_inc32(&number_of_elements);
back->unlock();
back = tmp;
back_mutex.unlock();
}
}
/**
* #brief erases the first element of the queue
* #returns a copy of the data held in the erased element
**/
template<class T>
T Fifo_Emut<T>::pop_front(void)
{
uint32_t elements = boost::interprocess::ipcdetail::atomic_read32(&number_of_elements);
if(elements == 0)
{
return NULL;
}
if(elements == 1)
{
anchor_mutex.lock();
back_mutex.lock();
if(elements == boost::interprocess::ipcdetail::atomic_read32(&number_of_elements))
{
//still the same so we can pop
MutexListElement<T>* erase = anchor;
erase->lock(); //we do not have to lock next since tis is the only one
anchor = NULL;
back = NULL;
boost::interprocess::ipcdetail::atomic_write32(&number_of_elements, 0);
anchor_mutex.unlock();
back_mutex.unlock();
T tmp = erase->getData();
erase->unlock();
delete erase;
return tmp;
}
else
{
//something has changed so we have to try again
back_mutex.unlock();
anchor_mutex.unlock();
return this->pop_front();
}
}
else
{
anchor_mutex.lock();
if(boost::interprocess::ipcdetail::atomic_read32(&number_of_elements) > 1)
{
//still more than one element in the queue so we can just pop whitout changing back pointer
MutexListElement<T>* erase = anchor;
erase->lock();
(dynamic_cast<MutexListElement<T>*>(anchor->next))->lock();
anchor = dynamic_cast<MutexListElement<T>*>(anchor->next);
anchor->prev = NULL;
boost::interprocess::ipcdetail::atomic_dec32(&number_of_elements);
anchor->unlock();
anchor_mutex.unlock();
T tmp = erase->getData();
erase->unlock();
delete erase;
return tmp;
}
else
{
//number of elements decreased to other case during locking
anchor_mutex.unlock();
return this->pop_front();
}
}
}
Question:
How is it possible that a 'functioning' mutex fails on being destroyed?
Or am I overseeing something here? How can I get rid of that error? What have I made wrong in my code and assumptions?
I have a while (!Queue.empty()) loop that processes a queue of elements. There are a series of pattern matchers going from highest-priority to lowest-priority order. When a pattern is matched, the corresponding element is removed from the queue, and matching is restarted from the top (so that the highest-priority matchers get a chance to act first).
So right now it looks something like this (a simplified version):
while (!Queue.empty())
{
auto & Element = *Queue.begin();
if (MatchesPatternA(Element)) { // Highest priority, since it's first
// Act on it
// Remove Element from queue
continue;
}
if (MatchesPatternB(Element)) {
// Act on it
// Remove Element from queue
continue;
}
if (MatchesPatternC(Element)) { // Lowest priority, since it's last
// Act on it
// Remove Element from queue
continue;
}
// If we got this far, that means no pattern was matched, so
// Remove Element from queue
}
This works, but I want to refactor this loop in some way to remove the use of the keyword continue.
Why? Because if I want to outsource a pattern matching to an external function, it obviously breaks. E.g.
void ExternalMatching(...)
{
if (MatchesPatternB(Element)) {
// Act on it
// Remove Element from queue
continue; // This won't work here
}
}
while (!Queue.empty())
{
auto & Element = *Queue.begin();
if (MatchesPatternA(Element)) {
// Act on it
// Remove Element from queue
continue;
}
ExternalMatching(...);
if (MatchesPatternC(Element)) {
// Act on it
// Remove Element from queue
continue;
}
// If we got this far, that means no pattern was matched, so
// Remove Element from queue
}
I don't want to have to write repetitive if statements like if (ExternalMatching(...)) { ... continue; }, I'd rather find a cleaner way to express this logic.
This simplified example might make it seem like a good idea to make pattern matching more general rather than having distinct MatchesPatternA, MatchesPatternB, MatchesPatternC, etc. functions. But in my situation the patterns are quite complicated, and I'm not quite ready to generalize them yet. So I want to keep that part as is, separate functions.
Any elegant ideas? Thank you!
If you have access to C++11 I would like to suggest another solution. Basicaly I created a container of handlers and actions that can be adjusted in runtime. It may be a pro or con for your design depending on your requirements. Here it is:
#include <functional>
typedef std::pair<std::function<bool(const ElementType &)>,
std::function<void(ElementType &)> > HandlerData;
typedef std::vector<HandlerData> HandlerList;
HandlerList get_handlers()
{
HandlerList handlers;
handlers.emplace_back([](const ElementType &el){ return MatchesPatternA(el); },
[](ElementType &el){ /* Action */ });
handlers.emplace_back([](const ElementType &el){ return MatchesPatternB(el); },
[](ElementType &el){ /* Action */ });
handlers.emplace_back([](const ElementType &el){ return MatchesPatternC(el); },
[](ElementType &el){ /* Action */ });
return handlers;
}
int main()
{
auto handlers = get_handlers();
while(!Queue.empty()) {
auto &Element = *Queue.begin();
for(auto &h : handlers) {
// check if handler matches the element
if(h.first(Element)) {
// act on element
h.second(Element);
break;
}
}
// remove element
Queue.pop_front();
}
}
I would recommend using a function that does the pattern matching (but does not act on the result) and then a set of functions that act on the different options:
enum EventType {
A, B, C //, D, ...
};
while (!queue.empty()) {
auto & event = queue.front();
EventType e = eventType(event); // Internally does MatchesPattern*
// and returns the match
switch (e) {
case A:
processA(event);
break;
case B:
processB(event);
This way you clearly separate the matching from the processing, the loop is just a simple dispatcher
Consider an interface:
class IMatchPattern
{
public:
virtual bool MatchesPattern(const Element& e) = 0;
};
Then you can organize a container of objects implementing IMatchPattern, to allow for iterative access to each pattern match method.
You can change your ExternalMatching to return bool, indicating that the processing has been done. This way the caller would be able to continue evaluating if necessary:
bool ExternalMatching(...)
{
if (MatchesPatternB(Element) {
// Act on it
// Remove Element from queue
return true;
}
return false;
}
Now you can call it like this:
if (ExternalMatchin1(...)) continue;
if (ExternalMatchin2(...)) continue;
...
if (ExternalMatchingN(...)) continue;
Ok, I ended up rewriting the loop more akin to this.
Huge thanks and credit goes to Yuushi, dasblinkenlight, David RodrÃguez for their help; this answer is based on a combination of their answers.
bool ExternalMatching(...)
{
bool Match;
if ((Match = MatchesPatternX(Element))) {
// Act on it
} else if ((Match = MatchesPatternY(Element))) {
// Act on it
}
return Match;
}
while (!Queue.empty())
{
auto & Element = Queue.front();
if (MatchesPatternA(Element)) { // Highest priority, since it's first
// Act on it
} else if (MatchesPatternB(Element)) {
// Act on it
} else if (ExternalMatching(...)) {
} else if (MatchesPatternC(Element)) { // Lowest priority, since it's last
// Act on it
}
// Remove Element from queue
}
Now, I know there's further room for improvement, see answers of Mateusz Pusz and Michael Sh. However, this is good enough to answer my original question, and it'll do for now. I'll consider improving it in the future.
If you're curious to see the real code (non-simplified version), see here:
https://github.com/shurcooL/Conception/blob/38f731ccc199d5391f46d8fce3cf9a9092f38c65/src/App.cpp#L592
Thanks everyone again!
I would like to suggest a Factory function that would take the Element and create an appropriate handler and return the interface pointer to the handler.
while (!Queue.empty())
{
auto & Element = *Queue.begin();
// get the appropriate handler object pointer e.g.
IPatternHandler *handler = Factory.GetHandler(Element);
handler->handle();
// clean up handler appropriately
}