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
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.
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
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...
Last edited by Mybowlcut; June 21st, 2008 at 09:16 AM.
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
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.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.