Проблема с std::вектор и пользовательский класс, который включает в себя sf:: Текст, C , SFML

#c #vector #sfml #stdvector

Вопрос:

Я создаю графическое приложение, используя библиотеку SFML. У меня есть класс Square , который создает квадратный блок с буквой внутри. У этого класса есть члены sf:: Font и sf::Text , за исключением самого квадрата ( sf::RectangleShape ). Конструктор этого класса принимает размер стороны квадрата, его положение, путь к шрифту, расположенному в папке проекта, и букву, на которую будет записано sf:: Text . Класс также содержит draw() метод, который берет объект sf::RenderWindow типа и рисует сам квадрат и текст, используя его.

Вот в чем проблема. Когда я создаю несколько экземпляров площади (и, соответственно, письмо с ним) с использованием отдельных переменных, все работает нормально, но когда я пытаюсь push_back площадях std::vector , все ломается, ошибки вылетают в режиме отладки и в режиме релиза только маленькие точки взяты вместо букв и программа не работает правильно, окно может перестать отвечать на запросы (только квадраты без письма работать с std::vector и их тянет нормально)

Я думаю, что есть ошибки, связанные с динамической памятью, указателями или итераторами, но я сам не могу разобраться и понять, что происходит, заранее благодарю вас за помощь.

Код для лучшего понимания:

 class Square
{
public:
    RectangleShape m_square;
    Font m_font;
    Text m_text;

    Square(int size, Vector2f pos, string fontPath, string letter)
    {
        m_square.setFillColor(Color(0, 0, 0, 50));
        m_square.setSize(Vector2f(size, size));
        m_square.setPosition(pos);
    
        if (!m_font.loadFromFile(fontPath))
            wcout << "Error loading the font!" << endl;

        m_text.setFont(m_font);
        m_text.setFillColor(Color(0, 0, 0, 220));
        m_text.setCharacterSize(size * 0.8);
        m_text.setString(letter);
        m_text.setPosition(Vector2f((pos.x - m_text.getGlobalBounds().left)   (size - m_text.getGlobalBounds().width) / 2, pos.y));
    }   

    void draw(RenderWindowamp; window)
    {
        window.draw(m_square);
        window.draw(m_text);
    }

};
 

main.cpp:

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

#include "Square.h"

using namespace sf;
using namespace std;

int main()
{
    ContextSettings settings;
    settings.antialiasingLevel = 10;
    RenderWindow window(VideoMode(1200, 800), "My window", Style::Default, settings);
    window.setVerticalSyncEnabled(true);

    Square sq1(50, Vector2f(100, 100), "Roboto-Bold.ttf", "A");
    Square sq2(50, Vector2f(200, 100), "Roboto-Bold.ttf", "B");
    Square sq3(50, Vector2f(100, 200), "Roboto-Bold.ttf", "C");
    Square sq4(50, Vector2f(200, 200), "Roboto-Bold.ttf", "D");

    vector<Square> squares;
    squares.push_back(Square(50, Vector2f(400, 100), "Roboto-Bold.ttf", "A"));
    squares.push_back(Square(50, Vector2f(500, 100), "Roboto-Bold.ttf", "B"));
    squares.push_back(Square(50, Vector2f(400, 200), "Roboto-Bold.ttf", "C"));
    squares.push_back(Square(50, Vector2f(500, 200), "Roboto-Bold.ttf", "D"));

    while (window.isOpen())
    {
        window.clear(Color::White);

        Event event;
        while (window.pollEvent(event))
        {
            if (event.type == Event::Closed)
            {
                window.close();
            }
        }

        sq1.draw(window);
        sq2.draw(window);
        sq3.draw(window);
        sq4.draw(window);

        for (autoamp; s : squares)
        {
            s.draw(window);
        }

        window.display();

        if (Keyboard::isKeyPressed(Keyboard::Escape))
        {
            window.close();
        }
    }
}
 

Вот скриншот окна программы

Любая помощь будет признательна.

Комментарии:

1.Начните читать документацию перед написанием кода.. Text::setFont Аргумент шрифта ссылается на шрифт, который должен существовать до тех пор, пока текст его использует. Действительно, текст не хранит свою собственную копию шрифта, а скорее сохраняет указатель на тот, который вы передали этой функции. Если шрифт уничтожен и текст пытается его использовать, поведение не определено. у вас висит ссылка на шрифт из — за его неглубокого копирования-выполняется операция копирования по умолчанию Square .

2. Используйте интеллектуальные указатели, чтобы сохранить все ваши объекты — чтобы избежать их неглубокого копирования или обеспечить правильные операции, такие как конструкторы копирования/перемещения и операторы присваивания.

Ответ №1:

В качестве простого обходного пути и небольшого улучшения памяти и производительности рассмотрите возможность хранения ваших шрифтов в std::map<std::string, sf::Font> папке. Эта структура данных позволяет сопоставлять имя шрифта с объектом, и она обладает тем приятным свойством, что объекты в ней не перемещаются при добавлении новых.

 // add this at top level
std::map<std::string, sf::Font> fonts;

// Change the Square constructor as such:
Square(int size, Vector2f pos, string fontPath, string letter) {
  if (auto it = fonts.find(fontPath); it == fonts.cend()) {
    // Font was not created before.
    autoamp; font = fonts[fontPath]; // this access will create a Font object and automatically store it in the map
    if (!font.loadFromFile(fontPath))
      wcout << "Error loading the font!" << endl;
  }
  ...
  m_text.setFont(fonts[fontPath]);
  ...
}
 

и, конечно же, избавиться от m_font члена.