I am learning C++ and decided to make a card deck system using vectors. I have been able to randomly shuffle it, make 1 singular deck, and now I want to make a function that deals a hand from that deck.
Say I wanted a hand of 10 cards from a deck of 52 cards, therefore 42 cards would be left and the first 10 cards of the Deck vector will be taken and placed into the newHand
vector but after looking for solutions on how to approach this using erase()
and pop_back()
, I cant seem to find an efficient or proper solution. However since I am new to C++ my code might not be the best thing to look at so I am open for suggestions on how to make this better, maybe with pointers? (Pointers are confusing to me and I am not sure when to use them).
Here are the main functions:
void Deck::deleteElement(std::vector<std::string> Deck, int index)
{
while (index--) {
Deck.erase(Deck.begin(), Deck.begin() + index);
}
}
void Deck::dealHand(int numOfCards, std::vector<std::string>& currentDeck, int numOfDecks)
{
std::vector<std::string> newHand;
static int remaining = deckSize(numOfDecks);
while (numOfCards-- && remaining != 0) {
newHand.push_back(currentDeck[numOfCards]);
--remaining;
} deleteElement(currentDeck, numOfCards);
for (auto & i : newHand) {
std::cout << i << " ";
}
std::cout << ",there are now " << remaining << " cards remaining" << std::endl;
}
I want to mention that deleteElement
when using erase gives me this error
malloc: *** error for object 0x16f9ddf40: pointer being freed was not allocated
malloc: *** set a breakpoint in malloc_error_break to debug
I also could not find much on explaining what this means, if anyone can that would be a great help.
I would probably not bother with actually erasing elements from the deck's internal vector. That's because you might want to reshuffle and deal cards multiple times over the course of a game, which is easier if you just keep them all in the deck and track which ones have been dealt. And since almost everything container-related uses iterators, you can keep it short and simple like this:
#include <iterator>
#include <vector>
class Card {};
class Deck {
public:
using Cards = std::vector<Card>;
// Just an example constructor
explicit Deck(std::size_t size = 52)
: m_cards(size), m_current{m_cards.begin()}
{}
Cards dealHand(std::size_t count) {
auto begin = m_current;
std::ranges::advance(m_current, count, m_cards.end());
return Cards(begin, m_current);
}
std::size_t
size() const { return std::ranges::distance(m_current, m_cards.end()); }
private:
Cards m_cards;
Cards::iterator m_current;
};
int main() {
Deck deck {};
auto hand = deck.dealHand(10);
return deck.size();
}
While it's not strictly necessary to use std::ranges functions (they have equivalents in the std namespace), this part of C++20 is now widely supported. One advantage is that range algorithms accept entire ranges (such as containers) instead of only pairs of iterators, for example std::ranges::shuffle
.