这是一个糟糕的黑客? memcpy与虚拟课程

时间:2013-06-02 07:17:47

标签: c++ winapi c++11

好的,这是我提出的一些黑客攻击,但我在现实代码中使用它时遇到了一些问题。这是我想要做的一个工作示例

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

此外,memcpy发生在里面:

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

1 个答案:

答案 0 :(得分:7)

你只是在复制指针。

即便如此,你也无法按照你想要的方式使用memcpy,因为你需要知道相关内存的大小(指针指向的内存),这可能因具体类而异。

执行您想要的操作的一种方法是添加虚拟Parent* Parent::clone()函数,然后由Child* Child::clone()覆盖。

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

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