2010-11-16 2 views
1

Мне нужно изменить проект с открытым исходным кодом, чтобы предотвратить повторное использование кода (более эффективно только для создания функции GetGameRulesPtr(), чем для того, чтобы продолжать работать с этим движком. Проблема в том, что он хранится как void ** g_pGameRules. Я никогда не понимал концепцию указателя на указатель, и я немного смущен.Как сделать функцию геттера для двойного указателя?

Я создаю функцию GetGameRules() для извлечения этого указателя, но я не уверен, что моя функция getter должна быть недействительной * ret введите, а затем верните * g_pGameRules или как именно я должен идти по этому вопросу.Я фактически чистил на использование моего указателя сейчас, но хотел узнать правильный метод для изучения.

Вот код, строки 58- 89 - это функция SDK, которая возвращает g_pGame Указатель правил из игрового движка. Другие функции - это то, к чему я добавляю функцию getter.

// extension.cpp 

class SDKTools_API : public ISDKTools 
{ 
public: 
    virtual const char *GetInterfaceName() 
    { 
     return SMINTERFACE_SDKTOOLS_NAME; 
    } 

    virtual unsigned int GetInterfaceVersion() 
    { 
     return SMINTERFACE_SDKTOOLS_VERSION; 
    } 

    virtual IServer *GetIServer() 
    { 
     return iserver; 
    } 

    virtual void *GetGameRules() 
    { 
     return *g_pGameRules; 
    } 
} g_SDKTools_API; 

// extension.h 

namespace SourceMod 
{ 
    /** 
    * @brief SDKTools API. 
    */ 
    class ISDKTools : public SMInterface 
    { 
    public: 
     virtual const char *GetInterfaceName() = 0; 
     virtual unsigned int GetInterfaceVersion() = 0; 
    public: 
     /** 
     * @brief Returns a pointer to IServer if one was found. 
     * 
     * @return   IServer pointer, or NULL if SDKTools was unable to find one. 
     */ 
     virtual IServer* GetIServer() = 0; 

     /** 
     * @brief Returns a pointer to GameRules if one was found. 
     * 
     * @return   GameRules pointer, or NULL if SDKTools was unable to find one. 
     */ 
     virtual void* GetGameRules() = 0; 
    }; 
} 

// vglobals.cpp 

void **g_pGameRules = NULL; 
void *g_EntList = NULL; 


void InitializeValveGlobals() 
{ 
    g_EntList = gamehelpers->GetGlobalEntityList(); 

    char *addr; 

#ifdef PLATFORM_WINDOWS 
    /* g_pGameRules */ 
    if (!g_pGameConf->GetMemSig("CreateGameRulesObject", (void **)&addr) || !addr) 
    { 
     return; 
    } 

    int offset; 
    if (!g_pGameConf->GetOffset("g_pGameRules", &offset) || !offset) 
    { 
     return; 
    } 
    g_pGameRules = *reinterpret_cast<void ***>(addr + offset); 
#elif defined PLATFORM_LINUX || defined PLATFORM_APPLE 
    /* g_pGameRules */ 
    if (!g_pGameConf->GetMemSig("g_pGameRules", (void **)&addr) || !addr) 
    { 
     return; 
    } 
    g_pGameRules = reinterpret_cast<void **>(addr); 
#endif 
} 
+1

Почему бы не включить код как часть вопроса, чтобы когда-либо все, что исчезло в палитре дня, код сохраняется как запись для кого-то другого, который находит этот вопрос? – Flexo

+0

Простите, я подумал, что выбрал вариант, чтобы ampaste никогда не удалял мой пост, но похоже, что я нажал на месяц. –

ответ

1

Вы хотите вернуть void* и сделать отливку обратно соответствующему SomeType** в коде реализации. Это связано с тем, что void** имеет странную семантику (которую я не могу найти в Google прямо сейчас). Он также сообщает пользователю больше информации, чем они действительно нужны. Весь смысл использования void* для начала состоял в том, чтобы избежать предоставления пользователю информации, которая им не нужна.

Если это вариант, я лично рекомендовал бы вообще избегать void* и просто предоставить непрозрачный ссылочный тип для вызова ваших API. Один из способов сделать это - определить фальшивую структуру, например struct GameObjectRef {};, и передать пользователю обратно GameObjectRef*, созданный из любого указателя, который использует ваша система. Это позволяет пользователю писать строго типизированный код, поэтому они не могут случайно указать неправильный тип указателя на ваши функции, поскольку они могут с void*.

Как указатели (и указателей-на-указателей) работают:

Представьте, что вы меня спрашиваете, где живет твоя тетя. Затем я вручу вам лист бумаги с адресом, на который нужно пойти. Этот лист бумаги является указателем на дом.

Теперь возьмите этот лист бумаги с адресом, сфотографируйте его с помощью цифровой камеры и поместите изображение на свой персональный сайт вики.

Теперь, если ваша сестра звонит, прося адрес вашей тети, просто скажите ей, чтобы она посмотрела на вашу вики. Если она попросит URL, напишите его на листе бумаги для нее. Этот второй лист бумаги является указателем на указатель на дом.

Вы можете видеть, как адрес не совпадает с реальным. Просто потому, что у кого-то есть адрес вашего сайта, это не значит, что он знает адрес вашей тети. И только потому, что у них есть адрес вашей тети, это не значит, что они стучат в ее дверь. То же самое верно для указателей на объекты.

Вы также можете увидеть, как вы можете копировать адреса (указатели), но это не делает копию базового объекта. Когда вы фотографируете адрес вашей тети, ваша тетя не получит новый блестящий дом.

И вы можете видеть, как разыменование указателя приведет вас к исходному объекту. Если вы заходите на сайт вики, вы получаете адрес своей тети. Если вы едете по этому адресу, вы можете оставить пакет на своем пороге.

Обратите внимание, что это не идеальные метафоры, но они достаточно близки, чтобы быть несколько описательными. Реальные указатели на указатели намного чище, чем эти примеры. Они описывают только две вещи: тип конечного объекта (скажем, GameObject) и количество уровней косвенности (скажем, GameObject** - два уровня).

0

Я думаю, что его не двойной указатель, но указатель на указатель, да и если вы хотите, чтобы получить недействительным * вы должны вернуть * g_pGameRules.

Думаю, что указатели похожи на уровни. Вы должны показать, какой уровень вы хотите получить.

+0

Это имеет большой смысл, спасибо. Вопрос в том, что если я сделаю rettype void * и вернусь * g_pGameRules, будет ли что-то другое, чем ** g_pGameRules? –

+0

Да, это так. Он будет возвращать указатель на g_pGameRules. Но адрес хранится в void ** g_pGameRules. Как «указатель-> указатель-> значение». Вы можете увидеть это некоторое время, когда работаете с классами, которые выделяют свои компоненты в кучу. Пример "SomeClassInst-> AnotherCLassInst-> ValueYouWantToChange" – DmitryM

0

Указатель на указатель полезен, если вы хотите изменить указатель (например, на большой блок памяти, если вы закончите работу), но сохраните общую ссылку на элемент, где бы он ни находился.

Если вы не собираетесь перераспределять или перемещать блок, на который указывает, то dereferencinig, как и у вас, в вашем получателе. Я не смотрел библиотеку, которую вы используете, но нужно учитывать, что она может иметь счет ссылки, когда вы получаете экземпляр, чтобы гарантировать, что объект не будет изменен после получения указателя.

Итак, я бы порекомендовал, что вы посмотрите, есть ли в библиотеке какие-либо функции «Factory» или «instance», создающие функции и использующие их.

-Dan8080

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