Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Problem with sf::Text in a custom class  (Read 3179 times)

0 Members and 1 Guest are viewing this topic.

matfire

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Problem with sf::Text in a custom class
« 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

« Last Edit: March 19, 2019, 10:57:28 am by Laurent »

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Problem with sf::Text in a custom class
« Reply #1 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?
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

matfire

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: Problem with sf::Text in a custom class
« Reply #2 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?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Problem with sf::Text in a custom class
« Reply #3 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
Laurent Gomila - SFML developer

matfire

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: Problem with sf::Text in a custom class
« Reply #4 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

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Problem with sf::Text in a custom class
« Reply #5 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 ;)
Laurent Gomila - SFML developer

matfire

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: Problem with sf::Text in a custom class
« Reply #6 on: March 20, 2019, 12:37:49 pm »
it is caused by the push_back call on the vector.

Tigre Pablito

  • Full Member
  • ***
  • Posts: 225
    • View Profile
    • Email
Re: Problem with sf::Text in a custom class
« Reply #7 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