0

So here's my problem.. I have a 2d array of 2 char strings.

9D 5C 6S 9D KS 4S 9D
         9S

If 3 found I need to delete the first 3 based on the first char. card My problem is I segfault almost anything i do... pool is the 2d vector

        selection = "9S";
        while(col != GameBoard::pool.size()  ){
            while(GameBoard::pool[col][0].at(0) == selection.at(0) || cardsRem!=0){
                if(GameBoard::pool[col].size() == 1){
                    GameBoard::pool.erase(GameBoard::pool.begin() + col);
                    cardsRem--;                        
                }
                else{
                    GameBoard::pool[col].pop_back();
                    cardsRem--;
                }
            }
            if(GameBoard::pool[col][0].at(0) != selection.at(0)){
                col++;
            }
        }

I've tried a series of for loops etc, and no luck! Any thoughts would save my sanity!

So I've tried to pull out a code segment to replicate it. But I can't... If I run my whole program in a loop it will eventually throw a segfault. If I run that exact code in the same circumstance it doesn't... I'm trying to figure out what I'm missing. I'll get back in if I figure out exactly where my issue is..

So in the end the issue is not my code itself, i've got memory leaks or something somewhere that are adding up to eventually crash my program... That tends to be in the same method each time I guess.

Hooch
  • 33
  • 8

2 Answers2

2

The safer and most efficient way to erase some elements from a container is to apply the erase-remove idiom.

For instance, your snippet can be rewritten as the following (which is testable here):

using card_t = std::string;
std::vector<std::vector<card_t>> decks = {
    {"9D", "5C", "6S", "9D", "KS", "4S", "9D"},
    {"9S"}
};

card_t selection{"9S"};

// Predicate specifing which cards should be removed 
auto has_same_rank = [rank = selection.at(0)] (card_t const& card) {
    return card.at(0) == rank;
};

auto & deck = decks.at(0);

// 'std::remove_if' removes all the elements satisfying the predicate from the range
// by moving the elements that are not to be removed at the beginning of the range
// and returns a past-the-end iterator for the new end of the range.

// 'std::vector::erase' removes from the vector the elements from the iterator
// returned by 'std::remove_if' up to the end iterator. Note that it invalidates
// iterators and references at or after the point of the erase, including the
// end() iterator (it's the most common cause of errors in code like OP's). 
deck.erase(std::remove_if(deck.begin(), deck.end(), has_same_rank),
           deck.end());
Bob__
  • 12,361
  • 3
  • 28
  • 42
  • Sooo, I am at a loss.. If I toss my program into debug mode, it runs on an infinite loop and eventually segfaults out. If I load the game EXACTLY with the last profile that crashed it works fine. – Hooch Feb 15 '20 at 02:15
  • 1
    @Hooch Have you tried testing each function of the code in isolation, to narrow down the possible cause? – Bob__ Feb 15 '20 at 10:10
  • Bob, I did. and the problem would only arise after running the program for a while. So independently in a single instance everything worked fine.. – Hooch Feb 15 '20 at 19:53
0

So for anyone else in the future who comes across this... The problem is I was deleting an element in the array in a loop, with the conditional stop was it's size. The size is set before hand, and while it was accounted for in the code it still left open the possibility for while(array.size() ) which would be locked in at 8 in the loop be treated as 6 in the code.

The solution was to save the location in the vector to delete and then delete them outside of the loop. I imagine there is a better, more technical answer to this, but it works as intended now!

    for (double col = 0; col < size; ++col)
    {
        if(GameBoard::pool[col][0].at(0) == selection.at(0)){
                while(GameBoard::pool[col][0].at(0) == selection.at(0) && cardsRem !=0){
                    if( GameBoard::pool[col].size() > 1 ){
                        GameBoard::pool[col].pop_back();
                        cardsRem--;
                    }
                    if(GameBoard::pool[col].size() <2){
                        toDel.insert ( toDel.begin() , col );
                        //GameBoard::pool.erase(GameBoard::pool.begin() + col);
                        cardsRem--;
                        size--;
                    }
                }
        }
    }
    for(int i = 0; i< toDel.size(); i++){
        GameBoard::pool.erase(GameBoard::pool.begin() + toDel[i]);    
    }
Hooch
  • 33
  • 8