如果通过指针访问这个函数,为什么会导致访问冲突?

Why does this function cause an Access Violation if accessed via a pointer?

本文关键字:为什么 访问冲突 函数 指针 访问 如果      更新时间:2023-10-16

我有以下代码:

void Aurora64::Messaging::SendConsoleMessageToPlayer(int channelId , const char *msg) 
{
    CGameRules *pGameRules = new CGameRules;
    pGameRules->SendTextMessage(eTextMessageConsole, msg, eRMI_ToClientChannel, channelId);
    delete(pGameRules);
}

通过指针pGameRules访问另一个类中的函数,但是该函数在调用时导致程序崩溃。

此代码位于另一个文件的Aurora64类中。


当将以下代码放入指针的类CGameRules(在其内部执行的函数中)时,程序崩溃:

CGameRules *pGameRules = new CGameRules;
pGameRules->SendTextMessage(eTextMessageConsole, "$4test", eRMI_ToClientChannel, channelId);
delete(pGameRules);

这是在测试Aurora64类文件中的某些内容是否导致崩溃(它不是)。

然而,当放置在同一个类中时,程序可以完美地工作,没有崩溃:

SendTextMessage(eTextMessageConsole, "$4test", eRMI_ToClientChannel, channelId);

除了指针之外,代码在功能上是相同的(使用相同的输入值)。

注释掉delete调用不起作用。


调用栈为:

Aurora64.dll!IGameObject::GetEntityId() Line 301    C+Aurora64.dll!IGameObject::InvokeRMI_Primitive<CGameRules::MethodInfo_ClTextMessage,
          CGameRules::TextMessageParams>(const CGameRules::MethodInfo_ClTextMessage method, 
          const CGameRules::TextMessageParams
            & params, unsigned int where,
          IRMIListener * pListener, int userId, int channel, unsigned int dependentId)
          Line 281  C++
Aurora64.dll!IGameObject::InvokeRMI<CGameRules::MethodInfo_ClTextMessage,
          CGameRules::TextMessageParams>(const
          CGameRules::MethodInfo_ClTextMessage method, const CGameRules::TextMessageParams 
          & params, unsigned int where, int channel) 
          Line 275  C++
Aurora64.dll!CGameRules::SendTextMessage(ETextMessageType type, const char * msg, unsigned int
          to, int channelId, const char * p0, const char * p1, const char * p2, 
          const char * p3)
          Line 3075 C++
Aurora64.dll!CGameRules::OnClientConnect(int channelId, bool isReset) Line 596  C++

我不明白为什么它会崩溃…从技术上讲,代码应该可以工作,因为调用的是完全相同的函数,输入也是完全相同的。

我有GitHub上的源代码应该是必需的(它没有Aurora64类,因为它是基于GitHub的另一个项目,但源代码没有改变)。这也有可能是调试它的危机战争游戏和专用服务器包将需要,使它更难的人在这里调试。

这个问题可能是我遗漏了一些非常明显的东西。

我做错了什么?


SendTextMessage方法:

int CScriptBind_GameRules::SendTextMessage(IFunctionHandler *pH, int type, const char *msg)
{
    CGameRules *pGameRules=GetGameRules(pH);
    if (!pGameRules)
        return pH->EndFunction();
    int to=eRMI_ToAllClients;
    int channelId=-1;
    if (pH->GetParamCount()>2)
        pH->GetParam(3, to);
    if (pH->GetParamCount()>3)
    {
        if (pH->GetParamType(4)==svtPointer)
        {
            ScriptHandle playerId;
            pH->GetParam(4, playerId);
            channelId=pGameRules->GetChannelId((EntityId)playerId.n);
        }
        else if (pH->GetParamType(4)==svtNumber)
            pH->GetParam(4, channelId);
    }
    if (pH->GetParamCount()>4)
    {
        string p[4];
        for (int i=0;i<pH->GetParamCount()-4;i++)
        {
            switch(pH->GetParamType(5+i))
            {
            case svtPointer:
                {
                    ScriptHandle sh;
                    pH->GetParam(5+i, sh);
                    if (IEntity *pEntity=gEnv->pEntitySystem->GetEntity((EntityId)sh.n))
                        p[i]=pEntity->GetName();
                }
                break;
            default:
                {
                    ScriptAnyValue value;
                    pH->GetParamAny(5+i, value);
                    switch(value.GetVarType())
                    {
                    case svtNumber:
                        p[i].Format("%g", value.number);
                        break;
                    case svtString:
                        p[i]=value.str;
                        break;
                    case svtBool:
                        p[i]=value.b?"true":"false";
                        break;
                    default:
                        break;
                    }           
                }
                break;
            }
        }
        pGameRules->SendTextMessage((ETextMessageType)type, msg, to, channelId, 
            p[0].empty()?0:p[0].c_str(),
            p[1].empty()?0:p[1].c_str(),
            p[2].empty()?0:p[2].c_str(),
            p[3].empty()?0:p[3].c_str()
            );
    }
    else
        pGameRules->SendTextMessage((ETextMessageType)type, msg, to, channelId);
    return pH->EndFunction();
}

我忽略了特定项目的对象系统,正如molbdnilo所解释的:

也许你不能仅仅创建一个CGameRules实例然后开始使用它-它必须正确设置。很可能只有一个在程序中,在启动时创建,你应该使用它。

我在项目四周寻找这样一个对象,我找到了:

CGameRules *pGameRules=g_pGame->GetGameRules();