Член класса С++ является нулевым указателем

У меня есть класс (для рендеринга текста):

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 и поэтому должна иметь к нему доступ?

Извините, но на самом деле вы не инициализируете члены класса в конструкторе, а только некоторые временные переменные.

Sam Varshavchik 05.02.2019 19:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это локальные переменные функции в конструкторе. Они отличаются от переменных-членов класса. Как следствие, переменные-члены остаются неинициализированными после возврата конструктора.

Удалите строки:

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);
}

Я предлагаю увеличить уровень предупреждения вашего компилятора. Компилятор, вероятно, предупредит вас, что эти переменные, функциональные переменные, затеняют переменные-члены.

Стоит упомянуть, что компиляция с предупреждениями выдала бы предупреждение эта переменная затеняет ту переменную.

Fantastic Mr Fox 05.02.2019 19:44

Тогда мне пришлось бы инициализировать и уничтожать ft и face на каждой итерации цикла...

Fl.pf. 05.02.2019 19:48

@Fl.pf., для меня это не очевидно из опубликованного кода.

R Sahu 05.02.2019 19:50

Я не согласен. "Ваша функция должна быть:": TextRenderer::TextRenderer() : FT_Init_FreeType(&ft)); FT_New_Face(ft, "Assets/monospace.ttf", 0, &face); FT_Load_Char(face, 3, FT_LOAD_RENDER) {} - используйте список инициализации, а не тело ctor.

Jesper Juhl 05.02.2019 19:51

@Fl.pf. Это неправда, и это настолько далеко от истины, что я подозреваю, что вы не понимаете некоторых основ ООП. Прочтите еще раз описание того, как работают переменные-члены класса, в учебнике по C++.

Sneftel 05.02.2019 19:52

@Fl.pf. Важным моментом является затенение, ваш код может быть написан со списком инициализаторов или без него. Ваша ошибка: повторное объявлениеft и face. Вам не показалось странным, что вам пришлось объявить их дважды?

john 05.02.2019 19:56
Ответ принят как подходящий
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. 05.02.2019 19:46

@Fl.pf. Не объявляя локальные переменные, скрывающие их. Или, в идеале, просто инициализировать их в классе или в списке инициализации.

Jesper Juhl 05.02.2019 19:48

Хорошо, извините, у вас есть ссылка на это? Я не так много знаю об ООП и классах (я работаю только с Fortran), и я не знаю, что такое затенение или как я буду инициализировать переменную? в классе? или что такое список инициализации.

Fl.pf. 05.02.2019 19:52

@Fl.pf. Лучшая ссылка, которую я могу вам дать в таком случае, это stackoverflow.com/questions/388242/….

Jesper Juhl 05.02.2019 19:54

@Fl.pf. См. списки инициализаторов членов. Затенение — это концепция объявления нового объекта с тем же именем, что и у существующего объекта, так что новый скрывает (затеняет) предыдущий. В этом случае FT_Library ft; объявляет переменную с именем ft, но она затеняет this->ft (это совершенно другой и отдельный объект).

François Andrieux 05.02.2019 19:55

Другие вопросы по теме