I am relatively new to C++ programming, but am a C programmer of 10 years so am more comfortable with pointers to objects than I am with references to objects.
I’m writing a Solitaire game – is this design unsafe? Is there a better way?
Anyway, I have a class SolitaireGame:
class SolitaireGame:
{
public:
SolitaireGame( int numsuits = 1 );
private:
Deck * _deck;
vector<Card> _shoe;
};
The Deck is defined thus:
class Deck:
{
public:
Deck::Deck( vector<Card>& shoe );
~Deck();
int DealsLeft() const { return deals_left; }
Card * PullCard();
private:
int deals_left;
int num_each_deal;
deque<Card *> _cards;
};
The Deck constructor, takes a reference to a vector of Card objects ( the shoe, normally 104 cards ) and pushes a pointer to each card onto it’s own deque of pointers.
Deck::Deck( vector<Card>& shoe )
{
vector<Card>::iterator iter = shoe.begin();
while( iter != shoe.end() )
{
_cards.push_front( &(*iter) );
iter++;
}
}
}
The shoe is created in the SolitaireGame constructor. Once this vector of dynamically created Card objects has been created – I then pass a reference to this vector to the constructor.
SolitaireGame::SolitaireGame( int numsuits ):_numsuits(numsuits )
{
Card * c;
vector<Card> _shoe;
for( int i = 0; i < NUM_CARDS_IN_SHOE; i++ )
{
c = new Card();
_shoe.push_back( *c );
}
_deck = new Deck( _shoe );
}
My idea was that the shoe would be the container for the actual memory for the Card objects and the Deck and Columns just handle pointers to those Card objects.
Just taking this snippet of code, you leak dynamically created cards.
_shoe.push_back( *c )adds a copy of theCardobject pointed to bycto the vector ofCards. You then fail to delete the originalCardas created in the line before.Allocating a vector of
NUM_CARDS_IN_SHOECardscan much more simply be achieved like this:Looking at your card structure, it looks like you have (or nearly have) strict ownership between objects so I don’t think that you need to dynamically create your
Cards.Note that your local variable
_shoeis shadowing the class variable_shoe. This probably isn’t what you want as the local_shoewhich you pass to theDeckconstructor will go out of scope at the end of the constructor.If you reorder you variables in
SolitaireGame, you can probably do something like this:I’ve changed
_deckfrom being a pointer. I’m using the fact that member variables are constructed in the order declared in the class definition, so_shoewill be fully constructed before it is passed as a reference to the constructor for_deck. The advantage of this is that I have eliminated the need to dynamically allocate_deck. With no uses ofnew, I know that I can’t have any missed calls todeleteas nothing needs to be deallocated explicitly.You are right that you can store pointers to the
Cards in_shoein your_deckwithout any memory management issues, but note that you must not add or remove any of theCards in the_shoeduring the lifetime of the game otherwise you will invalidate all of the pointers in_deck.