2014-01-09 1 views
1

스프라이트를 유지하기 위해 LPD3DXSPRITE를 사용하여 스프라이트 클래스를 만들었습니다. 벡터에서 사용하기 전까지는 환상적입니다. 이 문제는 벡터가 복사본을 만들고 다른 스프라이트를 삭제할 때 발생합니다. 그렇게되면, 소멸자를 호출하는데,이 소멸자는 LPD3DXSPRITE 객체의 해제를 요구합니다. 이 개체가 파괴되면 복사본에서 더 이상 호출 할 수 없으며 메모리 오류가 발생합니다.C++ Direct X 스프라이트 클래스, 벡터 문제

어떻게이 문제를 해결할 수 있습니까? 원본을 가리키는 포인터가있는 솔루션을 생각하고 포인터를 가리 키지 않으면 포인터가 null이되어 소멸자가 스프라이트를 죽여야한다는 것을 나타내지 만 비트가 미친 것처럼 보입니다.

다음 코드 중 일부를 포함했습니다. 또한 나는 여전히 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

Testground.cpp

#include "TestGround.h" 


    TestGround::TestGround(LPDIRECT3DDEVICE9 _device) 
    { 

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

질문을 편집하고 문제와 관련없는 모든 코드를 제거하십시오. 이것은 코드 리뷰를위한 장소가 아닙니다 :) – MichaelHouse

+0

실제 코드가 없으므로 지난 번에 소리를 지르므로 여기에 적절한 절차가 무엇인지 확실하지 않습니다. 나는 단지 올바른 절차가 무엇인지는 옳지 않다. –

+0

문제를 재현하는 데 필요한 최소한의 코드 만 있으면됩니다. 코드가 컴파일되기 때문에 인큐베이터 등이 올바른지 알 수 있다고 생각할 수 있습니다. – MichaelHouse

답변

2

업데이트 약간의 : 내 원래의 대답은 C++ 언어 재료 및 복사의 관점에서했다. 이제 기본 객체가 COM 객체라는 것을 알 수 있으므로 더 많은 방법으로 해결할 수 있습니다.

문제는 Sprite 클래스가 COM 개체 인 Direct3D 스프라이트에 대한 원시 포인터를 보유한다는 것입니다. Sprite의 인스턴스가 복사되면 동일한 COM 객체에 대한 포인터가있는 두 개의 객체가 있습니다. Sprite 중 하나가 파괴되면 COM 객체가 파괴되고 나머지 Sprite는 매달린 포인터로 남아있게됩니다.

이 복사는 벡터가 커질 때 발생할 수 있습니다. 벡터는 공간을 할당하고 객체를 새로운 공간에 복사 (또는 이동)하며 원본 복사본을 파괴합니다. (이동은 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. 복사 생성자와 할당 연산자를 = delete으로 선언하거나 비공개로 선언하고 구현하지 말고 Sprite를 복사 할 수 없게 만듭니다. 그런 다음 벡터에 Sprites에 대한 스마트 포인터 (예 : std::vector<std::shared_ptr<Sprite>>)를 저장합니다.

옵션 3. Sprite 복사 생성자와 복사 할당 연산자를 원본 복사와 동일하게 설정 한 새로운 LPD3DXSPRITE을 새로 작성하십시오. 이 방법을 사용하면 직접 std :: vector에 넣을 수 있습니다.

+0

감사합니다. 나는 지금 한 두 달 동안 붙어 있었어. 나는 집에 돌아 가면 이것을 구현할 것이다. –