-2

I have a class (to render Text):

class TextRenderer {
public:
  TextRenderer();
  void RenderText(GLFWwindow *window, std::string text);
private:
  FT_Library ft;
  FT_Face face;
};

where I initialize the members ft and face in the constructor

TextRenderer::TextRenderer() {
    FT_Library ft;
    FT_Face face;

    FT_Init_FreeType(&ft));
    FT_New_Face(ft, "Assets/monospace.ttf", 0, &face);
    FT_Load_Char(face, 3, FT_LOAD_RENDER);

}
void TextRenderer::RenderText(GLFWwindow *window, std::string text) {
  FT_GlyphSlot slot = face->glyph; //Shortcut
  ...
}

but when I want to use it like this:

  TextRenderer tr;
  while (cond) {
    tr.RenderText(consoleEngine.window, prefix + inp);
  }

I get an error stating

Exception thrown: read access violation.
this->face was nullptr.

for the first line of the TextRenderer::RenterText function.

I don't understand this. Isn't the variable face a member of the class TextRenderer and should thus have access to it?

Fl.pf.
  • 324
  • 1
  • 5
  • 18

2 Answers2

2

Those are function local variables in the constructor. They are different from the member variables of the class. As a consequence, the member variables remain uninitialized after the constructor returns.

Remove the lines:

FT_Library ft;
FT_Face face;

Your function should be:

TextRenderer::TextRenderer() {
    FT_Init_FreeType(&ft);
    FT_New_Face(ft, "Assets/monospace.ttf", 0, &face);
    FT_Load_Char(face, 3, FT_LOAD_RENDER);
}

I suggest increasing the warning level of your compiler. The compiler will probably warn you that those variables, the function variables, shadow the member variables.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 2
    Worth a mention is that compiling with warnings would have given a *this variable shadows that variable* warning. – Fantastic Mr Fox Feb 05 '19 at 18:44
  • Then I would have to initialize and destruct ft and face in every iteration of the loop... – Fl.pf. Feb 05 '19 at 18:48
  • @Fl.pf., that's not obvious to me from the posted code. – R Sahu Feb 05 '19 at 18:50
  • 2
    I disagree. "Your function should be:": `TextRenderer::TextRenderer() : FT_Init_FreeType(&ft)); FT_New_Face(ft, "Assets/monospace.ttf", 0, &face); FT_Load_Char(face, 3, FT_LOAD_RENDER) {}` - use the initialisation list, not the ctor body. – Jesper Juhl Feb 05 '19 at 18:51
  • @Fl.pf. That's not true, and it's so far from being true that I suspect you're confused about some basics of OOP. Read your C++ textbook's description of how class member variables work again. – Sneftel Feb 05 '19 at 18:52
  • @Fl.pf. The important point is shadowing, your code could be written with or without an initialiser list. Your error was *redeclaring* `ft` and `face`. Did you not think it strange that it seemed you had to declare them twice? – john Feb 05 '19 at 18:56
2
TextRenderer::TextRenderer() {
    FT_Library ft;
    FT_Face face;

    FT_Init_FreeType(&ft));
    FT_New_Face(ft, "Assets/monospace.ttf", 0, &face);
    FT_Load_Char(face, 3, FT_LOAD_RENDER);
}

The ft and face variables you initialize are the local variables you declare in the constructor body. Not the member variables. You are shadowing those. The local variables will go out of scope / die once the ctor ends and your member variables will still be left uninitialised.

Also; do use the initialisation list rather than the ctor body.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
  • And how would I initialize the member variables? – Fl.pf. Feb 05 '19 at 18:46
  • @Fl.pf. By not declaring local variables shadowing them. Or, ideally, just initializing them in-class or in the initialisation list. – Jesper Juhl Feb 05 '19 at 18:48
  • Ok sorry, do you have a link for that? I don't know that much about OOP and classes (I only work with Fortran) and I don't know what shadowing is or how I would initialize a variable ?in-class? or what a initialization list is. – Fl.pf. Feb 05 '19 at 18:52
  • @Fl.pf. The best link I can give you in that case is https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – Jesper Juhl Feb 05 '19 at 18:54
  • 2
    @Fl.pf. See [member initializer lists](https://en.cppreference.com/w/cpp/language/initializer_list). Shadowing is the concept of declaring a new object with the same name as an existing object such that the new one hides (shadows) the previous one. In this case, `FT_Library ft;` declares a variable called `ft` but it shadows `this->ft` (which is a totally different and distinct object). – François Andrieux Feb 05 '19 at 18:55