Оптимизирует ли компилятор / компоновщик идентичный код в разных единицах перевода? - PullRequest
0 голосов
/ 06 августа 2020

Я пытаюсь написать базовую c оболочку над библиотекой GLFW и GLAD, чтобы я мог написать что-то вроде

graphics::Window window(*args*);
graphics::Shader shader(*args*);
graphics::Box box(*args*);

while(!window.shouldClose())
{
    box.draw(shader) // Draws in current context that is set behind the scenes in Window's constructor
    window.swapBuffer();
    graphics::pollEvents();
}

Таким образом, это в основном прямые вызовы функций GLFW и GL (в целом), но без необходимости раздувать клиентский код такими вещами, как glfwInit, gladLoadGLLoader, компиляция шейдеров, инициализация VBO и т. д. c. На пути реализации всего этого я столкнулся с некоторыми трудностями. Да, на самом деле это не один вопрос (который я упомянул в заголовке), но я не хотел разбивать их на разные вопросы, потому что все они как бы связаны.

Может случиться ситуация, и мне нужно позвонить GLFW работает в разных cpp файлах, поэтому я включаю glfw3.h несколько раз, и, насколько мне известно, один и тот же код компилируется несколько раз в разных единицах перевода. Вопрос: это правильно и нормально?

Как вы могли заметить, я немного одержим идеей «Оптимизация», «Разделение зон ответственности», «Обертка кода» и т. Д. c. Из-за этого я решил организовать свой код таким образом:

  1. Class GLFWCore берет на себя управление инициализацией GLFW (имеет glfwInit(); в своем частном конструкторе, glfwTerminate(); в его деструкторе и single publi c stati c method init, в теле которого есть только static GLFWCore core;)
  2. Class GLCore берет на себя управление инициализацией GLAD и ничего не знает о GLFW, он также имеет метод init, который должен правильно загружать функции OpenGL. Для этого он принимает указатель на функцию в качестве параметра: void*(*func)(const char* procName) и вызывает gladLoadGLLoader в своем теле
  3. Кто-то должен взять под контроль весь этот беспорядок, пусть это будет класс Window. Этот класс создает окно, поэтому он должен иметь GLFWWindow как закрытый член. Я думал о включении glfw3.h, но если кто-то включает мой класс Window, он включает и glfw3.h, и я не думаю, что это хорошо. А вот идиома pimpl! (Вопрос: хорошее ли это решение или я должен подумать о другом способе организации кода?). В результате я включаю glfw3.h в cpp файл, но это не идеально для меня, мысль «Боже мой, он компилируется несколько раз в разных cpp файлах» просто взрывает мой мозг (Как мне поступить с это?)
  4. Window конструктор вызывает метод инициализации GLFWCore (он обеспечивает инициализацию GLFW), затем он должен вызывать несколько функций GLFW, таких как glfwWindowHint или glfwCreateWindow. Должен ли я включать glfw3.h в этот cpp и вызывать эти функции напрямую или переносить их в класс, например GLFWCore (чтобы сохранить все вызовы glfw в одном cpp) и вызывать их через GLFWCore publi c stati c методы? В случае второго варианта, как быть с тем, что glfwCreateWindow возвращает указатель GLFWWindow, и я не хочу включать glfw3.h в свои заголовки? После создания окна и инициализации контекста функции OpenGL должны быть загружены, но я не хочу вызывать метод инициализации GLCore внутри конструктора Window (предположим, что GLCore вызвало исключение, в этот момент GLFWWindow было фактически создано, но не будет уничтожено, потому что деструктор Window не будет вызван)

Вопрос в том, не слишком ли я одержим идеей разделения зон ответственности и оптимизации CPP? Если нет, как я могу реализовать все вышеперечисленное "красивым" способом? Просто направь меня по правильному пути и расскажи мне ключевые моменты

...