有人能解释一下为什么在释放指向它们的指针后我仍然有活动的对象吗?

我正在试验单例模式,以便更容易地使用DirectX API的一些常用接口,但是我有一个似乎无法解决的问题。

这是我的定义:

#include <d3d11.h>
#include <d3dx11.h>
#include <DxErr.h>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "DxErr.lib")

class Core
{
public:
    ~Core();

    static ID3D11Device*& getDevice();
    static ID3D11DeviceContext*& getContext();
    static IDXGISwapChain*& getSwapChain();
    static ID3D11RenderTargetView*& getRenderTargetView();
    static ID3D11Debug*& getDebug();

    static HRESULT Initialize(HWND hwnd);
    static void Reset();

private:
    Core();

    HRESULT CreateDevice();

    static Core*            instance;

    ID3D11Device*           device;
    ID3D11DeviceContext*    context;

    IDXGISwapChain*         swapChain;
    IDXGIDevice1*           ddevice;
    IDXGIAdapter1*          adapter;
    IDXGIFactory1*          factory;
    ID3D11RenderTargetView* rtv;
    ID3D11Debug*            debug;

    Core(Core const&);             
    void operator=(Core const&);
};

实现如下:

#include "Core.h"

Core* Core::instance;

Core::Core()
{
    HRESULT hr;
    hr = CreateDevice();
    if(FAILED(hr)) throw hr;
}

Core::~Core()
{
    if (device) device->Release();
    if (context) context->Release();

    if (swapChain) swapChain->Release();
    if (ddevice) ddevice->Release();
    if (adapter) adapter->Release();
    if (factory) factory->Release();
    if (rtv) rtv->Release();

    debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);

}

//--------------------------------------------------------------------------------
// Get Functions
//--------------------------------------------------------------------------------

ID3D11Device*& Core::getDevice()
{
    if (!instance)
    {
        try
        {
            instance = new Core();
        }
        catch (HRESULT hr)
        {
            throw hr;
        }
    }
    return instance->device;
}

ID3D11DeviceContext*& Core::getContext()
{
    if (!instance)
    {
        try
        {
            instance = new Core();
        }
        catch (HRESULT hr)
        {
            throw hr;
        }
    }
    return instance->context;
}


IDXGISwapChain*& Core::getSwapChain()
{
    if (!instance)
    {
        try
        {
            instance = new Core();
        }
        catch (HRESULT hr)
        {
            throw hr;
        }
    }

    return instance->swapChain;
}

ID3D11RenderTargetView*& Core::getRenderTargetView()
{
    if (!instance)
    {
        try
        {
            instance = new Core();
        }
        catch (HRESULT hr)
        {
            throw hr;
        }
    }
    return instance->rtv;
}

ID3D11Debug*& Core::getDebug()
{
    if (!instance)
    {
        try
        {
            instance = new Core();
        }
        catch (HRESULT hr)
        {
            throw hr;
        }
    }
    return instance->debug;
}


//--------------------------------------------------------------------------------
// Other Functions
//--------------------------------------------------------------------------------

HRESULT Core::CreateDevice()
{
    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
    };
    D3D_FEATURE_LEVEL featureLevel;

    UINT flags = NULL;
#ifdef _DEBUG
    flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    HRESULT hr;

    hr = D3D11CreateDevice(
        NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        flags,
        featureLevels,
        ARRAYSIZE(featureLevels),
        D3D11_SDK_VERSION,
        &device,
        &featureLevel,
        &context);
    if(FAILED(hr)) return hr;

    hr = device->QueryInterface(__uuidof(ID3D11Debug), (void**) &debug);
    if(FAILED(hr)) return hr;
    hr = device->QueryInterface(__uuidof(IDXGIDevice1), (void**) &ddevice);
    if(FAILED(hr)) return hr;
    hr = ddevice->GetParent(__uuidof(IDXGIAdapter1), (void**) &adapter);
    if(FAILED(hr)) return hr;
    hr = adapter->GetParent(__uuidof(IDXGIFactory1), (void**) &factory);
    if(FAILED(hr)) return hr;

    return S_OK;
}

