Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Problems with vector.push_back()


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
18 replies to this topic

#1 kaktusas2598   Members   -  Reputation: 865

Like
2Likes
Like

Posted 27 March 2013 - 08:02 AM

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[i].id = i;
			identifyCard(&pDeck[i]);			
		}
	}
	~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[i].id = d.pDeck[i].id;
			pDeck[i].type = d.pDeck[i].type;
			pDeck[i].num = d.pDeck[i].num;
			pDeck[i].val = d.pDeck[i].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.


Behind every great fortune lies a great crime.
Honore de Balzac

Sponsor:

#2 SiCrane   Moderators   -  Reputation: 9629

Like
7Likes
Like

Posted 27 March 2013 - 08:44 AM

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.

#3 kaktusas2598   Members   -  Reputation: 865

Like
0Likes
Like

Posted 27 March 2013 - 08:56 AM

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


Behind every great fortune lies a great crime.
Honore de Balzac

#4 hikrea   Members   -  Reputation: 161

Like
1Likes
Like

Posted 27 March 2013 - 09:02 AM

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


Edited by hikrea, 27 March 2013 - 09:04 AM.


#5 SiCrane   Moderators   -  Reputation: 9629

Like
3Likes
Like

Posted 27 March 2013 - 09:05 AM

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.

#6 Álvaro   Crossbones+   -  Reputation: 13671

Like
3Likes
Like

Posted 27 March 2013 - 09:15 AM

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.

#7 kaktusas2598   Members   -  Reputation: 865

Like
0Likes
Like

Posted 27 March 2013 - 10:34 AM

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


Behind every great fortune lies a great crime.
Honore de Balzac

#8 SiCrane   Moderators   -  Reputation: 9629

Like
2Likes
Like

Posted 27 March 2013 - 06:44 PM

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.

#9 kaktusas2598   Members   -  Reputation: 865

Like
0Likes
Like

Posted 28 March 2013 - 12:38 AM

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


Edited by kaktusas2598, 28 March 2013 - 12:38 AM.

Behind every great fortune lies a great crime.
Honore de Balzac

#10 BitMaster   Crossbones+   -  Reputation: 4274

Like
0Likes
Like

Posted 28 March 2013 - 02:45 AM

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.

#11 kaktusas2598   Members   -  Reputation: 865

Like
0Likes
Like

Posted 28 March 2013 - 05:11 AM

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.

I just removed it from my code and compiled generated constructors works just fine for me. One more question. Do anybody know how use random_shuffle() which I am using to shuffle my deck to shuffle deck diferrently every time, similar like using srand() with rand(). Cause now it shuffles the deck same way every time I run the game, so I think I need some way to seed some random number based by time every time I use random_shuffle(). Thank you.


Behind every great fortune lies a great crime.
Honore de Balzac

#12 Brother Bob   Moderators   -  Reputation: 8454

Like
0Likes
Like

Posted 28 March 2013 - 05:28 AM

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.

I just removed it from my code and compiled generated constructors works just fine for me.

But as BitMaster said, the compiler generated copy constructor is as incorrect as the copy constructor you originally had. It doesn't work. Your class simply isn't set up for handling the ownership of the pointer, and neither the compiler generated copy constructor nor your original copy constructor is doing the right job. And by the way, this applies to the copy assignment operator as well.

 

The point is to completely disable copying by making the copy constructor and assignment operators private to ensure that you cannot copy the objects. Or, implement proper copy operators to ensure that the ownership of the pointer is handled correctly.

 

One more question. Do anybody know how use random_shuffle() which I am using to shuffle my deck to shuffle deck diferrently every time, similar like using srand() with rand(). Cause now it shuffles the deck same way every time I run the game, so I think I need some way to seed some random number based by time every time I use random_shuffle(). Thank you.

Seed the random number generator with something that is not pre-defined, such as time.

srand(time(NULL));


#13 kaktusas2598   Members   -  Reputation: 865

Like
0Likes
Like

Posted 28 March 2013 - 10:51 AM

kaktusas2598, on 28 Mar 2013 - 13:09, said:

One more question. Do anybody know how use random_shuffle() which I am using to shuffle my deck to shuffle deck diferrently every time, similar like using srand() with rand(). Cause now it shuffles the deck same way every time I run the game, so I think I need some way to seed some random number based by time every time I use random_shuffle(). Thank you.

Seed the random number generator with something that is not pre-defined, such as time.

srand(time(NULL));

 

But I am using random_shuffle(). not rand(), does srand() also works with random_shuffle()? :o


Behind every great fortune lies a great crime.
Honore de Balzac

#14 Brother Bob   Moderators   -  Reputation: 8454

Like
0Likes
Like

Posted 28 March 2013 - 11:02 AM

kaktusas2598, on 28 Mar 2013 - 13:09, said:

One more question. Do anybody know how use random_shuffle() which I am using to shuffle my deck to shuffle deck diferrently every time, similar like using srand() with rand(). Cause now it shuffles the deck same way every time I run the game, so I think I need some way to seed some random number based by time every time I use random_shuffle(). Thank you.

Seed the random number generator with something that is not pre-defined, such as time.

srand(time(NULL));

 

But I am using random_shuffle(). not rand(), does srand() also works with random_shuffle()? ohmy.png

Sorry, I was thinking randomness and seeding and wasn't exactly thinking about what I was actually answering. The random generator used by the two-parameter variant of std::random_shuffle is in fact implementation defined, but probably uses rand. If it does, then srand will seed std::random_shuffle.

 

However, you may want to use the variant with the third parameter instead, which lets you specify the random number generator yourself. I believe you can pass rand as the third parameter to make sure that it does, in fact, use rand for random numbers.



#15 SiCrane   Moderators   -  Reputation: 9629

Like
2Likes
Like

Posted 28 March 2013 - 11:22 AM

rand() isn't a valid function for the third parameter of std::random_shuffle(). If you pass it a function, the function has to take one argument n, and return a value from 0 to n - 1. rand() doesn't take any arguments.

#16 Brother Bob   Moderators   -  Reputation: 8454

Like
0Likes
Like

Posted 28 March 2013 - 11:31 AM

I apologize, that makes total sense.



#17 kaktusas2598   Members   -  Reputation: 865

Like
0Likes
Like

Posted 28 March 2013 - 11:35 AM

I have read on internet, that random_shuffle really was inplemented using rand(), so srand() works! Thank you, fellow developers, for all your help! smile.png


Edited by kaktusas2598, 28 March 2013 - 12:27 PM.

Behind every great fortune lies a great crime.
Honore de Balzac

#18 SiCrane   Moderators   -  Reputation: 9629

Like
0Likes
Like

Posted 28 March 2013 - 12:31 PM

It would be more accurate to say "is usually implemented using rand()". The C++ standard doesn't require standard library implementations to use rand() under the hood for the two argument version of the random_shuffle() function. I would be cautious about trusting an internet source that said this was definitely the case (unless it was referring to your particular compiler/standard library implementation).

#19 Álvaro   Crossbones+   -  Reputation: 13671

Like
0Likes
Like

Posted 28 March 2013 - 12:43 PM

I just checked a late draft of the C++11 standard, and SiCrane is correct. This is unfortunate, and it leaves us with two options: Either avoid using the two-argument version of random_shuffle (since the standard doesn't give you any tools to seed the source of randomness) or live our lives ignoring this oddity in the standard, and trusting that compiler writers are sensible people. If a compiler doesn't use rand as the source of randomness, I will happily stop using that compiler.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS