Принято ли удалять синглтоны в 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 шт):

Автор решения: Harry

При завершении программы память автоматом освободится. Но это не значит, что будет выполнено еще что-то, в деструкторе прописанное. Совсем даже наоборот :)

Так что можете удалять сами (только после этого к нему не обращайтесь!), а можете выделять его не через указатель, а пользоваться статической переменной функции или класса, и тогда деструктор будет вызван автоматически перед окончательным завершением программы.

Нужно ли вам это — смотрите сами.

→ Ссылка
Автор решения: Bearded Beaver

В таком виде как у вас формально это утечка памяти, корректно память не освобождается при завершении программы и какой-нибудь ASAN или LSAN это задетектит. С практической стороны ничего страшного в этом нет, как упомянул @Harry, операционная система автоматически почистит всю память, выделенную вашей программой

Однако деструкторы объектов вызваны не будут, так что рассчитывать на сайд-эффекты от них (если таковые имеются) нельзя.

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

Все эти проблемы можно починить, создав синнлтон "правильно" (начиная с с++11 и дальше такой пассаж потокобезопасен):

class Textures {
public:
    static Textures& get() {
        static Textures instance;
        return instance;
    }

В таком случае деструктор будет вызван при завершении работы программы и все освободится как положено.

Не забудьте убрать copy-move конструкторы и операторы чтобы он был действительно singleton.

Немного больше информации тут https://stackoverflow.com/a/1008289/5998466

→ Ссылка