SFML community forums

Help => Graphics => Topic started by: matfire on March 19, 2019, 10:23:23 am

Title: Problem with sf::Text in a custom class
Post by: matfire on March 19, 2019, 10:23:23 am
Hello everyone,

For the needs of a school project, I need to create a menu using only the standard SFML that loads all the games in a directory and lets the user choose which one he wants to play. So I created a custom class that I called TextItem that holds a reference to the font used for the title (sf::Font) and the sf::Text that is going to be rendered on screen. I then add all the texts to a vector (std::vector<TextItem>) with a push_back. The problem is that when I try to run my game loop (code below), I get an invalid free() error.

This is the main loop code:

        //TextureItem menuBg("./assets/arcade_img.bmp");
        std::vector<std::string> gameNames = getGamesNames();
        std::vector<TextItem> gameTexts = getGamesTexts(gameNames);
        int baseText = 100;
        std::cout << "loaded " << gameTexts.size() << " titles" << std::endl;
        while (_window.isOpen()) {
                int event = this->HandleEvents();
                if (event == 1)
                        break;
                _window.clear();
                //_window.draw(menuBg.getSprite());
                // for (auto a: gameTexts) {
                //      _window.draw(a.getText());
                // }
                _window.display();
        }
        return "";

This is the constructor for the TextItem class:

TextItem::TextItem(std::string fontPath, std::string text, int fontSize, sf::Font font) : _font(font), _text(text, _font, fontSize)
{
}

This is the function getGamesTexts
std::vector<TextItem> getGamesTexts(std::vector<std::string> gameNames)
{
        std::vector<TextItem> res;
        sf::Font font;
        font.loadFromFile("./assets/gamesFont.ttf");
        int baseText = 100;
        for (auto a: gameNames) {
                std::cout << "a" << std::endl;
                TextItem name("./assets/gamesFont.ttf", a, 20, font);
                //name.setCoordinates(40, baseText);
                //res.push_back(name);
                std::cout << "added " << a << " to list" << std::endl;
                baseText += 30;
        }
        return res;
}

If I comment out the res.push_back part I get an invalid free error, if I leave it there I get a std::bad_alloc error.

I'm sorry if I'm too vague in my description, if any other detail is needed please let me know.

Thanks

Title: Re: Problem with sf::Text in a custom class
Post by: Hapax on March 19, 2019, 06:58:54 pm
I didn't look into the code in detail.
However, I did notice that you're passing the font by value. It's likely you want to be passing it by reference (or pointer) so that you can work with the original font and not a copy.

You should be very aware that the font that the text is set to should exist as long as the text uses it. If you're using a copy, this won't be the case.

Another thing though, is that the sf::Text itself knows all about the font it uses so is there a real need to store a reference to the font as well?
Title: Re: Problem with sf::Text in a custom class
Post by: matfire on March 20, 2019, 10:31:13 am
I also tried initialising a font inside the class

TextItem::TextItem(std::string fontPath, std::string text, int fontSize)
{
   _font.loadFromFile(fontPath);
   _text.setFont(_font);
   _text.setString(text);
}

But I still get an std::bad_alloc. I'm thinking of just having a reference to the font in the Core (where windows, events etc are initialized) and the referencing it when initializing text, but it's not very elegant. What do you think?
Title: Re: Problem with sf::Text in a custom class
Post by: Laurent on March 20, 2019, 10:57:51 am
You should definitely not store a sf::Font inside your TextItem instances, because of two very good reasons :

1. All the TextItem objects share the same font, it's a big waste of memory (both system and GPU), loading time, and possibly performances, to duplicate it in each instance

2. Your TextItem instances get moved around implicitly (they are stored by value in std::vector), so their font member gets moved too, and the sf::Text that points to that font quickly gets a dangling pointer and crashes
Title: Re: Problem with sf::Text in a custom class
Post by: matfire on March 20, 2019, 12:20:14 pm
So,
I changed my contructor to this:

TextItem(std::string text, int fontSize, sf::Font *font)

I can tell call it like this:
TextItem name(a, 20, font); where font = sf::Text *
where font is sf::Font _titleFont;
Still getting a bad_alloc exception.

I'm sorry to be such bother, I'm still learning how c++ really works
Title: Re: Problem with sf::Text in a custom class
Post by: Laurent on March 20, 2019, 12:31:41 pm
So maybe now it's time to learn ahow a debugger works, to know more about this bad_alloc exception ;)
Title: Re: Problem with sf::Text in a custom class
Post by: matfire on March 20, 2019, 12:37:49 pm
it is caused by the push_back call on the vector.
Title: Re: Problem with sf::Text in a custom class
Post by: Tigre Pablito on March 22, 2019, 03:19:21 am
Hi Matfire

I saw this post casually. I don't know much c++ ... but it seems you are corrupting the memory with a buggy argument pass and Font object access

What you need is to list Names of Games and to enter a number to select one of them, isn't it?

Maybe you could try this: create a Text object (with its Font object just once passed in its argument list if possible) and when iterating through the Game Names list just change its "DisplayedString" and "Position" attributes, and Draw it ...

Obviously to learn to use the Debugger is a very good idea ... but if you don't understand very well the language internal stuff, I have some doubts that you understand it enough ...

Please let me know if I can help in something else
Pablo