Search code examples
c++exceptionsfml

Exception 0x00000004 (sfml-graphics-2.dll) occuring after compilation


Recently, I've started to learn SFML. The first thing I wanted to do was a simple menu - so I've created an interface for all menus, containing everything necessary for other menus in protected field. However, my code throws an exception at some point, and I have no idea, why.

#include <SFML/Graphics.hpp>
#include <iostream>

class Menu
{
protected:
    sf::Color red;
    sf::Color white;
    std::vector<sf::Text> displayedText;
    int currentOption{ 0 };
public:
    virtual void draww(sf::RenderWindow& window) = 0;
    virtual void clickButton() = 0;
    virtual void moveUp() = 0;
    virtual void moveDown() = 0;
};

class FirstMenu : public Menu
{
public:
    FirstMenu(sf::RenderWindow& window)
    {
        sf::Text text;
        sf::Font font;
        if (!font.loadFromFile("arial.ttf"))
        {
            std::cout << "Font error. \n";
        }
        text.setFont(font);
        text.setString("Play");
        displayedText.push_back(text);
        text.setString("Options");
        displayedText.push_back(text);
        displayedText[0].setFillColor(red);
        displayedText[0].setPosition(20, 30);
        displayedText[1].setPosition(30, 30);
    }
    virtual void clickButton()
    {
        switch (currentOption)
        {
        case 0:
            std::cout << "Playing. \n";
            break;
        case 1:
            std::cout << "Options. \n";
            break;
        }
    }
    virtual void moveUp()
    {
        currentOption++;
        displayedText[currentOption].setFillColor(white);
        for (int i = 0; i < displayedText.size(); i++)
        {
            if (i == currentOption)
            {
                displayedText[i].setFillColor(red);
            }
        }
    }
    virtual void moveDown()
    {
        currentOption--;
        displayedText[currentOption].setFillColor(white);
        for (int i = 0; i < displayedText.size(); i++)
        {
            if (i == currentOption)
            {
                displayedText[i].setFillColor(red);
            }
        }
    }
    virtual void draww(sf::RenderWindow& window)
    {
        if (!displayedText.empty())
        {
            for (int i = 0; i < displayedText.size(); i++)
            {
                window.draw(displayedText[i]); //Exception thrown here
            }
        }
    }
};

int main()
{
    sf::RenderWindow window(sf::VideoMode(500, 500), "SFML works!");
    FirstMenu menu(window);
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }
        window.clear();
        menu.draww(window);
        window.display();
    }
    return 0;
}

Text displayed while throwing exception is: "Unhandled exception in location 0x799B35BB (sfml-graphics-2.dll) 0xC0000005: Access violation while reading location 0x00000004"


Solution

  • The main issue I can see is that in the constructor of FirstMenu you are

    sf::Font font;
    if (!font.loadFromFile("arial.ttf"))
    {
        std::cout << "Font error. \n";
    }
    text.setFont(font)
    

    Essentially setting the text's font to a local font object. This is problematic because text in SFML doesn't copy the passed in font resource.

    SFML's documentation on the text class states this about setFont

    The font argument refers to a font that must exist as long as the text uses it. Indeed, the text doesn't store its own copy of the font, but rather keeps a pointer to the one that you passed to this function. If the font is destroyed and the text tries to use it, the behavior is undefined.

    It is also worth noting that the setTexture function for Shapes and Sprites behaves similarly as it doesn't store a copy of the texture resource.

    The fix is to ensure that the font object is never destroyed while it is being used by a text object.

    The simplest fixes include:

    1. Load the font in main and pass the font around to functions and objects that need it.
    2. If you are using a single font then have a global function that has a static font and constructs and loads it only once.
    3. If multiple fonts are needed and you don't want to pass the font around then you could have a singleton resource manager for fonts.