std :: list и алгоритм сборки мусора - PullRequest
0 голосов
/ 08 марта 2019

У меня есть сервер, который объединяет 2 игроков по запросу и запускает игру Game в новой теме.

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
}

Я пишу «Сборщик мусора», который запускается в другом потоке для очистки памяти от прерванных игр.

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);
    }
}

Это генерирует segfault, я подозреваю, что это из-за того, что _active.erase(it) находится в цикле итерации. Для устранения неполадок я сделал _actives std::vector (вместо std::list) и применил тот же алгоритм, но с использованием индексов вместо итераторов, он работает нормально.

Есть ли способ обойти это?

Хорошо ли использован алгоритм, структура данных? Есть ли лучший способ сделать сборку мусора?

Помощь приветствуется!

Ответы [ 2 ]

1 голос
/ 08 марта 2019

Если вы посмотрите документацию по методу erase , он возвращает итератор для элемента после того, который был удален.

Способ использования этого - присвоить возвращаемое значение вашему итератору следующим образом.

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;
    }
}

Поскольку получение возвращаемого значения из erase переводит итератор к следующему элементу, мы должны быть уверены, что не увеличим итератор, когда это произойдет.

На несвязанной ноте имена переменных, начинающиеся с подчеркивания, обычно зарезервированы для внутренних компонентов компилятора, и их следует избегать в вашем собственном коде.

0 голосов
/ 08 марта 2019

Есть ли лучший способ сделать сборку мусора?

Да, не используйте new,delete или динамическую память вообще:

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);
    }
}

Там может быть несколько опечаток, но это идея.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...