Problems with vector.push_back()

Started by
17 comments, last by alvaro 11 years ago

Hello everybody, Yesterday I started to program Black Jack game in console and I have problems with vectpr.push_back(), I use it to add cards from deck to players hand, for what I use CPlayer::PDraw(CDeck d) function, here it is:


void PDraw( CDeck d)
	{	
		cards.push_back(d.getDeck()[cardCounter]);//error, deck deletes somehow after doing one command
		cardCounter++;
	}

The problem is, when I use puch back(), my deck what I pass into function somehow is changed and becomes empty, I think it has to do something with my Copy and Assignment constructors of CDeck class, here is my CDeck class:


//Class representing Deck of Cards
class CDeck
{
public:
	CDeck(){
		pDeck= new SCard[CARD_NUMBER];
		for(int i = 0; i < CARD_NUMBER; i ++)
		{
			//Assign ID to card and its suit and value
			pDeck.id = i;
			identifyCard(&pDeck);			
		}
	}
	~CDeck(){
		delete[] pDeck;
	}
	CDeck(const CDeck &d) { operator=(d); }//error here?
	const CDeck &operator=(const CDeck &d) {//still mistake
		for(int i = 0; i < CARD_NUMBER; i++)
		{
			pDeck.id = d.pDeck.id;
			pDeck.type = d.pDeck.type;
			pDeck.num = d.pDeck.num;
			pDeck.val = d.pDeck.val;
		}
    return d;
	}
	void shuffleDeck()
	{
		//Shuffles Deck, but maybe more suitable with vector and rand()
		std::random_shuffle(pDeck, pDeck + 52);		
	}
	void identifyCard(SCard* c)
	{
		c->type = suits[c->id/13];
		c->val = value[c->id%13];
		c->num = nums[c->id%13];
	}

	SCard* getDeck(){return pDeck;}
private:
	SCard* pDeck;
};

Here is SCard structure:


//Structure representing one card
typedef struct
{
	//Card ID convertible to its value and suit
	int id;
	//Card Value from Sce to King
	string val;
	//Card suit, Hearts etc.
	string type;
	//Cars numerical value with ace being 11 
	int num;
}SCard;

ANd lastly, my CPlayer class:


//Class representing main Player
class CPlayer
{
public:
	CPlayer()
	{
		bet = 0;
		balance = START_MONEY;
		counter = 0;
		//party begins
		isPlaying = true;
		//first move is banks
		isActive = false;
	}
	//Player actions funcs
	void PStay()
	{
		isActive = false;
	}
	void PDraw( CDeck d)
	{	
		cards.push_back(d.getDeck()[cardCounter]);//error, deck deletes somehow after doing one command
		cardCounter++;
	}
	void PDouble(CDeck d)
	{
		PDraw(d);
		bet*=2;
	}
	void PMove(CDeck d)
	{
		int choise;
		cout << "Choose move what you like: \n1.Stay.\n2.Draw\n3.Double.\n";
		cin >> choise;
		if(choise == 1) PStay();
		if(choise == 2) PDraw(d);
		if(choise == 3) PDouble(d);
	}
	void PInfo()
	{
		cout << "Balance: " << balance << endl;
		cout << "Bet: " << bet << endl;
		cout << "Cards in your hand:" << endl;
		vector<SCard>::iterator iter;
		for(iter = cards.begin(); iter != cards.end(); ++iter)
		{
			cout << (*iter).val << " of " << (*iter).type << endl;
		}
		cout << "Value: " << PSum() << endl;; 
	}
	void PBet()
	{
		bool isBetMade = false;
		while(!isBetMade)
		{
			cout << "Enter the bet between 10 to "<< balance << ": ";
			cin >> bet;
			if(bet < 10 || bet > balance)
				cout << "\nYou can't bet this sum. Type Again\n";			
			else
				isBetMade = true;
		}
		balance -= bet;
	}
	int PSum()
	{
		int numOfAces = 0; //nuimber of aces in hand 
		vector<SCard>::iterator iter;
		for(iter = cards.begin(); iter != cards.end(); ++iter)
		{
			if((*iter).val == "Ace") numOfAces++;
			counter += (*iter).num;			
			
		}
		if(counter > BLACK_JACK)
		{
			for(iter = cards.begin(); iter != cards.end(); ++iter)
			{
				if((*iter).val == "Ace") 
				counter -= 10;// +1 and -11
				if(counter <= BLACK_JACK)
					break;
			
			}
		}
		return counter;
	}
	
	bool isPlaying;//player currently playing


	bool isActive; // is players move
private:
	int balance;
	int bet;
	//stores current points that player has
	int counter;	
	//stores current cards in hand
	vector<SCard> cards;
};

I regard every possible answer to this problem. When I run program and step to line where I push card into my vector representing cards in player hands it throws unhandled exception (Unhandled exception at 0x779615de in Black Jack.exe: 0xC0000005: Access violation writing location 0x76d833aa.). To be more precise it comes to constructor of CDeck and then breaks.

Deltron Zero and Automator.

Advertisement
void PDraw(CDeck d) makes a copy of the deck because you are passing by value rather than by reference. This invokes your copy constructor, which is improperly implemented. You try to define your copy constructor in terms of your assignment operator, but your assignment operator assumes that the CDeck object is already properly constructed, which your copy constructor neglects to do before calling the assignment operator.

Since you're already using vectors, the easy way to fix this would be to change your deck's pCard member to a vector of SCard objects. Then the compiler generated copy constructor, assignment operator and destructor would all automatically do the right thing for you.

I thought the same way, array is probably not the best way to implement my deck, is there any other way without changing pDeck?

Deltron Zero and Automator.

void PDraw(CDeck d) makes a copy of the deck because you are passing by value rather than by reference.

void PDraw(CDeck &d) passing by reference

I thought the same way, array is probably not the best way to implement my deck, is there any other way without changing pDeck?

Yes, you could allocate a new array in your copy constructor before copying from the other object.

Actually, now that I look at your code again, there doesn't seem to be any reason that you need dynamic memory at all. A regular array (or std::array) of CARD_NUMBER elements would work just as well.
This is unrelated to the problem, but I think I should mention that using 64-bit arithmetic one can encode a set of cards (e.g., a deck or a hand) with a single number. If you are ever concerned about performance (like, if you want to develop a competitive AI engine) this format makes many operations very fast.

Thank you everybody. Passing CDeck by reference helped, so I think I do not need to convert it to vector.

Deltron Zero and Automator.

If you decide not to fix your copy constructor you should consider disabling it. For example, declaring it private and removing the definition or, if you have access to a C++11 compiler, declaring it as = delete.

Thank you, I removed my copy constructor and passed CDeck as reference. Now it works and im nearly finished my game smile.png

Deltron Zero and Automator.

What exactly do you mean by "removing"? Removed as per SiCrane's suggestions or just removed it from your code?

If you do not supply one explicitly the compiler will generate one which might have similar problems depending on the situation.

This topic is closed to new replies.

Advertisement