CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Nov 2006
    Location
    Australia
    Posts
    1,569

    std::vector::push_back issue

    Hey. I've got a weird problem... I've been building my program in release mode just recently and I've come across a problem where a string is inserted into a vector... the highlighted code shows the line where the problem is.

    The string is fine until it's pushed into the vector... after it's pushed in, the vector still has 0 elements... I stepped into the push_back definition and the parameter _Val was <Bad Ptr>...

    I have no clue why it's happening... here is the relevant code:
    Code:
    /*
      Universal class. Edits affect multiple projects.
    */
    
    #ifndef XSCREEN_H
    #define XSCREEN_H
    
    //testing
    #include <iostream>
    
    #include <algorithm>
    #include <functional>
    #include <string>
    #include <exception>
    
    #include "Base_XImage.h"
    #include "Clone_Back_Insert_Iterator.h"
    #include "Cloneable.h"
    #include "Drawable.h"
    #include "IO.h"
    #include "Uncopyable.h"
    
    // Type used to mark the end of a typelist.
    struct Null_Type
    {
    };
    
    // The typelist. For nested typelists type U is a typelist again, so one can
    // build typelists of any length.
    template<typename T, typename U>
    struct Type_List
    {
       typedef T head; 
       typedef U tail; 
    };
    
    // Convenience macros for building typelists.
    #define TL1(T1)                  Type_List<T1, Null_Type >
    #define TL2(T1,T2)                Type_List<T1, TL1(T2) >
    #define TL3(T1,T2,T3)              Type_List<T1, TL2(T2,T3) >
    #define TL4(T1,T2,T3,T4)            Type_List<T1, TL3(T2,T3,T4) >
    #define TL5(T1,T2,T3,T4,T5)            Type_List<T1, TL4(T2,T3,T4,T5) >
    #define TL6(T1,T2,T3,T4,T5,T6)          Type_List<T1, TL5(T2,T3,T4,T5,T6) >
    #define TL7(T1,T2,T3,T4,T5,T6,T7)        Type_List<T1, TL6(T2,T3,T4,T5,T6,T7) >
    #define TL8(T1,T2,T3,T4,T5,T6,T7,T8)      Type_List<T1, TL7(T2,T3,T4,T5,T6,T7,T8) >
    #define TL9(T1,T2,T3,T4,T5,T6,T7,T8,T9)      Type_List<T1, TL8(T2,T3,T4,T5,T6,T7,T8,T9) >
    #define TL10(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10)  Type_List<T1, TL9(T2,T3,T4,T5,T6,T7,T8,T9,T10) >
    
    /*
    To use this class, pass in a typelist (e.g):
    #define MY_TYPE_LIST TL3(XImage, XButton, Class_Derived_From_Base_XImage)
    
    Order matters... in this case XImage then XButton then Class_Der[..] will be
    updated and drawn in sequential order.
    */
    
    template<typename Type_List>
    class XScreen : public Drawable, public Updateable, public Uncopyable
    {
    public:
      XScreen() {}
    
      XScreen(const std::string& directory)
        :
        directory(directory)
      {
        Load<Type_List>();
      }
    
      virtual ~XScreen()
      {
        for(std::vector<Base_XImage*>::iterator it = elements.begin();
          it != elements.end(); ++it)
        {
          delete *it;
        }
      }
    
      virtual void Draw()
      {
        std::for_each(
          elements.begin(),
          elements.end(), 
          std::mem_fun(&Base_XImage::Draw));
      }
    
      virtual void Update(const SDL_Event& event_)
      {
        std::vector<Base_XImage*>::iterator it = elements.begin();
        for(; it != elements.end(); ++it)
        {
          (*it)->Update(event_);
        }
      }
    protected:
      template<typename Type_List>
      void Load()
      {
        // Get the name of the type of each element.
        Get_Element_Types<Type_List>();
        // Recursively load each type of element from respective file.
        Load_Elements<Type_List>();
      }
    
      template<typename Type_List>
        void Get_Element_Types()
        {
        // element_types.push_back(Remove_Class_Prefix(typeid(Type_List::head).name()));
    
        // testing
        std::string s = Remove_Class_Prefix(typeid(Type_List::head).name());
        std::cout << s;
            element_types.push_back(s);
        // testing
    
            // Recursive call when tail is NOT Null_Type.
            Get_Element_Types<Type_List::tail>();
        }
        // Specialized template function to end typelist traversion(recursion).
        template<>
        void Get_Element_Types<Null_Type>()
        {
        }
    
      static std::string XScreen::Remove_Class_Prefix(std::string s)
      {
        const int PREFIX_LENGTH = 6;
        if(s.size() <= PREFIX_LENGTH)
        { // Too small.
          throw std::runtime_error("Missing class prefix in Remove_Class_Prefix: " + s);
        }
    
        s.erase(s.begin(), s.begin() + 6);
        return s;
      }
    
        template<typename T>
        std::string Get_Element_File_Name()
        {
            return Remove_Class_Prefix(std::string(typeid(T).name()) + "s.txt");
        }
    
        template<typename T>
        bool Valid_Element_Class()
        {
        for(std::vector<std::string>::const_iterator it = element_types.begin();
        it != element_types.end(); ++it)
            {
                if(Remove_Class_Prefix(typeid(T).name()) == *it)
                {
                    return true;
                }
            }
            return false;
        }
    
        template<typename T>
        void Load_Elements_Of_Type()
      {
            if(!Valid_Element_Class<T>())
            { // Not a valid element.
                throw std::runtime_error("Load_Elements_Of_Type: " +
                    std::string(typeid(T).name()) + "is not a valid element type.");
            }
            try
            {
            std::ifstream file;
            IO::open_read_file(file, directory + Get_Element_File_Name<T>());
            IO::read_data_clone<T, std::vector<Base_XImage*> >(elements, file);
            file.close();
            }
        catch(const std::runtime_error r)
            { // No file; don't want to load element type "T".
            }
      }
        
        // The load function. Its template parameter is a typelist which is traversed
        // from head to tail. A specialized template function for Null_Type ends the 
        // recursion.
        template<typename Type_List>
        void Load_Elements()
        {
            Load_Elements_Of_Type<Type_List::head>();
            // Recursive call when tail is NOT Null_Type.
            Load_Elements<Type_List::tail>();
        }
        // Specialized template function to end typelist traversion(recursion).
        template<>
        void Load_Elements<Null_Type>()
        {
        }
    protected:
      std::vector<std::string> element_types;
      std::vector<Base_XImage*> elements;
      std::string directory;
    };
    
    #endif
    Cheers.
    Good judgment is gained from experience. Experience is gained from bad judgment.
    Cosy Little Game | SDL | GM script | VLD | Syntax Hlt | Can you help me with my homework assignment?

  2. #2
    Join Date
    Nov 2006
    Location
    Australia
    Posts
    1,569

    Re: std::vector::push_back issue

    Ok... the directory constructor parameter (string) is also a <Bad Ptr>... This is where XScreen is used:
    Code:
    class Checkers_Game : public Runnable
    {
    public:
      Checkers_Game();
      virtual ~Checkers_Game() {}
    public:
      virtual void Run();
    private:
      void Game_Over();
      void Instructions();
      void Menu();
      void New_Game();
        void High_Scores();
      void Exit();
      void Mute();
    private:
      typedef void (Checkers_Game::*Mem_Func)(void);
    
        void Test();
    
      void Init_Event_Mappings();
      bool Handle_Events();
    
      SDL_Event sdl_event;
    
      // Need this since we can't "switch" on strings.
      std::map<std::string, Mem_Func> event_mappings;
    
      XScreen<SCREEN_TYPELIST>* active_screen;
      XScreen<SCREEN_TYPELIST> menu;
      XScreen<SCREEN_TYPELIST> instructions;
      XScreen<SCREEN_TYPELIST> ingame_GUI;
        High_Scores_Screen<SCREEN_TYPELIST> high_scores;
    
      Board board;
      bool playing;
      bool exit_game;
      // Saves resetting the board twice the first time program is run.
      bool board_reset_necessary;
    };
    Code:
    Checkers_Game::Checkers_Game()
      :
      menu("Screens/Menu_Screen/"),
      ingame_GUI("Screens/Checkers_Screen/"),
      instructions("Screens/Instructions_Screen/"),
        high_scores(HIGH_SCORES_WRITE_X, HIGH_SCORES_WRITE_Y, HIGH_SCORES_ROW_SPACING,
        HIGH_SCORES_DETAIL_SPACING, "Screens/High_Scores_Screen/", "High Scores/", MAX_SCORES),
      active_screen(&menu),
      playing(false),
      exit_game(false),
      board_reset_necessary(false)
    {
      Init_Event_Mappings();
    }
    Good judgment is gained from experience. Experience is gained from bad judgment.
    Cosy Little Game | SDL | GM script | VLD | Syntax Hlt | Can you help me with my homework assignment?

  3. #3
    Join Date
    Apr 1999
    Posts
    27,449

    Re: std::vector::push_back issue

    Quote Originally Posted by Mybowlcut
    Hey. I've got a weird problem... I've been building my program in release mode just recently and I've come across a problem where a string is inserted into a vector... the
    Does the program work correctly?

    I ask this, since a release build with optimizations turned on will remove, move, and replace code. What you're seeing in the debugger is not what is being executed when debugging an optimized program.
    highlighted code shows the line where the problem is.

    The string is fine until it's pushed into the vector... after it's pushed in, the vector still has 0 elements... I stepped into the push_back definition and the parameter _Val was <Bad Ptr>...
    In release mode, things are optimized away. If you want to debug a release version, you have to make sure that optimizations are turned off.

    Regards,

    Paul McKenzie

  4. #4
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: std::vector::push_back issue

    Quote Originally Posted by Mybowlcut
    Hey. I've got a weird problem...
    Weird person...weird problem...no suprise...

    Seriously, Pauls assesment is most likely correct if:

    1) With optimizations turned off, things look as expected
    2) With optimizations turned on, the code functions in an identical manner.

    Remember, there is no such thing as "Release Mode". The build is controlled by dozens of options (switch settings). Visual studio creates two of these configurations by default, and happens to call then "Release" and "Debug".

    You can create your own, or modify the existing ones. Sometimes (I like to torment certain developers), I will turn off all symbolic information, and enable optimization in the debug configuration, while at the same time enabling symbolic information and disabling optimizations in the release configuration.

    Obviously this is not "good practice", and my recommendation is to never modify ANYTHING in either of the two default configurations. Rather create custom configurations. Typical ones I create are: Development, UnitTest,CheckIn, QA, and Production.

    Even when the code is completely optimized, you can use the debugger to see exactly what is going on. However, you have to use the disassembly window, the registers window, and the raw memory window to understand it.

    Your most likely scenario is that the return value of Remove_Class_Prefix is in a register, and directly passed to the push_back, without ever being stored at the locations the debugger (locals window) expects it.

    To verify this:

    1) Open Disassembly Window.
    2) See what register is being used.
    3) Open Register Window to see contents of register
    4) Open watch window and cast that address to a std::string.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  5. #5
    Join Date
    Nov 2006
    Location
    Australia
    Posts
    1,569

    Re: std::vector::push_back issue

    Cheers Paul. I'll try that.

    Quote Originally Posted by TheCPUWizard
    Weird person...weird problem...no suprise...

    Seriously, Pauls assesment is most likely correct if:

    1) With optimizations turned off, things look as expected
    2) With optimizations turned on, the code functions in an identical manner.

    Remember, there is no such thing as "Release Mode". The build is controlled by dozens of options (switch settings). Visual studio creates two of these configurations by default, and happens to call then "Release" and "Debug".

    You can create your own, or modify the existing ones. Sometimes (I like to torment certain developers), I will turn off all symbolic information, and enable optimization in the debug configuration, while at the same time enabling symbolic information and disabling optimizations in the release configuration.

    Obviously this is not "good practice", and my recommendation is to never modify ANYTHING in either of the two default configurations. Rather create custom configurations. Typical ones I create are: Development, UnitTest,CheckIn, QA, and Production.

    Even when the code is completely optimized, you can use the debugger to see exactly what is going on. However, you have to use the disassembly window, the registers window, and the raw memory window to understand it.

    Your most likely scenario is that the return value of Remove_Class_Prefix is in a register, and directly passed to the push_back, without ever being stored at the locations the debugger (locals window) expects it.

    To verify this:

    1) Open Disassembly Window.
    2) See what register is being used.
    3) Open Register Window to see contents of register
    4) Open watch window and cast that address to a std::string.
    Haha oi!

    Well, I tried to follow your steps.. but I'm not familiar with registers and assembly... I got as far as the picture attached when I realised I was lost...
    Attached Images Attached Images
    Last edited by Mybowlcut; June 21st, 2008 at 09:16 AM.
    Good judgment is gained from experience. Experience is gained from bad judgment.
    Cosy Little Game | SDL | GM script | VLD | Syntax Hlt | Can you help me with my homework assignment?

  6. #6
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: std::vector::push_back issue

    Look at the disassembly.

    00409664 is the actual call to print.
    00409663 is pushing the address of cout from ECX (this was loaded at 0040965C)
    00409662 is pushing the address of the string from EAX (this was loaded at 00409652 from the EDI register).

    Looking at the call to push_back we see

    004096FF is pushing the address of the string from the EDX (this was loaded at 0040966D from the EDI register)

    So the EDI register is containing the address of the string.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  7. #7
    Join Date
    Nov 2006
    Location
    Australia
    Posts
    1,569

    Re: std::vector::push_back issue

    Quote Originally Posted by TheCPUWizard
    Look at the disassembly.

    00409664 is the actual call to print.
    00409663 is pushing the address of cout from ECX (this was loaded at 0040965C)
    00409662 is pushing the address of the string from EAX (this was loaded at 00409652 from the EDI register).

    Looking at the call to push_back we see

    004096FF is pushing the address of the string from the EDX (this was loaded at 0040966D from the EDI register)

    So the EDI register is containing the address of the string.
    Hmm... I stopped debugging to post and I started debugging again and all the addresses have changed... I'm also unsure of how to cast an address to a string? I tried (std::string)(*0040B22B) but I really don't know... haha.

    Oh, I think the addresses changed because I turned optimisations off as per Paul's advice. It seemed to have the same problem though.
    Last edited by Mybowlcut; June 21st, 2008 at 09:34 AM.
    Good judgment is gained from experience. Experience is gained from bad judgment.
    Cosy Little Game | SDL | GM script | VLD | Syntax Hlt | Can you help me with my homework assignment?

Posting Permissions

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





Click Here to Expand Forum to Full Width

Featured