'SFML Ressource Manager class , null pointer on textures
I wrote a chess game and am now trying to change the design to include a Ressource Manager class (I have heard this is more efficient?). I am having issues though with null pointers regarding textures. I am getting the same errors both in this minimal example and on my main application.
Expected behavior
I am expecting 4 circles to appear on the screen distanced by 100 pixels.
Actual behavior
The screen flashes, then closes immediately with a segmentation fault
Minimally Reproducible Example
RessourceManager.hpp
#pragma once
#include <vector>
#include <unordered_map>
#include <SFML/Graphics.hpp>
#include <memory>
using namespace std;
typedef unordered_map<string, shared_ptr<sf::Texture>> textureMap;
class RessourceManager {
string m_textureNames[1] = {"circle.png"};
textureMap m_textures;
public:
RessourceManager(); // Constructor
void loadRessources();
void addTexture(const string& name);
shared_ptr<sf::Texture> getTexture(const string &name);
};
RessourceManager.cpp
#include "RessourceManager.hpp"
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
RessourceManager::RessourceManager() {};
void RessourceManager::addTexture(const string& name) {
shared_ptr<sf::Texture> texture = make_shared<sf::Texture>();
texture->loadFromFile(name);
m_textures.emplace(name, move(texture));
};
shared_ptr<sf::Texture> RessourceManager::getTexture(const string &name) {
for(auto it = m_textures.begin();it != m_textures.end(); ++it) {
if(it->first == name) {
cout << "found" <<endl;
return move(it->second);
}
}
return nullptr;
};
void RessourceManager::loadRessources() {
for(size_t i = 0; i < 1; ++i) addTexture(m_textureNames[i]);
}
main.cpp
#include <SFML/Graphics.hpp>
#include "RessourceManager.hpp"
void drawSquares(sf::RenderWindow&, RessourceManager&);
int main(){
sf::RenderWindow window(sf::VideoMode(600, 480), "SFML window");
RessourceManager ressources;
ressources.loadRessources();
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if (event.type == sf::Event::Closed) window.close();
}
drawSquares(window, ressources);
window.display();
}
return 0;
}
void drawSquares(sf::RenderWindow& window ,RessourceManager& ressources) {
for(int i = 20; i <= 320; ++i) {
shared_ptr<sf::Texture> temp = ressources.getTexture("circle.png");
sf::Sprite s(*temp);
s.setPosition(i, i);
window.draw(s);
}
}
Output console
found
found
[1] 4445 segmentation fault sudo ./main
Aditional information
Here I am using shared_ptr because I want multiple Sprites to point to the same texture (for instance 8 black pawns or 8 white pawns in a chess game). Further, I need these textures to move dynamically around on the screen so I must have them in the main loop in a standalone function.
Things I have tried
- In
drawSquares()I tried to first define an arrayshared_ptr<sf::Texture> textures[5];, populate it with the textures returned fromressources.getTexture()and then use these textures on the sprites in the for loop, but with no success. - I have tried using
unique_ptr - I have tried to write
sf::Sprite s(*(ressources.getTexture("circle.png")));immediately, but also doesn't work. - I have read the SFML documentation on Textures and c++ variable scope/life time information, but I still can't understand what I am doing wrong in here.
Solution 1:[1]
Answer was found
Thanks to metaquarks on Discord, removing the move() wrappers in move(it -> second) and .emplace(name. move(texture)) fixed the problem.
This is because after calling get(), the only thing keeping the texture alive is the pointer that was returned which is in this example dereferenced and passed as a non-owning reference, so it just dies. If one does not return using move(), both shared pointers keep it alive, and when the returned one eventually goes out of scope, it still exists because it is inside the map.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | hexaquark |