HRESULT Core::Initialize(HWND hwnd)
{
    // Create the swap chain
    RECT rc;
    GetClientRect(hwnd, &rc);
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;

    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory( &sd, sizeof( sd ) );
    sd.BufferCount = 1;
    sd.BufferDesc.Width = width;
    sd.BufferDesc.Height = height;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = hwnd;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.Windowed = TRUE;

    if (!instance)
    {
        try
        {
            instance = new Core();
        }
        catch (HRESULT hr)
        {
            return hr;
        }
    }

    instance->factory->CreateSwapChain(instance->device, &sd, &instance->swapChain);

    // Create and set the render target view
    HRESULT hr;
    ID3D11Texture2D* renderingBuffer;   
    hr = instance->swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**) &renderingBuffer);
    if(FAILED(hr)) 
    {
        renderingBuffer->Release();
        return hr;
    }
    hr = instance->device->CreateRenderTargetView(renderingBuffer, NULL, &instance->rtv);
    renderingBuffer->Release();
    if(FAILED(hr)) return hr;

    // TODO: create and set the depth stencil view

    instance->context->OMSetRenderTargets(1, &instance->rtv, nullptr);

    return S_OK;
}

void Core::Reset()
{
    delete instance;
}

调用析构函数,但在退出应用程序后仍在输出窗口中看到以下内容:

