1

Ok, here's some hack I came up with, but I'm having some problems using it in real world code. This is a working example of what I want to do

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;
}

This example works if I use memcpy, or memcpy_s. The idea is to pass a user derived class to a function, that then will create several copies, but as I don't know at compile time the derived class type, I thought of that. As I said, that works perfectly, and i copied that to my engine, where i want to use it, and I'm having some memory issues appearing from nowhere, and they seem to be releated to that hack. Using memcpy_s solves some of them. Is this something "good" to do, or there's a better way?

Here's the "real world" code

_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;

and the class

//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;
    };

Also, the memcpy happends inside:

 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);
Santiago Pacheco
  • 197
  • 1
  • 13

1 Answers1

7

You are just copying a pointer.

Even so, you cant use memcpy the way you are trying to, since you need to know how big the associated memory is (that the pointer is pointing to), which can vary based on the concrete class.

One way to do what you intend is to add a virtual Parent* Parent::clone() function which then gets overriden by Child* Child::clone().

Then you can do something like Parent* new_parent = p_ptr->clone() without needing to know the subclass.

It is assumed that the clone() function would take care of allocating (new) the heap memory for the correct/equivalent type.

Preet Kukreti
  • 8,417
  • 28
  • 36
  • Even if you know from somewhere how big the actual object is, copying with memcpy is still wrong. Imagine e.g. what happens if the derived class contains a reference-counted pointer. Or a pointer to another part of the same object. – celtschk Jun 02 '13 at 13:16