Which container to do what I need? - Page 2
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 2 of 2 FirstFirst 12
Results 16 to 24 of 24

Thread: Which container to do what I need?

  1. #16
    Join Date
    Oct 2006
    Location
    Sweden
    Posts
    3,634

    Re: Which container to do what I need?

    Both yes and no. The code you show produce the same result as Paul's but it cause the created object first to be default initialized and then assigned new values in the constructor body.
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are, by
    definition, not smart enough to debug it.
    - Brian W. Kernighan

    To enhance your chance's of getting an answer be sure to read
    http://www.codeguru.com/forum/announ...nouncementid=6
    and http://www.codeguru.com/forum/showthread.php?t=366302 before posting

    Refresh your memory on formatting tags here
    http://www.codeguru.com/forum/misc.php?do=bbcode

    Get your free MS compiler here
    http://www.microsoft.com/visualstudio/eng/downloads

  2. #17
    Join Date
    May 2012
    Posts
    57

    Re: Which container to do what I need?

    Quote Originally Posted by S_M_A View Post
    Both yes and no. The code you show produce the same result as Paul's but it cause the created object first to be default initialized and then assigned new values in the constructor body.
    Guess I need to do more research since I really don't understand why the code I showed works different from Pauls. Thanks for pointing that out.

  3. #18
    Join Date
    Apr 1999
    Posts
    27,429

    Re: Which container to do what I need?

    Quote Originally Posted by raptor88 View Post
    Guess I need to do more research since I really don't understand why the code I showed works different from Pauls. Thanks for pointing that out.
    There is a difference. The code I showed you initializes the member variables, i.e. as soon as the members of the struct are created, those members are initialized to a value. Note that this occurs outside (before) the constructor body, emphasizing the fact that those members have initial values before the constructor body is invoked.

    Your version doesn't give the members any values until the constructor body is invoked. You can see the difference if you place a breakpoint on the first line of the constructor. You will see that those members have values with my method, while with your method those variables have undefined or junk values.

    Even though initialization list isn't required in this scenario, in other scenarios you are required to use the initialization list. For example, if the struct or class has members that cannot be default-constructed, or if the struct is derived from a struct/class that cannot be default constructed, you're required to use an init-list.
    Code:
    class A
    {
       public:
         A(int x);
    };
    
    class B : public A
    {
       B() { } // error
    };
    The fix:
    Code:
    class A
    {
       public:
         A(int x);
    };
    
    class B : public A
    {
       B() : A(0) { } // ok now
    };
    Regards,

    Paul McKenzie

  4. #19
    Join Date
    May 2012
    Posts
    57

    Re: Which container to do what I need?

    Quote Originally Posted by Paul McKenzie View Post
    There is a difference.
    ... snip ...
    Thanks for clearing that up Paul. Learned a lot from this thread. I did plan to only use your method in the future since it's easier to type but now I know it also works better.

    Thanks,
    Raptor

  5. #20
    Join Date
    May 2012
    Posts
    57

    Re: Which container to do what I need?

    Is this the correct way to use Paul's code of the map of structs in an array for 4 players?

    Code:
    #include "stdafx.h"
    #include <string>
    #include <iostream>
    #include <map>
    
    using namespace std;
    
    
    struct BetInfo
    {
    	int betTotal;		// Total amount of a particular bet on the table.
    	int coordX;			// Horz coordinate of where to draw the chips for that bet.
    	int coordY;			// Vert coordinate of where to draw the chips for that bet.
    	BetInfo(int xVal=0, int yVal=0, int zVal=0) : betTotal(xVal), coordX(yVal), coordY(zVal) {}
    };
    
    	map<string, BetInfo> betInfoMap[4];	// Put before tmain to make instance of betInfoMap global.
    
    	enum {player1, player2, player3, player4};	// Set player1 = 0, player2 = 1, etc.
    
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    
    	// Note that each time "insert(make_pair" is called, it creates a new struct in betInfoMap.
    	// In that process the inline constructor is called which initializes the struct values.
    	betInfoMap[player1].insert(make_pair("PassLine", BetInfo(0, 1, 2)));
    	betInfoMap[player1].insert(make_pair("PassBkup", BetInfo(0, 3, 4)));
    	betInfoMap[player1].insert(make_pair("NoPass", BetInfo(0, 5, 6)));
    	betInfoMap[player1].insert(make_pair("NoPassBkup", BetInfo(0, 7, 8)));
    
    	betInfoMap[player2].insert(make_pair("PassLine", BetInfo(0, 9, 10)));
    	betInfoMap[player2].insert(make_pair("PassBkup", BetInfo(0, 11, 12)));
    	betInfoMap[player2].insert(make_pair("NoPass", BetInfo(0, 13, 14)));
    	betInfoMap[player2].insert(make_pair("NoPassBkup", BetInfo(0, 15, 16)));
    
    	betInfoMap[player3].insert(make_pair("PassLine", BetInfo(0, 17, 18)));
    	betInfoMap[player3].insert(make_pair("PassBkup", BetInfo(0, 19, 20)));
    	betInfoMap[player3].insert(make_pair("NoPass", BetInfo(0, 21, 22)));
    	betInfoMap[player3].insert(make_pair("NoPassBkup", BetInfo(0, 23, 24)));
    
    	betInfoMap[player4].insert(make_pair("PassLine", BetInfo(0, 25, 26)));
    	betInfoMap[player4].insert(make_pair("PassBkup", BetInfo(0, 27, 28)));
    	betInfoMap[player4].insert(make_pair("NoPass", BetInfo(0, 29, 30)));
    	betInfoMap[player4].insert(make_pair("NoPassBkup", BetInfo(0, 31, 32)));
    
    
    	// Print the map key and associated struct values for all players (1-4) on the console.
    	for (int playerNbr=0; playerNbr < 4; playerNbr++)
    	{
    		cout << "\nPlayer Number = " << playerNbr+1 << endl;
    		map<string, BetInfo>::iterator it = betInfoMap[playerNbr].begin();
    		while(it != betInfoMap[playerNbr].end() )
    		{
    			cout << it->first << " -> (" << it->second.betTotal << "," << it->second.coordX << "," << it->second.coordY << ")\n";
    			++ it;
    		}
    	}
    
    
    	char ch;
    	cin >> ch;
    		
    	return 0;
    }
    Thanks,
    Raptor

  6. #21
    Join Date
    Apr 1999
    Posts
    27,429

    Re: Which container to do what I need?

    Quote Originally Posted by raptor88 View Post
    Is this the correct way to use Paul's code of the map of structs in an array for 4 players?
    More or less, the code is correct.

    Maybe some code rearrangement, removal of the global variable(s), and better design would be in order (maybe have a vector instead of an array, where the number of players can be variable instead of a hard-coded 4). Given that, the code you posted as of now will work correctly.

    Regards,

    Paul McKenzie

  7. #22
    Join Date
    May 2012
    Posts
    57

    Re: Which container to do what I need?

    Quote Originally Posted by Paul McKenzie View Post
    More or less, the code is correct.

    Maybe some code rearrangement,
    Would that be moving the enum statement before the struct statement?

    removal of the global variable(s),
    Since I need to access the betInfoMap[4] in my "GetBets", "PayBets" and on every iteration of the crap table drawing routine which will be constantly looping, I decided to make betInfoMap[4] global. Seems like so much extra work to not make it global and have to pass a reference to every function that needs to access it. Comments welcome.

    and better design would be in order (maybe have a vector instead of an array, where the number of players can be variable instead of a hard-coded 4).
    Hmmm, I'll have to do research on how to do that. My current plan is to use a const value for the number of players like:

    ---------------
    // Place this statement where my constant values will be for easy access.
    const int NUMBER_OF_PLAYERS = 4;

    map<string, BetInfo> betInfoMap[NUMBER_OF_PLAYERS];
    ---------------

    Given that, the code you posted as of now will work correctly.
    Thanks for confirming that what I posted will work OK. I posted the code to verify that I wasn't doing anything bad with the array since I know it's possible to read/write outside of an array with dire consequences.


    Oh, one more question:
    From what I've read, I believe that the memory allocated for the map will be released when the program terminates without my having to do anything. Is that correct? If not, what statement(s) do I need to use to release the memory?

    Thanks,
    Raptor
    Last edited by raptor88; October 21st, 2012 at 05:53 PM. Reason: changed numberOfPlayers to all caps since constant value. + one more question.

  8. #23
    Join Date
    Apr 1999
    Posts
    27,429

    Re: Which container to do what I need?

    Quote Originally Posted by raptor88;2089679Since I need to access the betInfoMap[4
    in my "GetBets", "PayBets" and on every iteration of the crap table drawing routine which will be constantly looping, I decided to make betInfoMap[4] global. Seems like so much extra work to not make it global and have to pass a reference to every function that needs to access it.
    The issue is that GetBets and PayBets are also global functions. Why go that route when you can create an entire class that encapsulates this whole thing? Then there is no need for global variables, global functions, or global definitions.
    Code:
    #include <vector>
    
    class CrapsGame
    {
       //...
       unsigned numPlayers;
       //
       public:
            CrapsGame(unsigned numPlayers = 4);
            void PlayGame(); // plays the game
    };
    
    int main()
    {
        CrapsGame theGame(10);  // sets up a game for 10 players
        theGame.PlayGame();  // plays the craps game
    }
    If you want another example, look at the "map" class you're using now. Do you see globals being used in the map class denoting the number of items in the map, the internal tree-like structure used in the map, etc.? You don't -- so how does std::map accomplish keeping track of the map internals without using global variables? The entire map internals are encapsulated in a class -- something your game does not do.
    Hmmm, I'll have to do research on how to do that. My current plan is to use a const value for the number of players like:
    So what happens when you want 6 players, 8 players, etc? You now have to go and change your program, recompile, relink to get it to work for 6 players, and then create another program to have 8 players, etc. You can see how that won't work too well.

    First, you should have a struct defining a single player. The road you're going down now seems to suggest you'll have information for a single player strewn about in different and disjoint structs, functions, variables, etc. in your code. Instead you should be consolidating all of this information into a single entity that describes a single player. You now create a vector of this "player information"
    Code:
    #include <map>
    #include <string>
    #include <vector>
    //...
    class PlayerInformation
    {
        BetInfo m_BetInfo;
        std::string m_PlayerName;
        //... etc.
     };
    
    class CrapsGame
    {
        typedef std::map<std::string, PlayerInformation> Player;
        typedef std::vector<Player> AllPlayers;
        //...
        AllPlayers m_vPlayers;
        //...
    
        void initPlayerInformation()
        {
           // initialize information for all players defined
        }
    
        public:
            CrapsGame(unsigned numPlayers = 4) : m_vPlayers(numPlayers) 
            {
               initPlayerInformation();
            }
    
            void PlayGame();  // play the game
            //...
    };
    The above is a sample of what could be done.
    Oh, one more question:
    From what I've read, I believe that the memory allocated for the map will be released when the program terminates without my having to do anything. Is that correct?
    Yes, the map will destroy itself correctly. No different than the std::string class.
    If not, what statement(s) do I need to use to release the memory?
    Think about the question you asked. What good would a class such as map be if the user of the class has to clean up the remnants? The purpose of the map and other classes is to ensure that the objects will get properly destroyed once the object goes out of scope, and for any reason whatsoever. That's what destructor functions are for.

    Let's say that the user did have to clean up the memory. Would you like to code something like this?
    Code:
    void someFunction()
    {
       std::map<string, int> SomeMap;
       SomeMap.insert(make_pair("xyz", 1));
       if ( whatever )
       {
           DoSomething();
           CleanUpMyMap();
           return;
       }
       else
       if ( whatever2)
       {
           CleanUpMyMap();
           return;
       }
       else
       if ( whatever3)
       {
           DoSomething2();
           CleanUpMap();
       }
       else
       {
           try
           { 
               DoSomething4();
               CleanUpMap();
           }
           catch (someException& )
           {
               CleanUpMap();
           }
        }
    }
    The "CleanUpMap" is the code that the user would need to invoke to clean up the map. Do you see how convoluted code like this would be? Everywhere you have a potential return point, including exceptions that you may or may not know about, you have to clean the map up, else you get a memory leak, a resource not properly destroyed or closed, etc.

    Of course, this is not the way that well written classes such as map behave. You declare a map, and if the map goes out of scope for any reason whatsoever (a return from a function, an exception being thrown taking the code out of the current block, an exit from a block of code denoted by { ... }, etc.) the map is cleaned up automatically. Google the term "RAII". The string classes work the same way.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; October 21st, 2012 at 07:26 PM.

  9. #24
    Join Date
    May 2012
    Posts
    57

    Re: Which container to do what I need?

    Quote Originally Posted by Paul McKenzie View Post
    The issue is that GetBets and PayBets are also global functions. Why go that route when you can create an entire class that encapsulates this whole thing? Then there is no need for global variables, global functions, or global definitions.
    ... snip ...

    If you want another example, look at the "map" class you're using now. Do you see globals being used in the map class denoting the number of items in the map, the internal tree-like structure used in the map, etc.? You don't -- so how does std::map accomplish keeping track of the map internals without using global variables? The entire map internals are encapsulated in a class -- something your game does not do.
    So what happens when you want 6 players, 8 players, etc? You now have to go and change your program, recompile, relink to get it to work for 6 players, and then create another program to have 8 players, etc. You can see how that won't work too well.

    First, you should have a struct defining a single player. The road you're going down now seems to suggest you'll have information for a single player strewn about in different and disjoint structs, functions, variables, etc. in your code. Instead you should be consolidating all of this information into a single entity that describes a single player. You now create a vector of this "player information"
    ... snip ...

    The above is a sample of what could be done.
    Yes, the map will destroy itself correctly. No different than the std::string class.
    Think about the question you asked. What good would a class such as map be if the user of the class has to clean up the remnants? The purpose of the map and other classes is to ensure that the objects will get properly destroyed once the object goes out of scope, and for any reason whatsoever. That's what destructor functions are for.

    Let's say that the user did have to clean up the memory. Would you like to code something like this?
    ... snip ...

    The "CleanUpMap" is the code that the user would need to invoke to clean up the map. Do you see how convoluted code like this would be? Everywhere you have a potential return point, including exceptions that you may or may not know about, you have to clean the map up, else you get a memory leak, a resource not properly destroyed or closed, etc.

    Of course, this is not the way that well written classes such as map behave. You declare a map, and if the map goes out of scope for any reason whatsoever (a return from a function, an exception being thrown taking the code out of the current block, an exit from a block of code denoted by { ... }, etc.) the map is cleaned up automatically. Google the term "RAII". The string classes work the same way.

    Regards,

    Paul McKenzie
    My bad Paul. In hindsight I can see why you think my plan is to code most everything using globals and not using classes. The code I posted was just extending your example to verify whether my approach to using an array for the 4 players was valid and was not meant as an example of how I intend to code my program.

    I actually plan to use classes for every module and main will just be a very simple loop similar to this:
    Code:
    int _tmain(int argc, _TCHAR* argv[])
    {
        sf::RenderWindow App;
    
        //Applications variables
        std::vector<cScreen*> Screens;
        
        int screen = 1;   //Keeps track of the screen routine currently in use.
    
        //Screens preparations
        DummyScreen s0;
        Screens.push_back (&s0);
    
        PrimaryMenu s1;
        Screens.push_back (&s1);
    
        RTPlay s2;
        Screens.push_back (&s2);
    
        // Main loop
        // Return zero = exit.  Return value greater than zero goes to that screen (routine) number.
        while (screen > 0)
        {
            screen = Screens[screen]->Run(App);
        }
    
        return EXIT;
    }
    There will be a lot more screen routines for different things like SETUP, DISPLAY STATISTICS, HELP, etc.

    My plan is to have the one global array (or vector) of map/structs (like you showed me) called BetInformation.

    The GetBets class will get mouse clicks and determine which bet the player wants to make. The betTotal for that particular bet will be updated for the active player in BetInformation.

    The player will click the "Roll Dice" button which will call the RollDice class. This will produce die1, die2 and diceSum randomly.

    The PayBets class will scan the betTotal in the global BetInformation looking for bets made (betTotal > 0). If a betTotal > 0 is found, the bet will be paid, collected or ignored as appropriate for the diceSum rolled. This will continue until the entire BetInformation is scanned.

    The DisplayTable class is constantly being called during all of the above to reflect changes on the crap table. DisplayTable will use the betTotal, coordX and coordY to draw the proper amount of chips for every bet made, for each of the 1 to 4 players. IOW, DisplayTable draws everything on the crap table using information in BetInformation.

    There's major classes for ComeoutRoll (which contains all of the above) and PointRoll (which also contains all of the above).

    In summary, everything will be in classes except the BetInformation array of map/struts which every class needs to access.

    Thanks so much for explaining things so well, including the destructors. I really appreciate all of your help and you don't know how much it's helping me structure my program. I'll look into the struct defining a single player you suggested as to how it can fit into my plans.

    I always welcome your or other comments. I'm open to changing my plans. Thanks,
    Raptor
    Last edited by raptor88; October 22nd, 2012 at 02:34 AM.

Page 2 of 2 FirstFirst 12

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center