SFML Pointer to Pointer

Started by
6 comments, last by rip-off 12 years, 11 months ago
Hello, I have this function which creates SFML Strings / Fonts. But I want to refuse some of the already created fonts (if we load the same font file).
I have two std maps, seen here:


sf::String *CRenderManager::CreateFontString( const std::string &text, const std::string &fontFilename, float PosX, float PosY )
{
char MediaDIR[256];
sprintf_s( MediaDIR, 255, "media/%s", fontFilename.c_str() );

// [TJ]:
// Always alloc for a string, we check the map if we already have this font loaded
// so we don't need to use more memory (allocating sf::font)
sf::String *string = new sf::String;
sf::Font *fontFile = NULL;

std::map<std::string, sf::Font**>::iterator it = RenderFontPointers.find( MediaDIR );

if( it != RenderFontPointers.end() )
{
string->SetFont( **it->second );
}
else
{
sf::Font *fontFile = new sf::Font;
if( fontFile->LoadFromFile( MediaDIR ) )
{
string->SetFont( *(fontFile) );
RenderFontPointers[ MediaDIR ] = &fontFile;
}
}

RenderStrings[ text ] = string;
string->SetPosition( PosX, PosY );
string->SetText( text );

return string;
}


Maps:


std::map< std::string, sf::String* > RenderStrings;
std::map< std::string, sf::Font** > RenderFontPointers;

This code crashes when ran. It's use "RenderFontPointers" which is the problem. I'm sure there's a better way, I have a pointer->pointer->sf::font so I can reuse it. Any idea why it just crashes? Or is there a better way todo this? Sorry if it's to little code. Thanks!
Advertisement
What is the 'crash'? What is the debugger telling you is wrong?

What is the 'crash'? What is the debugger telling you is wrong?


Unfortunate, because of the way the debugger loads the .exe (i think?) it doesn't find my resources (.bmp .wav etc) so I have to run it outside the IDE,
or SFML dumps all kinds of "can't find file <file>" errors.

Unfortunate, because of the way the debugger loads the .exe (i think?) it doesn't find my resources (.bmp .wav etc) so I have to run it outside the IDE...
[/quote]
You just need to correct your working directory (which you can set in the IDE perferences), or don't use absolute paths.

As for your actual problems, you are storing a pointer to a local variable inside your map. Instead, don't store double pointers in the map, store regular pointers (or even smart pointers).

Offending line:

RenderFontPointers[ MediaDIR ] = &fontFile;
Thanks so much. It works now, along with the debugging!
[s]Because fontFile is just a local variable inside the else block. Once you exit the block, it doesn't exist anymore.

The font you have allocated on the heap still exists, but the particular 4 bytes you were using to hold the value of the pointer has been erased.[/s]

Bah, you edited out your question. Anyway I'll leave this in case the answer helps you.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game

[s]Because fontFile is just a local variable inside the else block. Once you exit the block, it doesn't exist anymore.

The font you have allocated on the heap still exists, but the particular 4 bytes you were using to hold the value of the pointer has been erased.[/s]

Bah, you edited out your question. Anyway I'll leave this in case the answer helps you.


Yeah. I didn't look hard enough before I posted. But i've ran into one last issue.
How can I "deallocate" memory via reference?

Removed like so:

void CRenderManager::ClearFontString( const std::string &text )
{
std::map<std::string, sf::String*>::iterator it = RenderStrings.find( text );
if( it != RenderStrings.end() )
{
delete it->second->GetFont();
delete it->second;

RenderStrings.erase( it );
}
}

GetFont() returns a reference (&).

Created like so:

sf::String *CRenderManager::CreateFontString( const std::string &text, const std::string &fontFilename, float PosX, float PosY )
{
char MediaDIR[256];
sprintf_s( MediaDIR, 255, "media/%s", fontFilename.c_str() );

// [TJ]:
// Always alloc for a string, we check the map if we already have this font loaded
// so we don't need to use more memory (allocating sf::font)
sf::String *string = new sf::String;
sf::Font *fontFile = NULL;

std::map<std::string, sf::Font*>::iterator it = RenderFontPointers.find( MediaDIR );

if( it != RenderFontPointers.end() )
{
string->SetFont( *(it->second) );
}
else
{
sf::Font *fontFile = new sf::Font;
if( fontFile->LoadFromFile( MediaDIR ) )
{
string->SetFont( *(fontFile) );
RenderFontPointers[ MediaDIR ] = fontFile;
}
}

RenderStrings[ text ] = string;

string->SetPosition( PosX, PosY );
string->SetText( text );

return string;
}


Sorry for the multiple code dumps.
Don't delete the font when removing a string, the font appears to be shared by multiple sf::String instances. However, You must delete the fonts in your destructor.

Also, CreateFontString could overwrite an existing entry in the map, even one that has a different font! I don't know why you are storing the strings in a map at all, the main reason to do so would be to cache duplicate strings, but you don't appear to be doing this. If you do want to cache repeated strings, I'd recommend restructuring your code like so:

class TextRenderer
{
public:

// ...

private:
struct FontData
{
sf::Font *font;
std::map<std::string, sf::String *> stringCache
};

map<std::string, std::shared_ptr<FontData> > FontMap;
};

Be very careful if you do decide to go down this route though, what happens if you end up trying to render the same string in two locations? I would probably just use a font cache for the moment, and only add a cache for the strings later on if this proves necessary.

This topic is closed to new replies.

Advertisement