У меня есть класс (для рендеринга текста):
class TextRenderer {
public:
TextRenderer();
void RenderText(GLFWwindow *window, std::string text);
private:
FT_Library ft;
FT_Face face;
};
где я инициализирую члены ft и face в конструкторе
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
...
}
но когда я хочу использовать его так:
TextRenderer tr;
while (cond) {
tr.RenderText(consoleEngine.window, prefix + inp);
}
я получаю сообщение об ошибке
Exception thrown: read access violation.
this->face was nullptr.
для первой строки функции TextRenderer::RenterText.
Я этого не понимаю. Разве переменная face не является членом класса TextRenderer и поэтому должна иметь к нему доступ?





Это локальные переменные функции в конструкторе. Они отличаются от переменных-членов класса. Как следствие, переменные-члены остаются неинициализированными после возврата конструктора.
Удалите строки:
FT_Library ft;
FT_Face face;
Ваша функция должна быть:
TextRenderer::TextRenderer() {
FT_Init_FreeType(&ft);
FT_New_Face(ft, "Assets/monospace.ttf", 0, &face);
FT_Load_Char(face, 3, FT_LOAD_RENDER);
}
Я предлагаю увеличить уровень предупреждения вашего компилятора. Компилятор, вероятно, предупредит вас, что эти переменные, функциональные переменные, затеняют переменные-члены.
Стоит упомянуть, что компиляция с предупреждениями выдала бы предупреждение эта переменная затеняет ту переменную.
Тогда мне пришлось бы инициализировать и уничтожать ft и face на каждой итерации цикла...
@Fl.pf., для меня это не очевидно из опубликованного кода.
Я не согласен. "Ваша функция должна быть:": TextRenderer::TextRenderer() : FT_Init_FreeType(&ft)); FT_New_Face(ft, "Assets/monospace.ttf", 0, &face); FT_Load_Char(face, 3, FT_LOAD_RENDER) {} - используйте список инициализации, а не тело ctor.
@Fl.pf. Это неправда, и это настолько далеко от истины, что я подозреваю, что вы не понимаете некоторых основ ООП. Прочтите еще раз описание того, как работают переменные-члены класса, в учебнике по C++.
@Fl.pf. Важным моментом является затенение, ваш код может быть написан со списком инициализаторов или без него. Ваша ошибка: повторное объявлениеft и face. Вам не показалось странным, что вам пришлось объявить их дважды?
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);
}
Инициализируемые вами переменные ft и face являются локальными переменными, которые вы объявляете в теле конструктора. Нет переменные-члены. Вы следите за ними. Локальные переменные выйдут из области видимости / умрут, как только ctor завершится, а ваши переменные-члены по-прежнему останутся неинициализированными.
Также; используйте список инициализации, а не тело ctor.
И как мне инициализировать переменные-члены?
@Fl.pf. Не объявляя локальные переменные, скрывающие их. Или, в идеале, просто инициализировать их в классе или в списке инициализации.
Хорошо, извините, у вас есть ссылка на это? Я не так много знаю об ООП и классах (я работаю только с Fortran), и я не знаю, что такое затенение или как я буду инициализировать переменную? в классе? или что такое список инициализации.
@Fl.pf. Лучшая ссылка, которую я могу вам дать в таком случае, это stackoverflow.com/questions/388242/….
@Fl.pf. См. списки инициализаторов членов. Затенение — это концепция объявления нового объекта с тем же именем, что и у существующего объекта, так что новый скрывает (затеняет) предыдущий. В этом случае FT_Library ft; объявляет переменную с именем ft, но она затеняет this->ft (это совершенно другой и отдельный объект).
Извините, но на самом деле вы не инициализируете члены класса в конструкторе, а только некоторые временные переменные.