这是一个坏的黑客吗?记忆与虚拟类

Is this a bad hack? memcpy with virtual classes

本文关键字:黑客 记忆 虚拟 一个      更新时间:2023-10-16

好的,这是我想出的一些hack,但是我在实际代码中使用它有一些问题。这是我想要做的一个工作示例

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

同样,内存也发生在:

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

你只是在复制一个指针。

即使这样,你也不能像你想的那样使用memcpy,因为你需要知道相关的内存有多大(指针指向的),这可以根据具体的类而变化。

你想做的一种方法是添加一个虚拟的Parent* Parent::clone()函数,然后被Child* Child::clone()覆盖。

那么你可以做类似Parent* new_parent = p_ptr->clone()的事情,而不需要知道子类。

假定clone()函数将负责为正确/等效类型分配(new)堆内存。