Объявления

Друзья, если не получается зарегистрироваться, напишите на почту vdv_forever@bk.ru.
Я оторву свою задницу от всех дел и обязательно Вас активирую! :smile10:
Добро пожаловать на геройский форум! :smile25:

Энциклопедия алгоритмов HoMM 3

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5229
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2030 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение AlexSpl » 14 авг 2021, 01:12

Это Герои 2 с сигнатурами. Просто пример того, что получится на выходе, если, например, когда-нибудь появится декомпилятор SuperH4, подхватывающий сигнатуры.
Вернуться к началу

offlinevoid_17  
имя: DM
Мастер
Мастер
 
Сообщения: 416
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 69 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение void_17 » 14 авг 2021, 06:57

Ааа! Герои 2.

Кстати жалко, что бараторч не сделал HD-Mod для двойки.
Вернуться к началу

offlinevoid_17  
имя: DM
Мастер
Мастер
 
Сообщения: 416
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 69 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение void_17 » 28 ноя 2021, 11:45

Восстановленный хедер array.h
https://twitter.com/DiskBlitz/status/92 ... 69/photo/1
и шаблон CAutoArray<...> оттуда.
По крайней мере в Dreamcast-базе использовались следующие экземпляры шаблона:
CAutoArray<int>
CAutoArray<CDPlayConnection>
CAutoArray<CDPlayGroup>
CAutoArray<CDPlayPlayer>
CAutoArray<CDPlaySession>
CAutoArray<CDPlayAddressElement>

Шаблон класса представляет из себя автоматический массив указателей на какие-либо данные.
Код: Выделить всё
//  Code restoration by void_17
//  vk.com/dm0ld

typedef unsigned long DWORD

#define   DEFAULT_ARRAY_STEP         25

// --------------------------------------------------------------------------------
// This array stores pointers to your actual data. It automatically grows
// as items are placed into it...
// Этот массив хранит указатели ваших данных,
// он автоматически возрастает по мере заполнения...
// --------------------------------------------------------------------------------
template <class TClass>
class CAutoArray
{
public:

   inline CAutoArray ()
   {
      step      = DEFAULT_ARRAY_STEP;
      size      = 0;
      allocSize   = 0;
      pArray   = NULL;
   }

   virtual ~CAutoArray ()
   {
      Destroy ();
   }

   void Destroy (bool deleteData=true)
   {
      if ( deleteData )
      {
         for (DWORD i=0;i<size;i++)
         {
            TClass *pElement = Get (i);
            delete pElement;
         }
      }
      if ( pArray )
         delete [] pArray;

      pArray   = NULL;
      allocSize   = 0;
      size      = 0;
   }

   inline void SetStep (DWORD   newStep)
   {
      step   = newStep;
   }

   bool Allocate (DWORD newSize)
   {
      allocSize   = newSize;
      DWORD      *pTemp = new DWORD[allocSize];
      if ( pArray )
      {
         memcpy (pTemp, pArray, sizeof(DWORD) * size);
         delete [] pArray;
      }
      pArray   = pTemp;
      return true;
   }

   virtual bool Add (TClass   *element)
   {
      if ( allocSize<=size )
      {
         Allocate (allocSize+step);
      }
      size++;
      return Put (size-1, element);
   }

   virtual TClass *Get (DWORD   elementNbr)
   {
      if ( elementNbr>=size )
      {
         return NULL;
      }
      return (TClass*)pArray[elementNbr];
   }

   virtual bool Put (DWORD   elementNbr, TClass *element)
   {
      if ( elementNbr >= size )
         return false;

      pArray[elementNbr]   = (DWORD)element;

      return true;
   }

   virtual bool Delete (DWORD   elementNbr)
   {
      if ( elementNbr >= size )
         return false;

      for (DWORD index=elementNbr;index<size-1;index++)
      {
         pArray[index]   = pArray[index+1];
      }
      size--;

      return true;
   }

   virtual bool Insert (DWORD nextElementNbr, TClass *element)
   {
      if ( nextElementNbr >= size )
         return false;

      TClass   *save = Get (size-1);

       for (DWORD index=size-1; index>nextElementNbr; index--)
       {
          pArray[index]   = pArray[index-1];
       }

       Put (nextElementNbr, element);
       Add ( save );

      return true;
   }