D3D11 WARNING: Live ID3D11Device at 0x007A201C, Refcount: 2 [ STATE_CREATION WARNING #441: LIVE_DEVICE]
D3D11 WARNING:  Live ID3D11Context at 0x007A3620, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #2097226: LIVE_CONTEXT]
D3D11 WARNING:  Live ID3DDeviceContextState at 0x007ADBB0, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #3145742: LIVE_DEVICECONTEXTSTATE]
D3D11 WARNING:  Live ID3D11BlendState at 0x007B3D84, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #435: LIVE_BLENDSTATE]
D3D11 WARNING:  Live ID3D11DepthStencilState at 0x007B3ECC, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #436: LIVE_DEPTHSTENCILSTATE]
D3D11 WARNING:  Live ID3D11RasterizerState at 0x007B403C, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #437: LIVE_RASTERIZERSTATE]
D3D11 WARNING:  Live ID3D11Sampler at 0x007B428C, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #434: LIVE_SAMPLER]
D3D11 WARNING:  Live ID3D11Query at 0x007B440C, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #438: LIVE_QUERY]
D3D11 WARNING:  Live IDXGISwapChain at 0x007B45B8, Refcount: 0 [ STATE_CREATION WARNING #442: LIVE_SWAPCHAIN]
D3D11 WARNING:  Live ID3D11Texture2D at 0x007B4B1C, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #425: LIVE_TEXTURE2D]
D3D11 WARNING:  Live ID3D11RenderTargetView at 0x007B4EBC, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #428: LIVE_RENDERTARGETVIEW]
D3D11 WARNING:  Live ID3D11Texture2D at 0x007B55EC, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #425: LIVE_TEXTURE2D]

我还检查了析构函数中的release()函数是否被实际调用,并且它们确实被调用了。

我肯定遗漏了一些非常明显的东西,如果有人能给我指出,我将不胜感激。

另外,我在这种情况下使用单例模式是否明智?

谢谢。

编辑:

下面是我的DirectX类,我在其中使用了Core类:

#include "DirectX.h"

DirectX::DirectX() {}
DirectX::DirectX(HWND hwnd)
{
    HRESULT hr;
    hr = Init(hwnd);
    if(FAILED(hr)) throw hr;
    hr = Load();
    if(FAILED(hr)) throw hr;
}
DirectX::~DirectX()
{
    Core::Reset();
}

HRESULT DirectX::Init(HWND hwnd)
{
    HRESULT hr;
    hr = Core::Initialize(hwnd);
    if(FAILED(hr)) return hr;

    return S_OK;
}

HRESULT DirectX::Load()
{
    return S_OK;
}

HRESULT DirectX::Update()
{
    return S_OK;
}

HRESULT DirectX::Render()
{
    try 
    {
        float backgroundcolor[4] = {1.0f, 1.0f, 0.0f, 1.0f};
        Core::getContext()->ClearRenderTargetView(Core::getRenderTargetView(), backgroundcolor);
        Core::getSwapChain()->Present(0, 0);
    }
    catch (HRESULT hr)
    {
        return hr;
    }
    return S_OK;
}

解决方案

我很高兴您自己已经找到了答案,但是我可以给您一些关于单例模式和cpp的建议吗?

对我来说,您看起来像是从C背景转到CPP。我已经为进行这种转换的团队回顾了很多代码,这对我来说很熟悉。

您在那里所做的不是单例模式(即使它具有该实例指针)。拥有指向实例的静电指针并不意味着所有方法都必须是静电。详细说明:您所做的是一个静电函数库,它操作一个结构中的数据,而这个结构恰好是它自己的实例。您可以离开类,将数据放在一个结构上,这样您就会得到几乎与您现在一样的东西。-但Singleton也是一种东西,它是一个使用自己的方法操作的对象,数据就像你从对象中预期的那样(比如家里唯一的一台不可复制的咖啡机),而不是操作静电的数据。

Joachim Pileborg关于指针的句柄也是正确的,这是危险的,因为任何人都可以在每次意外中分配另一个对象,留下泄漏的内存和其他影响,这将导致在更大的项目中很难找到错误。你只有在有一个非常非常好的理由的情况下才能这么做。

接下来,您应该明确地在构造函数上为所有成员变量使用初始值设定项列表,或者以另一种方式在构造函数中初始化它们,否则,如果有人获得一个实例并立即在您的类上调用Reset,则指针都是随机地址(而不是0)。这意味着析构函数肯定会崩溃。

作为最后一个技巧,不要使用指针,因为您会在if语句中使用布尔值。你写代码,你是作者,如果(obj==null),试着清楚地沟通你在做什么。

应用基本单例模式如下(还有其他方式可以实现更优雅的实例化或线程感知,但这是基本模式):

(请注意,我没有编译它,因为我在Linux机器ATM上工作,可能会有问题,例如,如果CreateDevice()函数中的这个->x在前面有一个&;,我没有选中这些)

祝您的项目好运!

核心.h

#include <d3d11.h>
#include <d3dx11.h>
#include <DxErr.h>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "DxErr.lib")

class Core
{
public:
    Core* instance();
    static void Reset();

    ~Core();

    HRESULT Initialize(HWND hwnd);

    ID3D11Device* getDevice();
    ID3D11DeviceContext* getContext();
    IDXGISwapChain* getSwapChain();
    ID3D11RenderTargetView* getRenderTargetView();
    ID3D11Debug* getDebug();

private:
    static Core*            instance;

    ID3D11Device*           device;
    ID3D11DeviceContext*    context;

    IDXGISwapChain*         swapChain;
    IDXGIDevice1*           ddevice;
    IDXGIAdapter1*          adapter;
    IDXGIFactory1*          factory;
    ID3D11RenderTargetView* rtv;
    ID3D11Debug*            debug;

    HRESULT CreateDevice();

    Core();
    Core(Core const&);          
    void operator=(Core const&);
};

Core.cpp

#include "Core.h"

Core* Core::instance;

Core* Core::instance()
{
    if (instance == NULL)
    {
        try
        {
            instance = new Core();
        }
        catch (HRESULT hr)
        {
            throw hr;
        }
    }
}

Core::Core() :
    device(NULL),
    context(NULL),
    swapChain(NULL),
    ddevice(NULL),
    adapter(NULL),
    factory(NULL),
    rtv(NULL),
    debug(NULL)
{
    HRESULT hr;
    hr = CreateDevice();
    if(FAILED(hr)) throw hr;
}

Core::~Core()
{
    if (device != NULL) device->Release();
    if (context != NULL) context->Release();

    if (swapChain != NULL) swapChain->Release();
    if (ddevice != NULL) ddevice->Release();
    if (adapter != NULL) adapter->Release();
    if (factory != NULL) factory->Release();
    if (rtv != NULL) rtv->Release();

    debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
}

ID3D11Device* Core::getDevice()
{
    return this->device;
}

ID3D11DeviceContext* Core::getContext()
{
    return this->context;
}


IDXGISwapChain* Core::getSwapChain()
{
    return this->swapChain;
}

ID3D11RenderTargetView* Core::getRenderTargetView()
{
    return this->rtv;
}

ID3D11Debug* Core::getDebug()
{
    return this->debug;
}

HRESULT Core::CreateDevice()
{
    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
    };
    D3D_FEATURE_LEVEL featureLevel;

    UINT flags = NULL;
#ifdef _DEBUG
    flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    HRESULT hr;

    hr = D3D11CreateDevice(
        NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        flags,
        featureLevels,
        ARRAYSIZE(featureLevels),
        D3D11_SDK_VERSION,
        &device,
        &featureLevel,
        &context);
    if(FAILED(hr)) return hr;

    hr = device->QueryInterface(__uuidof(ID3D11Debug), (void**) &debug);
    if(FAILED(hr)) return hr;
    hr = device->QueryInterface(__uuidof(IDXGIDevice1), (void**) &ddevice);
    if(FAILED(hr)) return hr;
    hr = ddevice->GetParent(__uuidof(IDXGIAdapter1), (void**) &adapter);
    if(FAILED(hr)) return hr;
    hr = adapter->GetParent(__uuidof(IDXGIFactory1), (void**) &factory);
    if(FAILED(hr)) return hr;

    return S_OK;
}

HRESULT Core::Initialize(HWND hwnd)
{
    // Create the swap chain
    RECT rc;
    GetClientRect(hwnd, &rc);
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;

    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory( &sd, sizeof( sd ) );
    sd.BufferCount = 1;
    sd.BufferDesc.Width = width;
    sd.BufferDesc.Height = height;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = hwnd;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.Windowed = TRUE;

    this->factory->CreateSwapChain(this->device, &sd, this->swapChain);

    // Create and set the render target view
    HRESULT hr;
    ID3D11Texture2D* renderingBuffer;   
    hr = this->swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**) &renderingBuffer);
    if(FAILED(hr)) 
    {
        renderingBuffer->Release();
        return hr;
    }
    hr = this->device->CreateRenderTargetView(renderingBuffer, NULL, this->rtv);
    renderingBuffer->Release();
    if(FAILED(hr)) return hr;

    // TODO: create and set the depth stencil view

    this->context->OMSetRenderTargets(1, &this->rtv, nullptr);

    return S_OK;
}

void Core::Reset()
{
    delete instance;
}

用法

#include "DirectX.h"

DirectX::DirectX() {}

DirectX::DirectX(HWND hwnd)
{
    HRESULT hr;
    hr = Init(hwnd);
    if(FAILED(hr)) throw hr;
    hr = Load();
    if(FAILED(hr)) throw hr;
}

DirectX::~DirectX()
{
    Core::instance()->Reset();
}

HRESULT DirectX::Init(HWND hwnd)
{
    HRESULT hr;
    hr = Core::instance()->Initialize(hwnd);
    if(FAILED(hr)) return hr;

    return S_OK;
}

HRESULT DirectX::Load()
{
    return S_OK;
}

HRESULT DirectX::Update()
{
    return S_OK;
}

HRESULT DirectX::Render()
{
    try 
    {
        Core* core = Core::instance();
        float backgroundcolor[4] = {1.0f, 1.0f, 0.0f, 1.0f};
        core->ClearRenderTargetView(core->getRenderTargetView(), backgroundcolor);
        core->Present(0, 0);
    }
    catch (HRESULT hr)
    {
        return hr;
    }
    return S_OK;
}

相关文章