C++ Direct X Sprite 类, vector 问题

标签 c++ directx sprite vector

所以我使用 LPD3DXSPRITE 创建了一个 sprite 类来保存一个 sprite。它工作得很好,直到我在 vector 中使用它。当 vector 创建一个拷贝并销毁另一个 Sprite 时,就会出现问题。当它这样做时,它调用析构函数,该析构函数要求释放 LPD3DXSPRITE 对象。当这个对象被销毁时,拷贝不能再调用它,我得到一个内存错误。

我该如何解决这个问题?我在考虑一个解决方案,涉及让拷贝指向原件,然后如果没有任何东西可指向,指针将变为空,这表明析构函数应该杀死 Sprite ,但这似乎有点疯狂。

我在下面包含了一些代码。另请注意,我仍在学习 C++(我的职业是 C# 程序员),所以如果您发现任何疯狂的事情,请告诉我,不要对我发火。

Sprite .h

#ifndef SPRITE_H
#define SPRITE_H

#include <d3dx9.h>

// 
class Sprite
    {
    private:
        LPD3DXSPRITE sprite;

Sprite .cpp

#include "sprite.h"

// Copy constructor
Sprite::Sprite(Sprite &_copy)
{
    center = _copy.center;
    color = _copy.color;
    matrix = _copy.matrix;
    position = _copy.position;
    rotation = _copy.rotation;
    scale = _copy.scale;
    sourceRect = _copy.sourceRect;
    sprite = _copy.sprite;
    texture = _copy.texture;
}

// Full constructor which fully initializes the sprite.
Sprite::Sprite(LPDIRECT3DDEVICE9 _device, LPDIRECT3DTEXTURE9 _texture)
{
    Initialize(_device,_texture);
}

Sprite::~Sprite()
{
    sprite->Release();
}

// Initializes values and creates the sprite
void Sprite::Initialize(LPDIRECT3DDEVICE9 _device, LPDIRECT3DTEXTURE9 _texture)
{
    Initialize();

    // Set our variables
    texture = _texture;

    // If we don't succeed throw an error so we know things
    // got ****ed up somehow
    if (!SUCCEEDED(D3DXCreateSprite(_device, &sprite)))
    {
        throw("Sprite creation failed");
    }
    SetCenter();
    SetSourceRect();
}

// Sets initial values for the sprite
void Sprite::Initialize()
{
    // Sets variable to default  
}

这里是我调用它的地方。

Testground.h

#ifndef TESTGROUND_H
#define TESTGROUND_H
#include "Console.h"
#include "Log.h"
#include "sprite.h"
#include <string>
#include "Animation.h"
#include <map>
#include <vector>

class TestGround
{
private:
    std::vector<Sprite> sprites;

还有一些 Testground.cpp

测试场.cpp

#include "TestGround.h"


    TestGround::TestGround(LPDIRECT3DDEVICE9 _device)
    {

        sprites.emplace_back(_device, tBank["TestTexture"]);

最佳答案

更新:我最初的回答是关于 C++ 语言的内容和复制。现在我看到底层对象是一个 COM 对象,所以有更多的方法来解决它。

问题是您的 Sprite 类包含指向 Direct3D Sprite 的原始指针,它是一个 COM 对象。如果复制 Sprite 的实例,则现在有两个对象具有指向同一 COM 对象的指针。如果其中一个 Sprite 被销毁,它会销毁 COM 对象,剩下的 Sprite 会留下悬空指针。

当 vector 需要增长时,就会发生这种复制。 vector 分配空间并将对象复制(或移动)到新空间,然后销毁原始拷贝。 (移动是 C++11 的一个特性,你也需要做一些工作来支持它。)

COM 对象是引用计数的,因此在最后一次发布之前不应销毁它们。但是引用计数的负担落在了你身上。复制Sprite时,需要增加对应D3DXSprite对象中的引用计数。

选项 1:您可以通过实现 Sprite 复制构造函数并让它在指针上调用 AddRef 来直接执行此操作。

Sprite::Sprite(const Sprite &_copy) :
  center(_copy.center),
  color(_copy.color),
  // blah blah blah
  sprite(_copy.sprite)
{
  sprite->AddRef();
}

选项 2:使用智能指针来管理引用计数。我找到了 ATL::CComPtr来自 <atlbase.h>为此工作得很好。

#include <atlbase.h>

class Sprite {
   // blah blah blah
   private:
     ATL::CComPtr<ID3DXSprite> sprite;
};

现在您甚至不必实现复制构造函数。编译器会通过复制每个成员来为你做这件事。复制 CComPtr 时,它会为您增加引用计数。当您的 Sprite 被销毁时,CComPtr 将减少引用计数(因此您不再需要您的 ~Sprite 析构函数——或者,如果您这样做,它不再应该调用 sprite->Release())。

下面是我原来的答案,这些也是有效的选项。

选项 1。如果您使用的是 C++11,请为 Sprite 实现移动构造函数和移动赋值运算符,然后像您现在所做的那样将 Sprite 直接放入 std::vector 中。

选项 2. 使您的 Sprite 不可复制(通过使用 = delete 声明复制构造函数和赋值运算符或通过将它们声明为私有(private)而不实现它们)。然后让你的 vector 持有指向你的 Sprites 的智能指针(例如 std::vector<std::shared_ptr<Sprite>> )。

选项 3. 让您的 Sprite 复制构造函数和复制赋值运算符执行深复制——即创建一个新的 LPD3DXSPRITE其设置方式与源对象中的设置方式相同。使用这种方法,您可以将它们直接放入 std::vector。

关于C++ Direct X Sprite 类, vector 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21011111/

相关文章:

css - SVG 图像 Sprite 在 IE9 和 10 中不起作用

css Sprite 作为背景,有限的部分?

c++ - Qt 运行 C++ 和 C 代码

c++ - glTexCoordPointer 输出不符合预期

c++ - 在子类中重写时如何调用私有(private)虚拟基类实现

c++ - 函数传递后 DirectX::XMMATRIX 乘法不正确 (C++)

c++ - 访问转换纹理的像素数据

c++ - 为什么隐式和显式删除的 move 构造函数会受到不同对待?

c++ - 在 D3D12 上获取显示器的刷新率

python - 如何使用 pygame.USEREVENT 让敌人定期开火