Sign in to follow this  
theSecondt

[c++/sdl_font] memleaking vector

Recommended Posts

hey, i have just started with vectors and it all went okay until i came to the part where i wanted to display FPS in the corner of the screen. i know when i did this with ordinary arrays, i had to freesurface before i reloaded the new value of the variable, but now it seems i have to do something else aswell? the code: main.cpp
 
TTF_Font *FontText;
std::vector<SDL_Surface*> text; 

//the var
std::stringstream ssFPS;
ssFPS << getFPS();

//set font
  FontText = TTF_OpenFont(font/font1.ttf, 12);

  //set font style
  TTF_SetFontStyle (FontText, TTF_STYLE_NORMAL);

  //set font color/alpha chan
  SDL_Color local_fg = {setRed,setGreen,setBlue,0};

  //render text
  //freesurface here, old way.
  //i did try by erasing the element out of the vector, but the memleak was still there
  text.push_back(TTF_RenderText_Solid(FontText, setFontVar.c_str(), local_fg));

  //set coords
  fontX.push_back(setFontX);
  fontY.push_back(setFontY);

  //blit text vectors
  for(short i= 0; i!= text.size(); i++)
    BlitIMG(text[i], fontX[i], fontX[i]);


Share this post


Link to post
Share on other sites
vector will clean up after itself, not after you. If you have a vector of pointers, vector will never destroy what these pointers point to. Indeed, it cannot know whether it should or not: you might be pointing to a statically allocated object or might still be using it through a pointer that the vector is unaware of.


When SDL gives you a pointer to a freshly allocated surface, font or howler monkey, you have the responsibility of deallocating it when you're done using it (which is why smart pointers are a good thing). Check the SDL documentation for further details.

Share this post


Link to post
Share on other sites
I think Fruny already answered your question. If you maintain a vector of pointers, it is your responsibility to delete() (or free()) the pointers. The vector will take care of itself.

A good rule to enforce is: every time you write 'new', you should also be writing 'delete' (in the appropriate place, of course). The same goes for 'malloc/calloc' and 'free', should you be possessed to use them. There are, of course, exceptions to this rule, but by the time you encounter one, you'll probably have the ritual firmly drilled in, and hence, the mentality successfully installed. [I think that's enough commas for one sentence]

Regards
Admiral

Share this post


Link to post
Share on other sites
For every pointer that you use SDL to initialize and then push into the vector, you need to use SDL to uninitialize that pointer when you're done with it, just like you would any pointer that is not in a vector. I've never used SDL, so I don't know the exact syntax, but a sufficient pattern to follow would be:

//Initialization:

std::vector<Something*> VectorOfPointers;

VectorOfPointers.push_back(CreateAnObjectAndReturnAPointer("a parameter"));
VectorOfPointers.push_back(CreateAnObjectAndReturnAPointer("a parameter"));
VectorOfPointers.push_back(CreateAnObjectAndReturnAPointer("a parameter"));
VectorOfPointers.push_back(CreateAnObjectAndReturnAPointer("a parameter"));



//Deinitialization:

while (!VectorOfPointers.empty())
{
DeleteAnObject(VectorOfPointers.back());
VectorOfPointers.pop_back();
}


In many cases, CreateAnObjectAndReturnAPointer() would be a simple call to new, and thus DeleteAnObject() would be a call to delete. In your case, they would be SDL-specific functions. But as Fruny said, standard containers only manage memory and resources that they allocate, which in this case is the space to store pointers (not the things being pointed to). Thus when a vector cleans up after itself, it only deallocates the memory for the pointers, not the stuff that the pointers point to.

Share this post


Link to post
Share on other sites
Quote:
Original post by theSecondt
nope, does not work.
i added: "delete text.back();" and it's making my app crash.

Is that how you normally delete SDL resources?

If so, what is the value of text.back() at the time you try to delete it? It's possible that it got altered somewhere along the way.

Share this post


Link to post
Share on other sites
i normally delete sdl resources with SDL_FreeSurface((SDL_Surface*)Var) (in this case Var was text[i] and the function was in a loop), but since that didn't work i'm puzzled :|

i printed out the values, they match
Quote:

1: 36449968 2: 36449968
1: 36446192 2: 36446192
1: 11526728 2: 11526728


edit: gonna try auto_ptr
edit2: and yet i fail.
code:
" std::vector< std::auto_ptr<SDL_Surface> > getFontText(){ return std::vector< std::auto_ptr<SDL_Surface> > (text); }"
errors:
Quote:

\include\c++\3.4.2\bits\stl_construct.h In function `void std::_Construct(_T1*, const _T2&) [with _T1 = std::auto_ptr<SDL_Surface>, _T2 = std::auto_ptr<SDL_Surface>]':
86 D:\zdelamo\Dev-Cpp\include\c++\3.4.2\bits\stl_uninitialized.h instantiated from `_ForwardIterator std::__uninitialized_copy_aux(_InputIterator, _InputIterator, _ForwardIterator, __false_type) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::auto_ptr<SDL_Surface>*, std::vector<std::auto_ptr<SDL_Surface>, std::allocator<std::auto_ptr<SDL_Surface> > > >, _ForwardIterator = std::auto_ptr<SDL_Surface>*]'
112 \include\c++\3.4.2\bits\stl_uninitialized.h instantiated from `_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::auto_ptr<SDL_Surface>*, std::vector<std::auto_ptr<SDL_Surface>, std::allocator<std::auto_ptr<SDL_Surface> > > >, _ForwardIterator = std::auto_ptr<SDL_Surface>*]'
221 \include\c++\3.4.2\bits\stl_vector.h instantiated from `std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::auto_ptr<SDL_Surface>, _Alloc = std::allocator<std::auto_ptr<SDL_Surface> >]'

81 \include\c++\3.4.2\bits\stl_construct.h passing `const std::auto_ptr<SDL_Surface>' as `this' argument of `std::auto_ptr<_Tp>::operator std::auto_ptr_ref<_Tp1>() [with _Tp1 = SDL_Surface, _Tp = SDL_Surface]' discards qualifiers


[Edited by - theSecondt on September 27, 2006 2:42:56 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by theSecondt
i normally delete sdl resources with SDL_FreeSurface((SDL_Surface*)Var) (in this case Var was text[i] and the function was in a loop), but since that didn't work i'm puzzled :|

Indeed that is puzzling, because SDL_FreeSurface((SDL_Surface*)text.back()) would be precisely what you need in the example I provided.

However, what this could mean might be that it's not the pointer itself or what it points to that is causing the problem, but something that you did earlier in the program. Sometimes, if you write to memory that shouldn't be written to (usually writing beyond the bounds of an array), nothing bad will happen at first, but the moment you try to free some memory, it might catch the error (some of the memory tracking data that the memory manager uses might have gotten overwritten, so now it has garbage and doesn't know how to delete memory), and cause the access violation that you're seeing.

Quote:
i printed out the values, they match
Quote:

1: 36449968 2: 36449968
1: 36446192 2: 36446192
1: 11526728 2: 11526728

That's good, at least.

Quote:

edit: gonna try auto_ptr
edit2: and yet i fail.
code:
" std::vector< std::auto_ptr<SDL_Surface> > getFontText(){ return std::vector< std::auto_ptr<SDL_Surface> > (text); }"
errors:
...


Unfortunately, std::auto_ptr won't work for containers, I believe due to not copying correctly, or at all (elements in standard containers have operator = and/or copy constructors called on them; if the type doesn't allow that, or doesn't handle those cases appropriately, problems will result). Either way, the only thing std::auto_ptr would do is try to call delete on the pointer, but what you need to do is call SDL_FreeSurface() on the pointer. You'd end up with a problem anyway, even if you used a smart pointer that does work with containers (such as boost::shared_ptr).

Share this post


Link to post
Share on other sites
Quote:
Original post by Agony
You'd end up with a problem anyway, even if you used a smart pointer that does work with containers (such as boost::shared_ptr).

Actually Boost's smart pointers are sufficiently smart that they could be used here. All you'd have to do is pass SDL_FreeSurface when constructing the pointer (boost::shared_ptr< SDL_Surface > shared_ptr(TTF_RenderText_Solid(FontText, setFontVar.c_str(), local_fg), SDL_FreeSurface);).

theSecondt: What exactly is going wrong and how are you diagnosing it? Going from an array to a vector should be trivial.

Σnigma

Share this post


Link to post
Share on other sites
sigh.
well, i can give you the whole code, since this were only snippets from different parts of different classes.

enigma: i know for sure that the problem occurs when i try to draw values from vars on screen, because they are in a loop.
static text(?) works fine(if i haven't done something horrific before in the code).

i have _tried_ to use gdb, but it fails at the 6th frame.. it seems there's a problem with the SDL_image library(or so i assume) i am using.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this