[c++/sdl_font] memleaking vector

Started by
10 comments, last by theSecondt 17 years, 6 months ago
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, fontX, fontX);


Advertisement
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.
"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
emm, i forgot to mention that i also tried adding a text.clear() into the loop, but it was the same.

yay, reading material!
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. <br><br>Regards<br>Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.
yes, but how would i implement this?
requesting examples.

EDIT:
i don't wanna use Boost atm, but you can supply those examples too, i guess.
ty.
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.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas only, and not for things themselves." - John Locke
nope, does not work.
i added: "delete text.back();" and it's making my app crash.
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.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas only, and not for things themselves." - John Locke
i normally delete sdl resources with SDL_FreeSurface((SDL_Surface*)Var) (in this case Var was text 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]
Quote:Original post by theSecondt
i normally delete sdl resources with SDL_FreeSurface((SDL_Surface*)Var) (in this case Var was text 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).
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas only, and not for things themselves." - John Locke

This topic is closed to new replies.

Advertisement