2013-06-02 2 views
1

Хорошо, вот какой хак я придумал, но у меня проблемы с его использованием в коде реального мира. Это рабочий пример того, что я хочу сделатьЭто плохой взлом? memcpy с виртуальными классами

class VirtualParent 
{ 
public: 
    virtual void printVal() = 0; 
}; 

class Parent : public VirtualParent 
{ 
public: 
    virtual void printVal() 
    { 
     cout << "Val is: " << val << endl; 
    } 
    void SetVal(foo * v) { val = v; } 
protected: 
    foo* val; 
}; 

class Child : public Parent 
{ 
public: 
    virtual void printVal() 
    { 
     cout << "From child, Val is: "; 
     val->print(); 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    Parent * p_ptr = new Child; 
    foo * val = new foo; 
    p_ptr->SetVal(val); 
    p_ptr->printVal(); 

    for(int n = 0;n < 100;n++) 
    { 
     Parent * new_ptr = nullptr; 

     //memcpy (&new_ptr, &p_ptr, sizeof(Parent)); 
     memcpy_s(&new_ptr, sizeof(p_ptr),&p_ptr, sizeof(p_ptr)); 

     new_ptr->printVal(); 
    } 

    return 0; 
} 

Этот пример работает, если я использую тетсру или memcpy_s. Идея состоит в том, чтобы передать пользовательский производный класс функции, которая затем создаст несколько копий, но, как я не знаю во время компиляции типа производного класса, я подумал об этом. Как я уже сказал, это работает отлично, и я скопировал это на свой движок, где я хочу его использовать, и у меня возникли проблемы с памятью, появляющиеся из ниоткуда, и они, похоже, были выпущены для этого взлома. Использование memcpy_s решает некоторые из них. Это что-то «хорошо», или есть лучший способ?

Вот "реальный мир" код

_Lua::ScriptedEntity * newScript = EntityBase;//nullptr; 
//assert(HeapValidate(GetProcessHeap(),0,nullptr)); 
//memcpy(&newScript, &EntityBase, sizeof(_Lua::ScriptedEntity)); 
memcpy_s(&newScript, sizeof(EntityBase), &EntityBase, sizeof(EntityBase)); 

//assert(HeapValidate(GetProcessHeap(),0,nullptr)); 

string luaPath = transforms.next_sibling().next_sibling().first_attribute().as_string(); 

newScript->CompileFile(luaPath.c_str()); 

auto callback = [&](_Physics::Trigger* trigger,PxTriggerPair* pairs, PxU32 count) 
          { 
           newScript->SelectScriptFunction("TriggerCallback"); 
           newScript->AddParam(trigger->Id); 

           auto data = (_Physics::RayCastingStats*)pairs->otherShape->userData; 

           newScript->AddParam((PxU8)pairs->flags); 
           newScript->AddParam(data->ID); 
           newScript->AddParam((int)data->Type); 

           newScript->AddParam((int)count); 

           newScript->Go(1); 

           return; 
          }; 
((_Physics::Trigger*)EnginePTR->iPhysics->GetPhysicObject(StartingTriggerID))->InternalCallback = callback; 

и класс

//class derived from LuaScript, implements a set of common use functions for AI scripts and similar. Used in the XLL parser. 
    class ScriptedEntity : public LuaScript 
    { 
    protected: 
     static const int NumberOfFunctions = 11; 
     std::array<function<int(LuaVirtualMachine& vm)>,NumberOfFunctions> FunctionsArray; 
     int m_iMethodBase; 
    public: 
     ScriptedEntity(LuaVirtualMachine& vm) : LuaScript (vm) 
     { 
      InternalEntity = new Entity; 

      m_iMethodBase = RegisterFunction("GetEntityPos"); 
      RegisterFunction("GetPlayerPos"); 
      RegisterFunction("Move"); 
      RegisterFunction("GetEntityLife"); 
      RegisterFunction("IsPlayerVisible"); 
      RegisterFunction("SetOrientationFromLookAt"); 
      RegisterFunction("RotateAxisUp"); 
      RegisterFunction("GetEntityOrientation"); 
      RegisterFunction("Idle"); 
      RegisterFunction("TeleportBehindPlayer"); 
      RegisterFunction("ApplyGravity"); 

      FunctionsArray[0] = [this](LuaVirtualMachine& vm){ return this->GetEntityPos(vm); }; 
      FunctionsArray[1] = [this](LuaVirtualMachine& vm){ return this->GetPlayerPos(vm); }; 
      FunctionsArray[2] = [this](LuaVirtualMachine& vm){ return this->Move(vm); }; 
      FunctionsArray[3] = [this](LuaVirtualMachine& vm){ return this->GetEntityLife(vm); }; 
      FunctionsArray[4] = [this](LuaVirtualMachine& vm){ return this->IsPlayerVisible(vm); }; 
      FunctionsArray[5] = [this](LuaVirtualMachine& vm){ return this->SetOrientationFromLookAt(vm); }; 
      FunctionsArray[6] = [this](LuaVirtualMachine& vm){ return this->RotateAxisUp(vm); }; 
      FunctionsArray[7] = [this](LuaVirtualMachine& vm){ return this->GetEntityOrientation(vm); }; 
      FunctionsArray[8] = [this](LuaVirtualMachine& vm){ return this->Idle(vm); }; 
      FunctionsArray[9] = [this](LuaVirtualMachine& vm){ return this->TeleportBehindPlayer(vm); }; 
      FunctionsArray[10] = [this](LuaVirtualMachine& vm){ return this->ApplyGravity(vm); }; 

      ViewRayCount = 16; 
     } 

