Принято ли удалять синглтоны в C++?
Например, есть класс Textures
:
Textures.hpp
:
#include <unordered_map>
#include <SFML/Graphics.hpp>
#pragma once
class Textures {
public:
static Textures *get() {
if (Textures::singletone == nullptr) {
Textures::singletone = new Textures();
}
return Textures::singletone;
}
void add(const std::string& name, const std::string& path);
void add(const std::string& name, const sf::Texture& texture);
sf::Texture *get(const std::string& name);
private:
Textures() = default;
Textures(const Textures& copy);
static Textures *singletone;
std::unordered_map<std::string, sf::Texture> textures;
};
Textures.cpp
:
#include <iostream>
#include "Textures.hpp"
#include "Root.hpp"
#include "CouldntOpenTexture.hpp"
Textures *Textures::singletone = nullptr;
void Textures::add(const std::string& name, const std::string& path) {
if (!this->textures[name].loadFromFile(Root::get()->getDataRoot() + "/" + path)) {
throw CouldntOpenTexture(path);
}
}
void Textures::add(const std::string& name, const sf::Texture& texture) {
this->textures[name] = texture;
}
sf::Texture *Textures::get(const std::string& name) {
auto it = this->textures.find(name);
if (it == this->textures.end()) {
std::cerr << "Invalid texture uid: " << name << std::endl;
}
return &it->second;
}
Очевидно, что тут есть утечка памяти; *Textures singletone
выделяется через new
, но нигде не удаляется. Однако синглтоны существуют все время выполнения, а любая операционная система должна ведь, как минимум по соображениям безопасности, полностью очищать память процесса после его завершения. Можно ли в связи с этим их не удалять?
Ответы (2 шт):
При завершении программы память автоматом освободится. Но это не значит, что будет выполнено еще что-то, в деструкторе прописанное. Совсем даже наоборот :)
Так что можете удалять сами (только после этого к нему не обращайтесь!), а можете выделять его не через указатель, а пользоваться статической переменной функции или класса, и тогда деструктор будет вызван автоматически перед окончательным завершением программы.
Нужно ли вам это — смотрите сами.
В таком виде как у вас формально это утечка памяти, корректно память не освобождается при завершении программы и какой-нибудь ASAN или LSAN это задетектит. С практической стороны ничего страшного в этом нет, как упомянул @Harry, операционная система автоматически почистит всю память, выделенную вашей программой
Однако деструкторы объектов вызваны не будут, так что рассчитывать на сайд-эффекты от них (если таковые имеются) нельзя.
Еще одна проблема в вашем коде в том, что ваш синлтон не потокобезопасен, если два потока одновременно сделают проверку, они увидят что указатель нулевой и оба создадут инстанс.
Все эти проблемы можно починить, создав синнлтон "правильно" (начиная с с++11 и дальше такой пассаж потокобезопасен):
class Textures {
public:
static Textures& get() {
static Textures instance;
return instance;
}
В таком случае деструктор будет вызван при завершении работы программы и все освободится как положено.
Не забудьте убрать copy-move конструкторы и операторы чтобы он был действительно singleton.
Немного больше информации тут https://stackoverflow.com/a/1008289/5998466