   virtual DWORD GetCount()         { return size; }


   inline TClass * operator[] (DWORD index)
   {
      return Get (index);
   }


protected:
   DWORD      step; //     +4
   DWORD      *pArray; //  +8
   DWORD      allocSize; //+12
   DWORD      size; //     +16
};

Последний раз редактировалось void_17 28 ноя 2021, 17:42, всего редактировалось 1 раз.
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 233 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение RoseKavalier » 28 ноя 2021, 14:38

There is an issue here with your virtual destructor, or more precisely with the Destroy() function.
A virtual destructor does a few extra things so that the user need not to, among others is pass a flag value which can take 2 meanings: delete the class itself if it was allocated, delete the class which was allocated as an array.
See here for more, I will quote the relevant part :
Цитата:
6) Deleting Destructors
When class has a virtual destructor, compiler generates a helper function - deleting destructor. Its purpose is to make sure that a proper _operator delete_ gets called when destructing a class. Pseudo-code for a deleting destructor looks like following:

virtual void * A::'scalar deleting destructor'(uint flags)
{
this->~A();
if (flags&1) A::operator delete(this);
};


The address of this function is placed into the vftable instead of the destructor's address. This way, if another class overrides the virtual destructor, _operator delete_ of that class will be called. Though in real code _operator delete_ gets overriden quite rarely, so usually you see a call to the default delete(). Sometimes compiler can also generate a vector deleting destructor. Its code looks like this:

virtual void * A::'vector deleting destructor'(uint flags)
{
if (flags&2) //destructing a vector
{
array = ((int*)this)-1; //array size is stored just before the this pointer
count = array[0];
'eh vector destructor iterator'(this,sizeof(A),count,A::~A);
if (flags&1) A::operator delete(array);
}
else {
this->~A();
if (flags&1) A::operator delete(this);
}
};



Therefore, you should not write the delete operation yourself in the destructor because the compiler does it itself - you would be invoking double delete operation and be looking for trouble.

pArray should be TClass**, not DWORD*.

Allocate is called Add in the symbols, there is no virtual function for allocation only.
Вернуться к началу

offlinevoid_17  
имя: DM
Мастер
Мастер
 
Сообщения: 416
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 69 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение void_17 » 28 ноя 2021, 15:16

I reconstructed this according to an old C++ standard via Ghidra dreamcast decompiler. Of course the language changed.
Последний раз редактировалось void_17 28 ноя 2021, 15:22, всего редактировалось 1 раз.
Вернуться к началу

offlinevoid_17  
имя: DM
Мастер
Мастер
 
Сообщения: 416
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 69 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение void_17 » 28 ноя 2021, 15:20

Цитата:
Therefore, you should not write the delete operation yourself in the destructor

I just rewrote it the way NWC have probably done it.

Btw, pArray should be DWORD*, since it stores a pointer(32 bit) to it, not the copy of the data itself.

pArray is just DWORD pArray[];
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 233 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение RoseKavalier » 28 ноя 2021, 15:25

This has nothing to do with the age of the language, it's a core part of new[] and delete[].
You can check the date of the original article which is 2006.

TClass** is a 32 bit pointer itself, and so would TClass* be, at least in x86 :smile5:

Anyhow, that's my $0.02, you're free to do as you wish but this is not how C++ is written, and definitely not by NWC.
Вернуться к началу

offlinevoid_17  
имя: DM
Мастер
Мастер
 
Сообщения: 416
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 69 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение void_17 » 28 ноя 2021, 16:00

Alright, I will remove Destroy function but I feel like it will cause a memory leak sometimes


Код: Выделить всё
#include <iostream>

typedef unsigned long DWORD;

#define   DEFAULT_ARRAY_STEP         25

// --------------------------------------------------------------------------------
// This array stores pointers to your actual data. It automatically grows
// as items are placed into it...
// Этот массив хранит указатели ваших данных,
// он автоматически возрастает по мере заполнения...
// --------------------------------------------------------------------------------
template <class TClass>
class CAutoArray
{
public:

   CAutoArray ()
   {
      step      = DEFAULT_ARRAY_STEP;   
      size      = 0;
      allocSize   = 0;
      pArray      = NULL;
   }

