This is really frustrating[Solved][SDL_SurfaceVectors]

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Post Reply
Aspirer
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 47
Joined: Tue May 01, 2012 8:20 pm

This is really frustrating[Solved][SDL_SurfaceVectors]

Post by Aspirer »

I'm trying to create a vector of SDL surface's, but for everything I try fails. Maybe its just not possible and I have to use some other kind of container, IDK.

Here's the most relevant part of my code:

Its a slightly modified tutorial function.

Code: Select all

void handle_input() {

if (event.type == SDL_KEYDOWN) {

	std::string temp = str;
	
	if ( str.length() <= 64) {
		logFile << "str's length is <= 64.\n";
		if ( event.key.keysym.unicode == (Uint16) ' ' ) {

			str += (char)event.key.keysym.unicode;
			logFile << "Space bar was pressed.\n";
		}
		else if ( ( event.key.keysym.unicode >= (Uint16)'0') && (event.key.keysym.unicode <= (Uint16) '9' ) ) //Finally works!
		{
			str += (char)event.key.keysym.unicode;
			logFile << "Number key: " <<(char)event.key.keysym.unicode << " pressed, and added to str.\n";
		}
		else if (( event.key.keysym.unicode >= (Uint16)'A' )&& (event.key.keysym.unicode <= (Uint16) 'Z') ) 
		{
			str += (char)event.key.keysym.unicode;
			logFile << "Number key: " <<(char)event.key.keysym.unicode << " pressed, and added to str.\n";
		}
		else if ( (event.key.keysym.unicode >= (Uint16)'a' )&& (event.key.keysym.unicode <= (Uint16) 'z' ) )
		{
				str += (char)event.key.keysym.unicode;
			logFile << "Number key: " <<(char)event.key.keysym.unicode << " pressed, and added to str.\n";
		}
		else if ( (event.key.keysym.unicode == SDLK_RETURN ) )
		{
			str = " RETURN WAS PRESSED.";

			
			//I am going to need to render multiple surfaces for each message, and two extra for the input window. This may need to be a vector of SDL_Surface's, and include two SDL_Rect's for both the body of messages, and the input box. The body will simply iterate through the SDL_Surface's, altering the SDL_Rect by 13 for every one, making them all move at the same time, then resetting the rect's Y value to the top position of the body. 
		
		}
		if (event.key.keysym.unicode == SDLK_BACKSPACE && str.length() != 0) {
			str.erase(str.length() - 1);

			logFile << "Backspace was pressed.\n";
		}
		if (str != temp) {
			SDL_FreeSurface ( text ); 
			text = TTF_RenderText_Solid(font, str.c_str(), textcolor); //Assigns the rendered text to the end of the suface_vect, vector..
			
			surface_vect->push_back (& text );

			logFile << "Full text rendered to SDL_Surface text: " << str.c_str() << "\n"; 
		}
	}
}
These are my errors:
1>------ Build started: Project: KeypressSDL, Configuration: Debug Win32 ------
1> NetworkingWithSDLExperiment.cpp
1>NetworkingWithSDLExperiment.cpp(119): error C2228: left of '.push_back' must have class/struct/union
1>------ Build started: Project: KeypressSDL, Configuration: Debug Win32 ------
1> NetworkingWithSDLExperiment.cpp
1>NetworkingWithSDLExperiment.cpp(119): error C2228: left of '.push_back' must have class/struct/union
1> type is 'std::vector<_Ty> *[1]'
1> with
1> [
1> _Ty=SDL_Surface
1> ]

1>NetworkingWithSDLExperiment.cpp(376): error C2065: 'vertCoord' : undeclared identifier //Ignore this.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
On a side note,
I just do not know how to read these massive statements, like the one in bold there. If I did it might help me. But other things like a function argument list, which pops up an intellisense thingamjigger which shows what its supposed to be, I find impossible to comprehend!

Is there a way to make a potentially infinite list of surfaces? I know that would create more overhead with every new surface, but I just need to make a few. This function is supposed to take input from the user, display it in the window, and once return is pressed, move the message and any others away from the box, and upward. I know of no other way to make multiple lines of text in a surface other than to make more surfaces!

Im
Last edited by Aspirer on Wed Aug 08, 2012 6:06 pm, edited 2 times in total.
"We got more information out of a German general with a game of chess or Ping-Pong than they do today, with their torture" --Henry Kolm
User avatar
Nokurn
Chaos Rift Regular
Chaos Rift Regular
Posts: 164
Joined: Mon Jan 31, 2011 12:08 pm
Favorite Gaming Platforms: PC, SNES, Dreamcast, PS2, N64
Programming Language of Choice: Proper C++
Location: Southern California
Contact:

Re: This is really frustrating (SDL_Surface vectors?)

Post by Nokurn »

There's a whole lot of code here and only one line has anything to do with the problem. I'd suggest fixing that.

Inferring what I can from that one line and the build log, it looks like surface_vect is defined like this:

Code: Select all

std::vector<SDL_Surface>* surface_vect;
There's a few problems with this:

1. There's approximately two scenarios in the entire world in which you would want a pointer to a std::vector, and I doubt that this is one of those cases. If you're using new/delete a lot in your code--particularly with STL types--you're seriously misusing C++ and you're inflicting a lot of pain on yourself. If surface_vect is a pointer to a non-pointer elsewhere, you should either be checking it for NULL or using a reference instead.

2. You never, ever deal with an SDL_Surface. You do, however, deal with SDL_Surface*. This is the primary issue here. You're trying to put a SDL_Surface* into a vector of SDL_Surface. Change your template argument.

3. Unless you're explicitly cleaning up surface_vect with SDL_FreeSurface somewhere, you're going to leak memory like a motherfucker. And because std::vector doesn't properly destroy pointers when it's destroyed or cleared or even when an element is erased, your SDL_Surfaces will remain unfreed when an exception pulls you out of scope even if you do explicit cleanup elsewhere (eg, in your destructor). You need a smart pointer that uses SDL_FreeSurface instead of delete (easy enough to write on your own).
Aspirer
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 47
Joined: Tue May 01, 2012 8:20 pm

Re: This is really frustrating (SDL_Surface vectors?)

Post by Aspirer »

Code: Select all

vector <auto_ptr<SDL_Surface> >surface_vect [1];

void handle_input() {

    if (event.type == SDL_KEYDOWN) {

       std::string temp = str;
       //Unimportant code deleted for this!
          if (str != temp) {
             SDL_FreeSurface ( text );
             text = TTF_RenderText_Solid(font, str.c_str(), textcolor); //Assigns the rendered text to the end of the suface_vect, vector..
             
             surface_vect.push_back (& text );

             logFile << "Full text rendered to SDL_Surface text: " << str.c_str() << "\n";
          }
       }
    }

Is that what you meant by smart pointer?

That's some very useful information, I didn't know any of that. All I know is how to write the language, and my experience with libraries is that of an absolute newbie.

I have to ask, since I wasn't using something to clean up surface_vect, but I've never used it in release mode, did it get cleaned up when I exited debug mode, or must I shut down my computer?
"We got more information out of a German general with a game of chess or Ping-Pong than they do today, with their torture" --Henry Kolm
User avatar
YourNerdyJoe
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
Posts: 79
Joined: Sun Oct 02, 2011 3:28 pm
Current Project: Top secret (not really) Top-Down Shooter for GBA
Favorite Gaming Platforms: GBA, Gamecube, PC, 3DS
Programming Language of Choice: C/C++
Contact:

Re: This is really frustrating (SDL_Surface vectors?)

Post by YourNerdyJoe »

From what I see surface_vect is defined like

Code: Select all

std::vector<SDL_Surface>* surface_vect;
and text is defined as

Code: Select all

SDL_Surface* text;
so when when you say

Code: Select all

surface_vect->push_back (& text );
push_back is expecting a SDL_Surface and you're giving it a SDL_Surface**.
So changing it to this should make it work as intended:

Code: Select all

std::vector<SDL_Surface*> surface_vect;
//and
surface_vect.push_back(text);
At the end of the program just loop through the vector and call SDL_FreeSurface on each one to prevent any memory leaks.
See that?.....
Exactly
https://yournerdyjoe.github.io/
User avatar
Nokurn
Chaos Rift Regular
Chaos Rift Regular
Posts: 164
Joined: Mon Jan 31, 2011 12:08 pm
Favorite Gaming Platforms: PC, SNES, Dreamcast, PS2, N64
Programming Language of Choice: Proper C++
Location: Southern California
Contact:

Re: This is really frustrating (SDL_Surface vectors?)

Post by Nokurn »

What YourNerdyJoe said about your push_back is also correct.

I don't understand why you're making an array of one vector of SDL_Surface auto_ptr. That [1] is extremely unnecessary; it's about on par with "a = a;" on the unnecessary meter.

Using straight auto_ptr will not work. auto_ptr will call delete on your SDL_Surface, which will cause all sorts of fuck. SDL_Surface can only be destroyed using SDL_FreeSurface. Also, auto_ptr is deprecated; don't use it unless you don't have access to any alternatives (std::shared_ptr or std::unique_ptr).

If you can use std::shared_ptr:

Code: Select all

typedef std::shared_ptr<SDL_Surface> SharedSurface;

SharedSurface ShareSurface(SDL_Surface* surface)
{
    return SharedSurface(surface, SDL_FreeSurface);
}

std::vector<SharedSurface> surface_vect;
If std::unique_ptr is better suited:

Code: Select all

struct SdlSurfaceDeleter {
    void operator()(SDL_Surface* surface)
    {
        SDL_FreeSurface(surface);
    }
};

typedef std::unique_ptr<SDL_Surface, SdlSurfaceDeleter> SharedSurface;

std::vector<SharedSurface> surface_vect;
If you can't use either, you'll have to come up with your own pointer class. It'll be ugly without rvalue references. You could also do some hacky shit with a std::vector wrapper that replaces clear(), erase(), ~(), etc. with versions that do SDL_FreeSurface.

Side node, what's with all of these topics in which smart pointers are a relevant subject?
Aspirer
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 47
Joined: Tue May 01, 2012 8:20 pm

Re: This is really frustrating (SDL_Surface vectors?)

Post by Aspirer »

Ah, NerdyJoe, that's exactly what I was planning, I just didn't understand how to make it happen. I wasn't sure if you could have a vector of pointers.
I don't understand why you're making an array of one vector of SDL_Surface auto_ptr. That [1] is extremely unnecessary; it's about on par with "a = a;" on the unnecessary meter.
As to that, you did say use a smart pointer if I wanted to make a vector of SDL surface's, I've never used one so I googled it. I found wikipedia, and chose the statement which came under "smart pointers". I'm not using C++11, unless I got some kind of update I don't know about, so I don't think its relevant to me. I read in that same article on wikipedia the statement is deprecated and knew this before you mentioned it, but since I'm not using C++11, I don't think it matters. Maybe I'm wrong, I'm not sure.

EDIT: I just ran it a few times, an every time I exited the program after that code ran, it would just hang there and I would have to shut down the debugger. Then I realized, since its freeing surfaces, they are being deleted, and when I'm deleting surfaces the size of the vector is being reduced, but my for...next loop counts upward, and deletes (uses SDL_FreeSurface() )in that direction as well. So I should have to count downward since its basically "stealing" memory out from under it. So I changed it to count down, and it stopped hanging! Haha! I'm a freakin' genius sometimes!
"We got more information out of a German general with a game of chess or Ping-Pong than they do today, with their torture" --Henry Kolm
User avatar
Nokurn
Chaos Rift Regular
Chaos Rift Regular
Posts: 164
Joined: Mon Jan 31, 2011 12:08 pm
Favorite Gaming Platforms: PC, SNES, Dreamcast, PS2, N64
Programming Language of Choice: Proper C++
Location: Southern California
Contact:

Re: This is really frustrating (SDL_Surface vectors?)

Post by Nokurn »

Aspirer wrote:I wasn't sure if you could have a vector of pointers.
You can have a vector of whatever you want, but pointers won't be properly destroyed when the vector is destroyed, cleared, or when an element is erased.
Aspirer wrote:As to that, you did say use a smart pointer if I wanted to make a vector of SDL surface's, I've never used one so I googled it. I found wikipedia, and chose the statement which came under "smart pointers". I'm not using C++11, unless I got some kind of update I don't know about, so I don't think its relevant to me. I read in that same article on wikipedia the statement is deprecated and knew this before you mentioned it, but since I'm not using C++11, I don't think it matters. Maybe I'm wrong, I'm not sure.
In this case, it does matter. std::auto_ptr was a poorly designed class and it doesn't allow you to use a custom deleter--which is mandatory for using any smart pointer template with SDL_Surface.

If you can't use C++11, you might be able to get away with using raw pointers as long as you are very cautious to clean up after yourself. For every surface_vect.erase(iter), there must be a preceding SDL_FreeSurface(*iter). In your destructor, and before every surface_vect.clear(), you'll need something like this:

Code: Select all

for (std::vector<SDL_Surface*>::iterator iter = surface_vect.begin(); iter != surface_vect.end(); ++i)
    SDL_FreeSurface(*iter);
However, your code won't be very robust, and it may cause problems down the road.
Aspirer wrote:EDIT: I just ran it a few times, an every time I exited the program after that code ran, it would just hang there and I would have to shut down the debugger. Then I realized, since its freeing surfaces, they are being deleted, and when I'm deleting surfaces the size of the vector is being reduced, but my for...next loop counts upward, and deletes (uses SDL_FreeSurface() )in that direction as well. So I should have to count downward since its basically "stealing" memory out from under it. So I changed it to count down, and it stopped hanging! Haha! I'm a freakin' genius sometimes!
If you're removing a range of surfaces, it would be more efficient to first call SDL_FreeSurface on each element to be removed, and then remove the entire range at once. For example, if you're writing a clear() method, you could use the snippet above followed by:

Code: Select all

surface_vect.erase(surface_vect.begin(), surface_vect.end());
Aspirer
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 47
Joined: Tue May 01, 2012 8:20 pm

Re: This is really frustrating (SDL_Surface vectors?)

Post by Aspirer »

Thank you Nokurn, that sort of helped.

After some searching, I found a way to dynamically create unlimited (unlimited so far as there is enough memory!) surfaces. I used SDL_CreateRGB();

Here's my code in case anyone wants to know how to do what I did:

Code: Select all

vector <SDL_Surface*> surface_vect;

	Uint32 rmask, gmask, bmask, amask;

Code: Select all

		  surface_vect.push_back( SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,
                                   rmask, gmask, bmask, amask) );
		  if ( surface_vect.back() == NULL ) { 
			 logFile << "\nSurface_vect.at(" << surf_count << "failed to have a new surface added to it!\n";
			  return false;
		  }else  {
			  surf_count+=1;
		  surface_vect.back() = TTF_RenderText_Solid(font, str.c_str(), textcolor);
		  logFile << "surface_vect has: " << surf_count << " surfaces!";
		  str = "";
		  }
     }

Code: Select all

 //Sets the byte order of the bitmasks. Necessary because every computer has a different byteorder, if I am not mistaken.
if( SDL_BYTEORDER == SDL_BIG_ENDIAN ) {
    rmask = 0xff000000;
    gmask = 0x00ff0000;
    bmask = 0x0000ff00;
    amask = 0x000000ff;
}
else {
    rmask = 0x000000ff;
    gmask = 0x0000ff00;
    bmask = 0x00ff0000;
    amask = 0xff000000;
} 
Info on SDL_CreateRGB:

http://www.libsdl.org/docs/html/sdlcrea ... rface.html
"We got more information out of a German general with a game of chess or Ping-Pong than they do today, with their torture" --Henry Kolm
Post Reply