Autor Wątek: Twór językowy - mapa w wektorze, szybkość rzutowania  (Przeczytany 1161 razy)

Offline tomaszwir

  • Użytkownik

# Czerwiec 14, 2012, 19:50:03
Witam!

Mam kolejne podejście to napisania czegoś co mogło by się nazywać managerem zasobów ( chodzi mi o zasoby directx'a ). Do tej pory to robiłem tak że miałem szablon klasy ( managera ) i dziedziczyłem dla tekstry, shaderów itp i miałem kilka managerów, teraz wpadłem na pomysł żeby zrobić jeden do wszystkiego a wyglądało by to tak:

class CResourceClass
{
//....
};
class CResource
{
//...
         CResourceClass* getClass()  { return reinterpret_cast<CResourceClass>( m_Resource->get() );


         std::shared_ptr<void*> m_Resource;
};

class CGlobalManager
{
//..
         vector< map < string, void* > >;
};

I teraz po co to wszystko, Klasa CResource zawiera w sobie inteligentny wskaźnik na klasę CResourceClass, teraz pytanie jak jest z szybkością rzutowania wskaźników mam tego unikać jak ognia czy jednak moge spokojnie stosować mimo to że ta operacja będzie chyba najczęstsza.
Ale po co są te dwie klasy ? Są zasoby wczytane z pliku, oraz utworzone w programie (vb, ib itp)
I żebym ze zasobów wszystkich korzystał jednakowo, rozdzielił metody tworzenia zasobu tzn w klasie która przechowuje zasób nie miał metod tworzenia go.

Klasa CGlobalManager rejestruje wszystkie zasoby, tzn przy tworzeniu zasobu ( wczytaniu tekstury itp ) trzeba wywołać metodę registerResource do której trzeba podać typ zasobu ( tekstura, shader itp) właśnie po to jest ten wektor żeby odróżnić zasoby oraz nazwę pliku i wskaźnik na klasę  CResourceClass zasobu. Jeżeli taki zasób został już wczytany to metoda registerResource zwróci adres na klasę tego zasobu.
Przy usuwaniu zasobu trzeba go wyrejestrować no i jeżeli licznik referencji shader_ptr'a jest równy 2 ( referencje posiada tylko manager oraz jeden obiekt zasobu ) to można go usunąć.

Nie wiem tylko jak będzie w przypadku gdy zwalnianie będzie się odbywać na koniec programu czy usuwając wskaźnik void* wywoła się normalnie destruktor czy będą jakieś mankamenty
CResourceClass* a = new CResourceClass();
void* ptr = (void*)a;

delete ptr;
Destruktor niby normalnie się wywołuje

Czy może za bardzo kombinuje i lepiej wrócić do kilku managerów ?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

# Czerwiec 14, 2012, 20:27:53
Tak, za bardzo kombinujesz. Nie wiem czy lepsze jest wiele managerów dla poszczególnych typów zasobów, ale na pewno można to zaprojektować jakoś prościej. Ja nieraz zrobiłem abstrakcyjną klasę bazową zasobu, która miała metody wirtualne Load, Unload, IsLoaded itp., tą klasą posługiwał się manager zasobów, a konkretne klasy tekstury, modelu, dźwięku itp. dziedziczyły z niej.

Rzutowanie wskaźników jest darmowe, bo (pomijając pokręcone przypadki wielodziedziczenia) polega tylko na poinformowaniu kompilatora, że traktuje adres jako wskaźnik na inny typ. Na poziomie asemblera już nie ma typów, po prostu ten adres jest jakoś używany.

Natomiast nie, nie można zrobić delete na wskaźniku void*. Trzeba żeby to był wskaźnik na prawidłowy typ, jakiego typu naprawdę jest wskazywany obiekt. Tylko wtedy wywoła się właściwy destruktor. Ewentualnie może to być wskaźnik na typ klasy bazowej pokazujący tak naprawdę na obiekt klasy pochodnej, o ile ta klasa bazowa deklaruje destruktor jako wirtualny.

Aha, a rzutować wskaźnika na void* nie trzeba. Zasady rzutowania wskaźników są takie, że każdy wskaźnik można tak po prostu przypisać do void* a wskaźnik KlasaPochodna* można przypisać do KlasaBazowa*. Inne kombinacje oraz przypisanie w drugą stronę (w dół hierarchii dziedziczenia albo z void* na inny wskaźnik) już wymaga rzutowania, bo może być niebezpieczne i dlatego musimy poinformować kompilator, że jesteśmy świadomi co robimy.

Offline tomaszwir

  • Użytkownik

# Czerwiec 16, 2012, 14:09:26
Dobra zdecydowałem się na wiele managerów, tylko teraz mam takie dwa problemy których nie rozumiem:
http://wklej.org/id/774275/
Tutaj jest zakomentowany kod managera działa on tak że mam klasę np. CTexture2DManager i ta klasa dziedziczy ten manager i wypełnia wirtualną metodę loadInPointer.
Na końcu działania programu wywołuję metodę release_all która zwalnia mapę i ją czyści metodą clear, tylko teraz tak skoro w destruktorze zasobu mam metodę release, i wywołuję ją na każdym nie zwolnionym zasobie
to czy nie mogę tego pominąć i wywołać tylko metodę clear na mapie ?
Trochę się tu gubię ponieważ jeżeli nie zwolnię wszystkich zasobów to program zatrzymuje się na debugowaniu w pliku xtree i wyskakuje komunikat: "Unhandled exception at 0x01405445 in FrameWork.exe: 0xC0000005: Access violation reading location 0xfeeeff23."

Nie wiem czy dobrze robię że w tym managerze w ogóle wywołuję metodę release zwalniając zasób a nie usuwając jedną referencję, bo jeżeli mam jakiś globalny obiekt który trzyma wskaźnik na zasób, to będzie się starał on zwolnić zwolniony zasób:
class CResourceClass
{
public:
           ~CResourceClass() { release(); }
}

class CResource : public CResourceClass
{
}

CResource g_Resource;

void onReleaseProgram()
{
      // Ta metoda zwolni wszystkie zasoby, a zmienna globalna g_Resource dalej będzie trzymała referencje do zasobu, i na końcu programu będzie chciała go zwolnić.
       Manager.release_all();
}

Druga sprawa to taka że w metodzie managera release() nie mogę usunąć pozycji w mapie, tak jak by nie było w niej funkcji erease, pojęcia nie mam czemu
error C2039: 'erease' : is not a member of 'std::map<_Kty,_Ty>'
        with
1>          [
1>              _Kty=std::string,
1>              _Ty=std::tr1::shared_ptr<CVertexShaderClass>
1>          ]
1>          d:\programowanie\framework\resource_manager_template.h(222) : while compiling class template member function 'void CResourceManagerTemplate<T>::release(std::tr1::shared_ptr<_Ty> *)'
1>          with
1>          [
1>              T=CVertexShaderClass,
1>              _Ty=CVertexShaderClass
1>          ]
1>          d:\programowanie\framework\vertex_shader.h(77) : see reference to class template instantiation 'CResourceManagerTemplate<T>' being compiled
1>          with
1>          [
1>              T=CVertexShaderClass
1>          ]
« Ostatnia zmiana: Czerwiec 16, 2012, 14:24:41 wysłana przez tomaszwir »

Offline radsun

  • Użytkownik
    • CaRpg

# Czerwiec 16, 2012, 20:17:20
Co do drugiego problemu to ta funkcja nazywa się "erase"...