I have a class Message that has a std::string as a data member, defined like this:
class Message
{
// Member Variables
private:
std::string text;
(...)
// Member Functions
public:
Message(const std::string& t)
: text(t) {}
std::string getText() const {return text;}
(...)
};
This class is used in a vector in another class, like this:
class Console
{
// Member Variables
private:
std::vector<Message> messageLog;
(...)
// Member Functions
public:
Console()
{
messageLog.push_back(Message("Hello World!"));
}
void draw() const;
};
In draw(), there's an iterator that calls getText(). When it does, the program segfaults. I've determined that text is valid inside the Message constructor. However, I can't tell if it's valid from inside Console. I'm assuming it is, but if I try to inspect indices of Console's messageLog, gdb tells me this:
(gdb) p messageLog[0]
One of the arguments you tried to pass to operator[] could not be converted to what
the function wants.
Anyone know what's going on?
EDIT: here's draw(). TCODConsole is part of a curses library I'm using, and so this function prints each message in Console to a part of the curses screen. TL and BR are Point member objects (two ints) that tell where on the screen to draw Console. I left out parts of Message and Console in the original question to hopefully make things clearer, but if you need me to post the entire classes then I can. They aren't too long.
void Console::draw() const
{
int x = TL.getX(), y = TL.getY();
int width = BR.getX() - TL.getX();
int height = BR.getY() - TL.getY();
// draw the Console frame
TCODConsole::root->printFrame(x, y, width, height, true);
// print the Console's messages
vector<Message>::const_iterator it;
for(it=messageLog.begin(); it<messageLog.begin()+height-1; ++it)
{
string message = "%c" + it->getText();
TCODConsole::setColorControl(TCOD_COLCTRL_1,
it->getForeColor(),
it->getBackColor());
y += TCODConsole::root->printRectEx(x, y, width, height,
TCOD_BKGND_NONE,
TCOD_LEFT,
message.c_str(),
TCOD_COLCTRL_1);
}
}
My guess is that by the point you use it->getText(), the iterator is NULL. Add a check it != messageLog.end() when you walk the array, and before calling it->getText().
Is it definitely std::vector messageLog and not std::vector<Message> messageLog? That seems a bit odd.
What does the height have to do with the vector's index? You have:
messageLog.begin()+height-1;
Why are you adding the screen coordinate to the iterator? That seems to be your problem and you're most likely overindexing and that's why you're getting a SIGSEGV.
What you probably want is to simply iterate over all the messages in the vector and display them at a particular location on the screen. I see what you're trying to do, but if you're trying to calculate the screen boundary using the iterator you're definitely going about it the wrong way. Try running a counter or get messageLog.size() and then recalculate the height with each iteration. As for the loop just do:
for(it=messageLog.begin(); it!=messageLog.end(); ++it)
It's probably because the scope of the Message object created in the Console method is just the Console method. So, if your program is trying to access this object in another method, like draw, you will get this segmentation fault, since this object is deleted after the execution.
Try this (just insert a new keyword):
Console()
{
messageLog.push_back(new Message("Hello World!"));
}
In this case, the object is not deleted after Console's end.
Just remember to delete the objects created when your program doesn't need them anymore.
Related
EDIT 2:
as suspected the solution was hidden in plain sight. Thanks to #hyde for not only a helpful answer but one which taught me something i had not known before.
EDIT:
I had thought adding a little context would be helpful but perhaps it only has caused some misdirection. I'm sure the solution is simple and right under my nose.
I have a function:
cursorPosition(int y, int x)
{
getyx(_win, y, x);
}
i want this function to modify y and x to contain the cursor position of _win, a window object.
instead it returns y = 0, x = 0, persistently.
my question is what am i missing.
i will leave the rest of the post untouched. But you don't need to go further.
--end transmission--
i have a class object which uses the ncurses library and i am trying to get the position of the cursor in the screen.
I can clearly see that the cursor moves when i call wmove and wprintw methods within the window, but when i check the cursor position it reads y = 0, x = 0. I cannot figure out why it will not retrieve the actual cursor position. getyx(stdscr,y,x ) and getsyx(y,x) seem to work fine which both use stdscr, but i need to use a new window and not the stdscr window.
here are some (relevant) details of my code:
I create class called Window.
Window is a wrapper for an ncurses window object, with methods to print to and modify that window:
class Window
{
public:
// if int is 1: calls initscr and creates a newwin to assign to member variable 'win'
// if int is 0: calls delwin, sets member variable '_win' to nullptr then endwin
setWin(int)
// calls setWin(0) if member variable '_win' is not already nullptr
~Window()
// retrieves the cursor position
cursorPosition(int y, int x)
private:
WINDOW * _win = nullptr;
}
HERE is the problem:
cursorPosition just wraps around '''getyx(_win,y,x)''', using the private member variable '''_win'''.
I will later create a shared pointer to this window object called DISPLAY, and i am doing this:
DISPLAY->setWin(1);
int CURSOR_Y, CURSOR_X;
DISPLAY->cursorPosition(CURSOR_Y, CURSOR_X);
std::string yx = std::tostring(CURSOR_Y) + " " + std::to_string(CURSOR_X);
// prints to '_win' with 'wprintw'.
DISPLAY->print(yx)
however i always get back
"0 0"
And indeed this is true because when i try to use to navigate the window CURSOR_Y and CURSOR_X, anything i output is in the top left corner.
getyx etc are macros, and take internally the address of their y and x macro parameters. So you need to be able to modify the original x and y passed to your function.
Since you are using C++, simply use references:
cursorPosition(int &y, int &x)
Now when the macro internally takes address of x and y, it will get the address of the originals, not just local copies.
PS. This once again demonstrates how macros are quite horrible and create confusing code and confusing error messages (just try getyx(_win, 1, 1); to see).
So i have some troubles getting pointers to work with SFML shapes. I'm not sure if it has something to do with SFML or if I'm doing anything wrong.
In Draw() x(a ControlWindow) does not contain valid values, it only shows "???" as shown here. However the m_controls(map) contains the correct values for the control object.
I'm quite new to C++ so any help would be greatly appreciated.
Exception
Exception thrown at 0x60B26EE5 (sfml-graphics-2.dll) in OokiiUI.exe: 0xC0000005: Access violation reading location 0x00000000.
Main
vector<WindowControl> windowControls;
void Draw ();
int main ()
{
RectangleShape rect(Vector2f(120,120));
WindowControl windowControl(nullptr,0);
Control testControl(&windowControl,1);
testControl.SetShape(&rect);
windowControl.AddControl(testControl);
windowControls.push_back(windowControl);
return 0;
}
WindowControl
class WindowControl : Control
{
public:
WindowControl ( WindowControl * windowControl, uint64_t uint64 )
: Control ( windowControl, uint64 )
{
}
void AddControl(Control control)
{
m_controls.insert_or_assign(control.GetId(), control);
m_controlPtrs.push_back(&control);
}
vector<Control*>* GetControls()
{
return &m_controlPtrs;
}
private:
map<uint64_t, Control> m_controls;
vector<Control*> m_controlPtrs;
};
Draw
for (auto x : windowControls)
{
vector<Control*> *controlPtrs = x.GetControls();
window->draw(x.GetControl(0)->GetShape());
}
There is a problem here:
void AddControl(Control control)
{
m_controls.insert_or_assign(control.GetId(), control);
m_controlPtrs.push_back(&control);
}
You add the address of the parameter control which is destroyed when the function ends. It looks like you want to add the address of the copy that you add to your map like this:
void AddControl(Control control)
{
m_controls.insert_or_assign(control.GetId(), control);
// don't use the parameter here, use the copy you put in the map
m_controlPtrs.push_back(&m_controls[control.GetId()]);
}
Although that is not ideal because if you send the same control twice, it will only appear once in the map (updated) but twice in the vector of pointers. You can use the returned pait from insert_or_update to fix that:
void AddControl(Control control)
{
auto [iter, was_inserted] = m_controls.insert_or_assign(control.GetId(), control);
// only add to vector if it was not in the map before
if(was_inserted)
m_controlPtrs.push_back(&iter->second);
}
A side note:
It is more idiomatic to return a reference in this situation rather than a pointer:
vector<Control*>& GetControls()
{
return m_controlPtrs;
}
This also breaks encapsulation so it may be worth thinking about how you can avoid accessing the internals of your objects so directly.
Your problem is that you are adding the pointer of a local variable into your m_controlPtrs:
void AddControl(Control control)
{
m_controlPtrs.push_back(&control);
}
Here you take a copy of Control, then add the address of that into your vector. The moment the function returns, your object goes out of scope and that memory is pointing to uninitialised garbage.
You probably want to update AddControl to take a Control&.
#ShadowRanger raises a good point in the comments: what I've mentioned may fix your issue, perhaps indefinitely, but your design still isn't terrific. Any time you have a Control which won't outlive m_controlPtrs you're going to encounter this same problem. Your code is small now, but this may eventually turn into a nightmare to fix. It's likely you should instead update m_controlPtrs to share (or take) ownership of the Control so this problem won't occur.
The easiest way out is to have m_controlPtrs declared as a std::vector<std::shared_ptr<Control>>, but it's something you should think about.
I'm entirely new to SDL 2 , and I'm hoping to find some help with making my very first proper program for a class in it. We've been provided with some code already for use in this project, which is why I'm not simply using a BlitSurface function to make this solution. If that is indeed the better solution, I'll switch over to that. This is part of a State to be used when the program runs, showing a title image.
I am getting a break error due to a pointer issue in the following code:
void MenuState::Enter()
{
//Is to load the title image used for the State
Sprite* extBackgroundSprite = met_extSystem.met_pointextSpriteManager- >CreateSprite("../assets/Testimage1.bmp" , 0 , 0 , 768 , 1024);
}
Which refers to a Sprite made by a SpriteManager class and CreateSprite function, as seen here:
Sprite * SpriteManager::CreateSprite(const std::string & point_stringFilePath, int point_intX, int point_intY, int point_intWidth, int point_intHeight)
{
auto iter = met_arraypointextTextures.find(point_stringFilePath); //breaks here
if (iter == met_arraypointextTextures.end())
//If the iterator cannot locate the sprite we need in our already loaded memory,
//it needs to be loaded into our map to create pointers
{
SDL_Surface* extSurface = SDL_LoadBMP(point_stringFilePath.c_str());
SDL_Texture* extTexture = SDL_CreateTextureFromSurface(met_pointextRenderer, extSurface);
SDL_FreeSurface(extSurface);
met_arraypointextTextures.insert(std::pair<std::string, SDL_Texture*>(point_stringFilePath, extTexture));
iter = met_arraypointextTextures.find(point_stringFilePath);
}
//Creates the sprite, adds a new index point via pushback
Sprite* extSprite = new Sprite(iter->second, point_intX, point_intY, point_intWidth, point_intHeight);
met_arraypointextSprites.push_back(extSprite);
return extSprite;
}
I hope this is enough information and code to present my problem. If not, let me know! And thank you in advance.
Turns out the issue was impossible to solve with the information I provided. The pointer did indeed need to be initialized, but with arguments found in the constructor, which I had not provided here.
I'm building a simple generic engine for my true start in the making of games, and I am trying to be somehow organized and decent in the making of my engine, meaning I don't want it to be something I throw to the side once I make what I'm planning to.
I add objects to be displayed, drawObjects, and these can either move, not move, and have an animation, or not have one.
In case they DO have an animation, I want to initialize a single animationSet, and this animationSet will have xxx animationComp inside of it. As I'm trying to be neat and have worked abit on "optimizations" towards memory and cpu usage (such as sharing already-loaded image pointers, and whatever came across my mind), I wanted to not ask for possibly unused memory in arrays.
So I had animationSetS* animationSet = NULL; initially, planning to do a animationSet = animationSetS[spacesINEED]; after, only on the objects that needed animation that I added, being those that aren't animations a NULL and therefore not using memory (correct?).
And then this question popped up! (title)
struct animationComp {
SDL_Rect* clip;
int clipsize;
};
struct animationSetS {
animationComp* animation;
int currentFrame;
int currentAnimation;
int animationNumber;
};
struct drawObject { // Um objecto.
char* name;
SDL_Surface* surface;
bool draw = true;
float xPos;
float yPos;
bool willMove = false; // 0 - Won't move, 10 - Moves alot, TO IMPLEMENT
bool isSprite = false;
animationSetS* animationSet;
};
I dabble alot in my questions, sorry for that. For any clarifications reply here, I'll reply within 10 minutes for the next... 1 hour perhaps? Or more.
Thanks!
Setting the pointer to NULL means that you'll be able to add ASSERT(ptr != NULL); and KNOW that your pointer does not accidentally contain some rubbish value from whatever happens to be in the memory it was using.
So, if for some reason, you end up using the object before it's been properly set up, you can detect it.
It also helps if you sometimes don't use a field, you can still call delete stuff; [assuming it's allocated in the first place].
Note that leaving a variable uninitialized means that it can have ANY value within it's valid range [and for some types, outside the valid range - e.g. pointers and floating point values can be "values that are not allowed by the processor"]. This means that it's impossible to "tell" within the code if it has been initialized or not - but things will go horribly wrong if you don't initialize things!
If this should be really implemented in C++ (as you write), why don't you use the C++ Standard Library? Like
struct animationSetS {
std::vector< std::shared_ptr<animationComp> > animation;
// ...
}
when i run my program it compiles fine but when it runs i get this box which stops my program. the box says this Unhandled exception at 0x0039e9a7 in Mon.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd. i don't even know what that means. when it breaks it point at this function.
void CXFileEntity::SetAnimationSet(unsigned int index)
{
if (index==m_currentAnimationSet)
return;
if (index>=m_numAnimationSets)
index=0;
// Remember current animation
m_currentAnimationSet=index;
// Get the animation set from the controller
LPD3DXANIMATIONSET set;
IT BREAKS HERE>>>>m_animController->GetAnimationSet(m_currentAnimationSet, &set );
// Note: for a smooth transition between animation sets we can use two tracks and assign the new set to the track
// not currently playing then insert Keys into the KeyTrack to do the transition between the tracks
// tracks can be mixed together so we can gradually change into the new animation
// Alternate tracks
DWORD newTrack = ( m_currentTrack == 0 ? 1 : 0 );
// Assign to our track
m_animController->SetTrackAnimationSet( newTrack, set );
set->Release();
// Clear any track events currently assigned to our two tracks
m_animController->UnkeyAllTrackEvents( m_currentTrack );
m_animController->UnkeyAllTrackEvents( newTrack );
// Add an event key to disable the currently playing track kMoveTransitionTime seconds in the future
m_animController->KeyTrackEnable( m_currentTrack, FALSE, m_currentTime + kMoveTransitionTime );
// Add an event key to change the speed right away so the animation completes in kMoveTransitionTime seconds
m_animController->KeyTrackSpeed( m_currentTrack, 0.0f, m_currentTime, kMoveTransitionTime, D3DXTRANSITION_LINEAR );
// Add an event to change the weighting of the current track (the effect it has blended with the secon track)
m_animController->KeyTrackWeight( m_currentTrack, 0.0f, m_currentTime, kMoveTransitionTime, D3DXTRANSITION_LINEAR );
// Enable the new track
m_animController->SetTrackEnable( newTrack, TRUE );
// Add an event key to set the speed of the track
m_animController->KeyTrackSpeed( newTrack, 1.0f, m_currentTime, kMoveTransitionTime, D3DXTRANSITION_LINEAR );
// Add an event to change the weighting of the current track (the effect it has blended with the first track)
// As you can see this will go from 0 effect to total effect(1.0f) in kMoveTransitionTime seconds and the first track goes from
// total to 0.0f in the same time.
m_animController->KeyTrackWeight( newTrack, 1.0f, m_currentTime, kMoveTransitionTime, D3DXTRANSITION_LINEAR );
// Remember current track
m_currentTrack = newTrack;
}
any idea?
UPDATE
this is the class
class CXFileEntity
{
private:
LPDIRECT3DDEVICE9 m_d3dDevice; // note: a pointer copy (not a good idea but for simplicities sake)
// Direct3D objects required for animation
LPD3DXFRAME m_frameRoot;
LPD3DXANIMATIONCONTROLLER m_animController;
D3DXMESHCONTAINER_EXTENDED* m_firstMesh;
// Bone data
D3DXMATRIX *m_boneMatrices;
UINT m_maxBones;
// Animation variables
unsigned int m_currentAnimationSet;
unsigned int m_numAnimationSets;
unsigned int m_currentTrack;
float m_currentTime;
float m_speedAdjust;
// Bounding sphere (for camera placement)
D3DXVECTOR3 m_sphereCentre;
float m_sphereRadius;
std::string m_filename;
void UpdateFrameMatrices(const D3DXFRAME *frameBase, const D3DXMATRIX *parentMatrix);
void UpdateSkinnedMesh(const D3DXFRAME *frameBase);
void DrawFrame(LPD3DXFRAME frame) const;
void DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase) const;
void SetupBoneMatrices(D3DXFRAME_EXTENDED *pFrame/*, LPD3DXMATRIX pParentMatrix*/);
public:
CXFileEntity(LPDIRECT3DDEVICE9 d3dDevice);
~CXFileEntity(void);
bool Load(const std::string &filename);
void FrameMove(float elapsedTime,const D3DXMATRIX *matWorld);
void Render() const;
void SetAnimationSet(unsigned int index);
void NextAnimation();
void AnimateFaster();
void AnimateSlower();
D3DXVECTOR3 GetInitialCameraPosition() const;
unsigned int GetCurrentAnimationSet() const {return m_currentAnimationSet;}
std::string GetAnimationSetName(unsigned int index);
std::string GetFilename() const {return m_filename;}
};
im releasing m_animController in the destructor
0xC0000005: Access violation reading
location 0xcdcdcdcd.
Well it's simple :
Access violation is an error where you tried to access some memory that are allowed to be accessed. For example you might be trying to use a null pointer.
Here the 0xcdcdcdcd part is a special adress put by visual studio when a pointer have been deleted (or more precisely, the object pointed by the pointer is destroyed and the pointer is set to this value) or non-initialized > (edit: I'm not sure anymore, will have to check the VS documentation). That's true only in Debug mode if my memory is correct.
So here, m_animController is in a wrong state (as it seems that it's the unique pointer of the expression where it crashes).
First, I would suggest that you make sure that delete have not been called before on this pointer. It might be obvious or it might be that you call delete in the object destructor and you didn't see that this object have bee destroyed or copied. If your object (CXFileEntity) must not be copied, make sure it can't be (by inheriting from boost::noncopiable or by putting it's copy constructor and copy operator in private with no implementation).
Next, if you really have to use raw pointers (instead of references or smart pointers) you'd better check all your pointers (and other contextual values) at the start of each function, using assertions (look for assertions in google and stackoverflow, there is a lot of discussions about that). Even better: check that pointers are valid each time you get them from functions. That will help you track early when a a pointer got in a state you didn't expect.
You attempted to access memory to which you do not have access. Most commonly this is because you are using a pointer that you have not initialized and it points to an address that's not in your process's memory space.
You should make sure that m_animController is initialized (and pointing to a valid object) before you dereference it with the -> operator.
You have a bad pointer somewhere. Based on the line where it breaks, I'm guessing m_animController has a bad value. Check that m_animController is initialized to a default value. And make sure you aren't deleting it somewhere before using it.
Note: 0xcdcdcdcd is a common value that some debuggers will initialize invalid pointers with, but it's not guaranteed.