     virtual int ScriptCalling (LuaVirtualMachine& vm, int iFunctionNumber) 
     { 
      if(iFunctionNumber - m_iMethodBase > NumberOfFunctions) 
       return 0; 
      else 
       return FunctionsArray[iFunctionNumber - m_iMethodBase](vm); 
      // The user might want to add functions to the script, and that's done by overloading this function. That's why it's virtual 
     } 

     // Functions 
     //  Prototypes 
     int GetEntityPos(LuaVirtualMachine& vm); 
     int GetPlayerPos(LuaVirtualMachine& vm); 
     int AttackPlayer(LuaVirtualMachine& vm); 
     int Move(LuaVirtualMachine& vm); 
     int GetEntityLife(LuaVirtualMachine& vm); 
     int GetEntityRawDamage(LuaVirtualMachine& vm); 
     int IsPlayerVisible(LuaVirtualMachine& vm); 
     int SetOrientationFromLookAt(LuaVirtualMachine& vm); 
     int RotateAxisUp(LuaVirtualMachine& vm); 
     int GetEntityOrientation(LuaVirtualMachine& vm); 
     int Idle(LuaVirtualMachine& vm); 
     int TeleportBehindPlayer(LuaVirtualMachine& vm); 
     int ApplyGravity(LuaVirtualMachine& vm); 
     int ShootPlayer(LuaVirtualMachine& vm); 

     //  Defined 
     bool Update(float ElapsedTime) 
     { 
      SelectScriptFunction("Update"); 
      AddParam(ElapsedTime); 

      Go(1); 
      SelectScriptFunction("Clear"); // dummy function to clean the stack 
      Go(); 
      return InternalEntity->Alive; 
     } 

     void HandleReturns (LuaVirtualMachine& vm, const char *strFunc) 
     { 
      if(string(strFunc) == "Update") 
      { 
       // frames returns an answer of the stack 
       lua_State *state = (lua_State *) vm; 
       InternalEntity->Alive = lua_tonumber(state,-1) != 0; 
      } 
     } 

     // Vars 
     Entity * InternalEntity; 
     void * EnginePTR_voidptr; 
     int PhysicID,VisualID,PlayerID; 
     int ViewRayCount; 
    }; 

Кроме того, тетсру happends внутри:

HRESULT LoadSceneSimple(string Path, 
             int StartingModelID, 
             int StartingInstanceID, 
             int StartingEmmitterID, 
             int CameraID, 
             int StartingTriggerID, 
             int StartingMaterialID, 
             int StartingPhysicsID, 
             int ShaderID, 
             void* engPtr,function<void(_X3D::BaseEffect* effect, _X3D::MaterialValues* matt,int ObjectID,int ShaderID)> MaterialCallback, 
             string subfolder, 
             _Lua::ScriptedEntity * EntityBase, string LuaSubfolder); 
+2

Вы копируете значение указателя, а не объект. Не используйте memcpy для копирования объекта, добавьте правильный конструктор копирования. –

+1

Это может показаться сработавшим, но оно не делает то, что вы думаете (если бы оно попыталось, оно потерпело бы неудачу). – juanchopanza

ответ

7

Вы просто скопировав указатель.

Так или иначе, вы не можете использовать memcpy так, как вы пытаетесь это сделать, поскольку вам нужно знать, насколько важна связанная память (на которую указывает указатель), которая может варьироваться в зависимости от конкретного класса.

Один из способов сделать то, что вы намереваетесь, - это добавить виртуальную функцию Parent* Parent::clone(), которая затем переопределяется Child* Child::clone().

Тогда вы можете сделать что-то вроде Parent* new_parent = p_ptr->clone(), не нуждаясь в подклассе.

Предполагается, что функция clone() позаботится о распределении памяти кучи правильного/эквивалентного типа (new).

+0

Даже если вы знаете откуда, насколько велик реальный объект, копирование с memcpy по-прежнему не так. Представьте себе, например. что произойдет, если производный класс содержит указатель с подсчетом ссылок. Или указатель на другую часть того же объекта. – celtschk

+0

Спасибо! Совершенно верно. –

Смежные вопросы