例如,有一个类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
,但不会在任何地方删除。然而,单例在整个执行过程中都存在,并且至少出于安全原因,任何操作系统都必须在进程终止后完全清除进程的内存。那么,是否可以不删除它们呢?
当程序结束时,内存会自动释放。但这并不意味着析构函数中指定的其他内容将被执行。恰恰相反:)
所以你可以自己删除它(只是之后不要访问它!),或者你可以不通过指针分配它,而是使用函数或类的静态变量,然后析构函数将在final之前自动调用程序终止。
您是否需要它 - 亲自看看。
从你的形式来看,这在形式上是内存泄漏,程序结束时内存没有正确释放,一些ASAN或LSAN会检测到这一点。从实用的角度来看,这没有什么问题,正如@Harry提到的,操作系统会自动清理你的程序分配的所有内存
但是,不会调用对象析构函数,因此您不能指望它们的副作用(如果有)。
代码中的另一个问题是您的 synlton 不是线程安全的,如果两个线程同时进行检查,它们将看到指针为空,并且都会创建一个实例。
所有这些问题都可以通过“正确”创建 Synlton 来解决(从 c++11 开始,这段文字是线程安全的):
在这种情况下,当程序退出时将调用析构函数,并且所有内容都将按预期释放。
不要忘记删除复制移动构造函数和运算符,以便它是真正的单例。
这里有更多信息https://stackoverflow.com/a/1008289/5998466