我正在尝试创建一个类对象的单个实例,以便只需通过包含标头并调用getInstance()
方法的相应形式,使该实例可以被任何其他需要它的类访问。我试图通过遵循显示here的Singleton示例来实现这一点,但由于某种原因,这个单个实例在创建后就会被销毁。
以下是标题文件Window.h
#pragma once
#include <string>
#include <SDL.h>
class Window {
public:
static Window* getInstance();
static Window* getInstance(const std::string &title, int width, int height);
private:
Window(const std::string &title, int width, int height);
~Window();
bool init();
std::string _title;
int _width = 800;
int _height = 600;
SDL_Window *_window = nullptr;
static Window *_instance;
// static Window _solidInstance;
};
以下是源文件Window.cpp
,其中删除了一些不相关的部分以节省空间。
#include "Window.h"
#include <iostream>
Window* Window::instance = 0;
SDL_Renderer *Window::_renderer = nullptr;
Window::Window(const std::string &title, int width, int height) {
// Code that isn't relevant to this issue
std::cout << "Window constructor called\n";
}
Window::~Window() {
// Code that isn't relevant to this issue
std::cout << "Window destructor called\n";
}
Window* Window::getInstance() {
return _instance;
}
Window* Window::getInstance(const std::string &title, int width, int height) {
if (_instance == 0) {
std::cout << "Just before construction\n";
_instance = &Window(title, width, height);
std::cout << "Just after construction\n";
// _solidInstance = Window(title, width, height);
}
return _instance;
}
构建并运行此代码后,将按以下顺序将以下行打印到控制台:
Just before construction
Window constructor called
Window destructor called
Just after construction
这告诉我,在getInstance()
甚至有机会返回之前,我创建的Window实例已经被销毁。我不确定如何防止这种情况发生。我已经尝试使用Window的常规实例而不是指向一个(请参阅引用soldInstance
的注释掉的代码行)但这只会给我链接器错误。
非常感谢任何帮助。
答案 0 :(得分:7)
您的问题出在此处:_instance = &Window(title, width, height);
您正在获取临时窗口的地址,该窗口在离开范围后会被销毁。
将其更改为:_instance = new Window(title, width, height);
但请务必在退出程序前删除该窗口!
在退出时自动删除窗口的更好的解决方案是:
Window* Window::getInstance(const std::string &title, int width, int height) {
static Window window{title, width, height};
return &window;
}
答案 1 :(得分:1)
_instance = &Window(title, width, height);
这会创建一个临时对象并获取其地址。表达式完成后,对象将被销毁,并且您将留下一个悬空指针。
要创建以更持久的方式存储的对象,请使用&#34; new&#34;要从堆中分配的运算符:
_instance = new Window(title, width, height);
小心这种单身方法。例如,你要求一个实例并提供可能使用或不使用的参数。如果尚未创建任何对象,则使用提供的参数创建窗口。但是,如果已经创建了窗口,则忽略提供的参数,您只需获得正常情况。这最终会给某人带来惊喜和愤怒。保证。
问题二,内存管理。在某些时候你应该删除这个指针。也许你可以通过将它存储在unique_ptr中来保存程序关闭,然后你可以用make_unique()分配它,但你应该考虑你做出的任何选择的后果。