   virtual ~CAutoArray ()
   {
      //Destroy ();
   }

   /*void Destroy (bool deleteData=true)
   {
      if ( deleteData )
      {
         for (DWORD i=0;i<size;i++)
         {
            TClass *pElement = Get (i);
            delete pElement;
         }
      }
      if ( pArray )
         delete [] pArray;

      pArray       = NULL;
      allocSize   = 0;
      size           = 0;
   }
*/

   void SetStep (DWORD   newStep)
   {
      step   = newStep;
   }

   virtual bool Allocate (DWORD newSize)
   {
      allocSize   = newSize;
      DWORD      *pTemp = new DWORD[allocSize];
      if ( pArray )
      {
         memcpy (pTemp, pArray, sizeof(DWORD) * size);
         delete [] pArray;
      }
      pArray   = pTemp;
      return true;
   }

   virtual bool Add (TClass   *element)
   {
      if ( allocSize<=size )
      {
         Allocate (allocSize+step);
      }
      size++;
      return Put (size-1, element);
   }

   virtual TClass *Get (DWORD   elementNbr)
   {
      if ( elementNbr>=size )
      {
         return NULL;
      }
      return (TClass*)pArray[elementNbr];
   }

   virtual bool Put (DWORD   elementNbr, TClass *element)
   {
      if ( elementNbr >= size )
         return false;

      pArray[elementNbr]   = (DWORD)element;

      return true;
   }

   virtual bool Delete (DWORD   elementNbr)
   {
      if ( elementNbr >= size )
         return false;

      for (DWORD index=elementNbr;index<size-1;index++)
      {
         pArray[index]   = pArray[index+1];
      }
      size--;

      return true;
   }

   virtual bool Insert (DWORD nextElementNbr, TClass *element)
   {
      if ( nextElementNbr >= size )
         return false;

      TClass   *save = Get (size-1);

       for (DWORD index=size-1; index>nextElementNbr; index--)
       {
          pArray[index]   = pArray[index-1];
       }

       Put (nextElementNbr, element);
       Add ( save );

      return true;
   }

   virtual DWORD GetCount()         { return size; }


   TClass *      operator[] (DWORD index)
   {
      return Get (index);
   }


protected:
   //void* VMT   //0
   //DO NOT DEFINE THIS FIELD, IT WILL BE DEFINED AUTOMATICALLY SINCE THIS CLASS USES VIRTUAL METHODS
   //НЕ ОЪЯВЛЯЙТЕ ВРУЧНУЮ ЭТО ПОЛЕ, ОНО ОБЪЯВИТСЯ АВТОМАТИЧЕСКИ КОМПИЛЯТОРОМ

   DWORD      step; //     +4
   DWORD      *pArray; //  +8
   DWORD      allocSize; //+12
   DWORD      size; //     +16
};


class message {
    public:
    const char* text;
    int number;
    message(const char* msg, int num) {
        this->text       =     msg;
        this->number =  num;
    }
};

int main(int argc, char *argv[])
{
   message Msg("Hello World", 123);
   CAutoArray<message> Array;
   Array.Add(&Msg);
   std::cout << Msg.text << std::endl;
   std::cout << Array.Get(0)->text << std::endl;
   
   std::cout << Msg.number<< std::endl;
   std::cout << Array.Get(0)->number;
}


check this.
It works fine. Almost the same way as the original dreamcast (THEY HAD DESTROY FUNCTION!) and SoD game. You can check this in Dreamcast database if you do not believe me.

Изображение
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 233 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение RoseKavalier » 28 ноя 2021, 17:04

I did not say there was no Destroy() method, I said there was no virtual Allocate() method in the original, only 7 virtual methods but you have 8.
You do need to clear data in the destructor, but you should not be forcing the delete flag in general if you want non-allocated data as in your example: you passed a pointer to a non-allocated message.
If you had done:
Код: Выделить всё
Array.Add(new message("Hello World", 123));

then you need the delete flag. In your case, forcing the delete flag would attempt to free non-allocated data and possibly crash.
Вернуться к началу

offlinevoid_17  
имя: DM
Мастер
Мастер
 
Сообщения: 416
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 69 раз.

Re: Энциклопедия алгоритмов HoMM 3

