SFML 2.1 "setFont" unhandled exception

1

So I'm trying to use the .setFont(sf::Font) method from SFML, and it seems to somehow break the rest of the sf::Text object. I'm using the following function to do this:

sf::Text Renderer::CreateText(FontEntity font)
{
    sf::Text out;

    out.setFont(font.GetFont());
    out.setString(font.GetText());
    out.setCharacterSize(24);
    out.setColor(sf::Color::White);
    out.setStyle(sf::Text::Bold);

    return out;
}

The above is used in a draw call that I've implemented, and is where I think the problem probably lies (though I'm not sure where):

void Renderer::Draw(DrawData* drawData)
{
    this->window->clear();

    for (Entity* entity: drawData->GetEntities())
    {
        auto fontEntity = static_cast<FontEntity*>(entity);

        // If font entity
        if (fontEntity)
        {
            sf::Text text = CreateText(*fontEntity);
            this->window->draw(text);
        }
    }

    this->window->display();
}

This loops through a list of Entity objects, converts them to FontEntity objects, passes the converted FontEntity into the CreateText(FontEntity) method, and then tries to draw the sf::Text that is returned.

However, when out.setString(font.GetText()); is called, I get the exception:

Unhandled exception at 0x6177BA8C (sfml-graphics-d-2.dll) in GameEngine.exe: 0xC0000005: Access violation reading location 0x0000000D.

If, on the other hand, I remove the out.setFont(font.GetFont()) line, this error does not occur.

I was wondering if anyone knew exactly what's going on here? I can't seem to find any advice on this specific issue, and I've tried (and failed) to follow the SFML Text and fonts tutorial.

My first thoughts were that I have some sort of dodgy pointer issues going on, but as far as I understand the tutorial what I'm trying to do should be okay.

The FontEntity class is a custom class that I'm using to manage what are effectively drawable strings, but can be stored in my list of Entity objects nicely.

The .h file, if it helps, is as follows:

#include "Entity.h"
#include <string>
#include "SFML\Graphics.hpp"

class FontEntity : public Entity
{
public:
    FontEntity(float x, float y, sf::Font font);
    FontEntity(float x, float y, sf::Font font, std::string text);
    ~FontEntity(void);

    std::string GetText(void);
    void SetText(std::string);

    sf::Font GetFont(void);
    void SetFont(sf::Font);

    int GetSize(void);
    void SetSize(int);

protected:
    std::string text;
    sf::Font font;
    int size;
};

And the .cpp file:

#include "stdafx.h"
#include "FontEntity.h"


FontEntity::FontEntity(float x, float y, sf::Font font) : Entity(x, y)
{
    this->text = "";
    this->font = font;
}

FontEntity::FontEntity(float x, float y, sf::Font font, std::string text) : Entity(x, y)
{
    this->text = text;
    this->font = font;
}

FontEntity::~FontEntity(void)
{
}

std::string FontEntity::GetText(void)
{
    return this->text;
}

void FontEntity::SetText(std::string text)
{
    this->text = text;
}

sf::Font FontEntity::GetFont(void)
{
    return this->font;
}

void FontEntity::SetFont(sf::Font font)
{
    this->font = font;
}

int FontEntity::GetSize(void)
{
    return this->size;
}

void FontEntity::SetSize(int size)
{
    this->size = size;
}

Thanks for reading! All input is totally appreciated.

c++
sfml
asked on Stack Overflow Oct 24, 2013 by Callum Evans

1 Answer

1

Passing by value and passing by reference/pointer

sf::Font are heavy objects, never pass them by value, always by reference like so:

class FontEntity : public Entity
{
public:
    FontEntity(float x, float y, sf::Font* font);
    FontEntity(float x, float y, sf::Font* font, std::string text);
    ~FontEntity(void);

    // every member function that do not modify the object
    // should be const.
    std::string GetText(void) const;

    // most of the time, it's more efficient to pass-by-reference
    // except for base type (int, char, etc.)
    // std::string are not that big, so it's not really inefficient to
    // pass them by value
    void SetText(const std::string&);

    // you don't want the rest of the code messing with the font
    // parameter since it will affect every object that is using it.
    const sf::Font *GetFont(void) const;
    void SetFont(sf::Font*);

    int GetSize(void) const;
    void SetSize(int);

protected:
    std::string text;
    sf::Font* font; // keep a pointer to the sf::font
    int size;
};

On the other hand, sf::Text are very lightweight objects and are designed to be copied and passed everywhere.

As @Pawnguy7 commented, the error is coming from you passing sf::Font by value. This has to do with how you use C++ and not how SFML works. See the Rules of thumb for passing objects in C++.

Now your FontEntity

The other thing is, I don't really understand why you have FontEntity. You should only keep like a vector or list (any container you like) of sf::Text and just go through that vector and call this->window->draw(yourTextContainer.at(i)); or something like that.

If sf::Font were car mags and sf::Text car tire, your FontEntity would be like trying to put a tire on a tire on a wheel.

Also, why keeping your FontEntity objects in an Entity container? Casting is an expensive operation and should be avoided at all cost if possible by design. What is another expensive operation is creating text for each FontEntity each frame, what you should do is create them once and store them after for the rendering.

answered on Stack Overflow Oct 29, 2013 by Emile Bergeron • edited May 23, 2017 by Community

User contributions licensed under CC BY-SA 3.0