Singleton导致内存泄漏

时间:2017-04-22 15:26:16

标签: c++ memory-leaks singleton

所以我有一个像这样的单身游戏类:

class GameScene
{
public:
    ~GameScene();

    static GameScene& GetInstance()
    {
        static GameScene instance;
        return instance;
    };

    void MainMenu();
    void Gameplay();
    void GameOver();

    Sprite Sprites;
    Text* aText[2];
private:
    string MenuText[4];
    TextLabel* m_pText[5];

    GameScene();
    GameScene(const GameScene&) {}
    GameScene& operator=(const GameScene&) {};
};

请注意,我不是单身人士的专家,这是我第一次使用这种特殊的设计模式。

上面这个类的目的是避免在main.cpp中实例化多个游戏对象,只使用一个可以引用所有这些不同对象的单例实例。这就是我定义类的方法:

#include "GameScene.h"

GameScene::GameScene()
{
    m_pText[0] = new TextLabel("arial.ttf");
    m_pText[1] = new TextLabel("arial.ttf");
    m_pText[2] = new TextLabel("arial.ttf");
    m_pText[3] = new TextLabel("arial.ttf");

    // Do stuff with MenuText etc...
}

GameScene::~GameScene()
{
    // This is not being called :( 
    for (int i = 0; i < 4; ++i)
    {
        delete m_pText[i];
        m_pText[i] = nullptr;
    }
}

void GameScene::MainMenu()
{
    // Display some texts... 
}

void GameScene::Gameplay()
{
    // Display some texts...
}

void GameScene::GameOver()
{
    // Display some texts...
}

最后,不确定这是多么相关,这个问题对于你们中的一些人来说似乎已经很明显了,但这是main.cpp中的一个示例用法:

// Global Objects
GameScene* Manager;

// ...
// In a start up function()
Manager->GetInstance().aText[0] = new TextLabel("arial.ttf");
    Manager->GetInstance().aText[0]->Scale(0.2f);
    Manager->GetInstance().aText[0]->Color(glm::vec3(1.0f, 1.0f, 0.0f));
// ... 

// Finally in the render() function
// ...
if (IsPlaying)
    {
        GameManager->GetInstance().Sprites.Render();
        GameManager->GetInstance().aText[0]->Render();
        // ...
    }

我遇到的内存泄漏示例:

{295} normal block at 0x08A668F0, 44 bytes long.
 Data: <    pn          > F0 E4 86 04 70 6E A6 08 F0 E4 86 04 01 00 CD CD 
{294} normal block at 0x08A66DC0, 44 bytes long.
 Data: <Pu  8r   l      > 50 75 A6 08 38 72 A6 08 08 6C A6 08 00 00 CD CD 
{293} normal block at 0x08A66840, 44 bytes long.

注意:我知道我应该在某个时候解除分配“aText”,但问题不仅仅是来自aText数组的内存泄漏。我得到了数百个内存泄漏(即使我甚至根本没有分配那么多内存),它肯定与静态实例有关。有什么简单的方法来解决这个问题?谢谢。

1 个答案:

答案 0 :(得分:0)

首次调用GameScene::GetInstance时会构建静态实例,但

  

析构函数(12.4)用于静态存储持续时间的初始化对象   (在块作用域或命名空间作用域声明)作为结果被调用   从main返回并由于调用exit(18.3)。

因此,即使没有内存泄漏检查代码,也可能会报告内存泄漏。只是破坏者尚未被召唤。

错误报告内存泄漏的示例代码:

#include <memory>

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>

class A {
public:
    A() : pi(std::make_unique<int>(0)) {}
    std::unique_ptr<int> pi;
    static void CreateInstance() {
        static A instanceFunction;
    }
};

void main() {
    _CrtMemState initialMemoryState;
    _CrtMemCheckpoint(&initialMemoryState);

    A::CreateInstance();

    _CrtMemState finalMemoryState;
    _CrtMemCheckpoint(&finalMemoryState);
    _CrtMemState differenceMemoryState;
    if (_CrtMemDifference(&differenceMemoryState, &initialMemoryState, &finalMemoryState))
        _CrtMemDumpAllObjectsSince(&initialMemoryState);
}

要解决问题,您可以将静态实例定义为类memeber而不是局部变量。

标题文件:

#pragma once
#include <memory>

class A {
public:
    A() : pi(std::make_unique<int>(0)) {}
    std::unique_ptr<int> pi;
    static A& GetInstance() {
        return instance_;
    }
private:
    static A instance_;
};

Cpp文件:

#include "A.h"

A A::instance_;

另一种解决方案是使用Init / Shutdown对。