Сообщение void_17 » 28 ноя 2021, 17:23

It works fine now.

Btw, Allocate() method were inlined in RoE. You can verify this in Ghidra.

Check this now! No problems at all. (It was just a bad example, but trust me, it works the same as in the original game)

Код: Выделить всё
#include <iostream>

typedef unsigned long DWORD;

#define   DEFAULT_ARRAY_STEP         25

// --------------------------------------------------------------------------------
// This array stores pointers to your actual data. It automatically grows
// as items are placed into it...
// Этот массив хранит указатели ваших данных,
// он автоматически возрастает по мере заполнения...
// --------------------------------------------------------------------------------
template <class TClass>
class CAutoArray
{
public:

   CAutoArray ()
   {
      step      = DEFAULT_ARRAY_STEP;   
      size      = 0;
      allocSize   = 0;
      pArray      = NULL;
   }

   virtual ~CAutoArray ()
   {
      Destroy ();
   }

   void Destroy (bool deleteData=true)
   {
      if ( deleteData )
      {
         for (DWORD i=0;i<size;i++)
         {
            TClass *pElement = Get (i);
            delete pElement;
         }
      }
      if ( pArray )
         delete [] pArray;

      pArray       = NULL;
      allocSize   = 0;
      size           = 0;
   }


   void SetStep (DWORD   newStep)
   {
      step   = newStep;
   }

   virtual bool Allocate (DWORD newSize)
   {
      allocSize   = newSize;
      DWORD      *pTemp = new DWORD[allocSize];
      if ( pArray )
      {
         memcpy (pTemp, pArray, sizeof(DWORD) * size);
         delete [] pArray;
      }
      pArray   = pTemp;
      return true;
   }

   virtual bool Add (TClass   *element)
   {
      if ( allocSize<=size )
      {
         Allocate (allocSize+step);
      }
      size++;
      return Put (size-1, element);
   }

   virtual TClass *Get (DWORD   elementNbr)
   {
      if ( elementNbr>=size )
      {
         return NULL;
      }
      return (TClass*)pArray[elementNbr];
   }

   virtual bool Put (DWORD   elementNbr, TClass *element)
   {
      if ( elementNbr >= size )
         return false;

      pArray[elementNbr]   = (DWORD)element;

      return true;
   }

   virtual bool Delete (DWORD   elementNbr)
   {
      if ( elementNbr >= size )
         return false;

      for (DWORD index=elementNbr;index<size-1;index++)
      {
         pArray[index]   = pArray[index+1];
      }
      size--;

      return true;
   }

   virtual bool Insert (DWORD nextElementNbr, TClass *element)
   {
      if ( nextElementNbr >= size )
         return false;

      TClass   *save = Get (size-1);

       for (DWORD index=size-1; index>nextElementNbr; index--)
       {
          pArray[index]   = pArray[index-1];
       }

       Put (nextElementNbr, element);
       Add ( save );

      return true;
   }

   virtual DWORD GetCount()         { return size; }


   TClass *      operator[] (DWORD index)
   {
      return Get (index);
   }


protected:
   //void* VMT   //0
   //DO NOT DEFINE THIS FIELD, IT WILL BE DEFINED AUTOMATICALLY SINCE THIS CLASS USES VIRTUAL METHODS
   //НЕ ОЪЯВЛЯЙТЕ ВРУЧНУЮ ЭТО ПОЛЕ, ОНО ОБЪЯВИТСЯ АВТОМАТИЧЕСКИ КОМПИЛЯТОРОМ

   DWORD      step; //     +4
   DWORD      *pArray; //  +8
   DWORD      allocSize; //+12
   DWORD      size; //     +16
};


class message {
    public:
    const char* text;
    int number;
    message(const char* msg, int num) {
        this->text       =     msg;
        this->number =  num;
    }
};

int main(int argc, char *argv[])
{
   message *Msg = new message("Hello World", 123);
   CAutoArray<message> Array;
   Array.Add(Msg);
   std::cout << Msg->text << std::endl;
   std::cout << Array.Get(0)->text << std::endl;
   
   std::cout << Msg->number<< std::endl;
   std::cout << Array.Get(0)->number;
}
Вернуться к началу

Пред.След.

Вернуться в Общий раздел

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

cron