Привести указатель на векторный тип в обратном вызове - PullRequest
0 голосов
/ 11 ноября 2018

Программист выходного дня, новичок в C ++, сражающийся с войной указателей!

Я пытаюсь закодировать в C ++ метод для извлечения данных из API, используя вектор, который передается через аргумент void * в функцию обратного вызова.

Возвращенные данные будут переданы обратно в lua, который является внешним интерфейсом, используемым в приложении. Часть lua - это не то, что меня озадачило, это проблема наполнения моей структуры данными обратного вызова.

У меня все это работало с использованием простых указателей int, но мне сказали, что это предпочтительный способ сделать это с помощью структуры, и мне предложили сделать следующее:

1 - define a struct that contains the 6 ints
2 - create an std::vector that can contain instances of the new struct
3 - pass a pointer to the vector as refcon into XPLMGetAllMonitorBoundsGlobal
inside the callback function:
    4 - cast the refcon pointer back to the vector type
    5 - create a new instance of the struct and fill it with the 6 ints that are passed to the callback function
    6 - push that instance into the vector
7 - when XPLMGetAllMonitorBoundsGlobal returns, the vector will be filled with the bounds of all screens
8 - convert the vector into a lua-compatible thing, probably a two-dimensional array
push that array into lua

Вот код, который я придумал, сделал ли поиск в Google / Stackoverflow так близко, но, хотя код компилируется, приложение зависает или вызывает ошибки сегмента, зависит от того, что я настроил. Я думаю, что основная проблема заключается в том, как я возвращаю указатель refcon к векторному типу, слишком много ссылок / разыменований указателей, и, вероятно, есть и другие проблемы.

struct  MonitorBoundsStructure    // #1
{
    int     MonitorIndex;
    int     LeftBx;
    int     TopBx;
    int     RightBx;
    int     BottomBx;
    int     RefCon;
};

static void LuaReceiveMonitorBoundsOS_t(int inMonitorIndex, int inLeftBx, int inTopBx, int inRightBx, int inBottomBx, void * refcon)
{
    vector<MonitorBoundsStructure*>& MonitorBounds = *reinterpret_cast<vector<MonitorBoundsStructure*> *>(refcon);  #4
    //vector<MonitorBoundsStructure> MonitorBounds = reinterpret_cast<vector<MonitorBoundsStructure*> *>(refcon);
    //vector<MonitorBoundsStructure> MonitorBounds = *reinterpret_cast<vector<MonitorBoundsStructure> *>(refcon);
    //vector<MonitorBoundsStructure> MonitorBounds = reinterpret_cast<vector<MonitorBoundsStructure> *>(refcon);
    //vector<MonitorBoundsStructure>* MonitorBounds = static_cast<vector<MonitorBoundsStructure> *>(refcon);

    MonitorBoundsStructure returnData; //{0,0,0,0,0,0};   #5
    returnData.MonitorIndex = inMonitorIndex;
    returnData.LeftBx = inLeftBx;
    returnData.TopBx = inTopBx;
    returnData.RightBx = inRightBx;
    returnData.BottomBx = inBottomBx;
    returnData.RefCon = *(int *)refcon;

    MonitorBounds.push_back(&returnData);   // #6
}

static int LuaXPLMGetAllMonitorBoundsOSTest()
{
    //std::vector<std::shared_ptr<MonitorBoundsStructure>> MonitorBounds;
    vector<MonitorBoundsStructure> MonitorBounds;  // #2

    XPLMGetAllMonitorBoundsOS(LuaReceiveMonitorBoundsOS_t, &MonitorBounds);  // #3

    int i = 0;
    for (vector<MonitorBoundsStructure>::iterator it = MonitorBounds.begin(); it != MonitorBounds.end(); ++it)
    {
        i++;
        logMsg(logToAll, string("MonitorBounds ").append(to_string(i)));

    }

    return 1;
}

Если я закомментирую MonitorBounds.push_back (& ​​returnData), код, по крайней мере, попадет туда, где структура внутри обратного вызова заполнена правильными данными, я ударю стену, возвращая эту структуру обратно в вызывающую функцию, что означает мой приведение пустоты * к вектору по меньшей мере неверно.

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

Я близок к решению или далеко?

Решение: Спасибо Теду Лингмо за предоставленное решение, даже за то, что он даже написал тестовый код на своей собственной системе. Моя проблема, как я подозревал, заключалась в приведении указателя на вектор. Я включил ответы как push_back, так и emplace_back (гораздо точнее).

функция обратного вызова:

static void LuaReceiveMonitorBoundsOS_e(int inMonitorIndex, int inLeftBx, int inTopBx, int inRightBx, int inBottomBx, void * refcon)
{
    auto& MonitorBounds = *reinterpret_cast<vector<MonitorBoundsStructure>*>(refcon);


    MonitorBoundsStructure returnData;
    returnData.MonitorIndex = inMonitorIndex;
    returnData.LeftBx = inLeftBx;
    returnData.TopBx = inTopBx;
    returnData.RightBx = inRightBx;
    returnData.BottomBx = inBottomBx;

    MonitorBounds.push_back(returnData);
}

и

static void LuaReceiveMonitorBoundsOS_e(int inMonitorIndex, int inLeftBx, int inTopBx, int inRightBx, int inBottomBx, void * refcon)
{
    auto& MonitorBounds = *reinterpret_cast<vector<MonitorBoundsStructure>*>(refcon);

    MonitorBounds.emplace_back(
         MonitorBoundsStructure{
             inMonitorIndex,
             inLeftBx,
             inTopBx,
             inRightBx,
             inBottomBx
         }
     );
}

функция вызова:

static int LuaXPLMGetAllMonitorBoundsOSTestE(lua_State *L)
{
    vector<MonitorBoundsStructure> MonitorBounds;

    XPLMGetAllMonitorBoundsOS(LuaReceiveMonitorBoundsOS_e, &MonitorBounds);

    for (auto& m : MonitorBounds) {
         std::cout << m.MonitorIndex << "\n";
     }

    return 1;
}

1 Ответ

0 голосов
/ 11 ноября 2018
MonitorBoundsStructure returnData; //{0,0,0,0,0,0};   #5
MonitorBounds.push_back(&returnData);   // #6

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

Похоже, что вы используете неверный тип. Если это вектор:

vector<MonitorBoundsStructure> MonitorBounds;

Вы должны использовать это в своем обратном вызове:

auto& MonitorBounds = *reinterpret_cast<vector<MonitorBoundsStructure>*>(refcon);

И толкать всю структуру, а не указатель на нее:

MonitorBounds.push_back(returnData);

Редактировать: я сделал тестовую версию со своей собственной XPLMGetAllMonitorBoundsOS, чтобы проверить, что она работает и выглядит нормально.

#include <iostream>
#include <string>
#include <vector>

typedef void (*XPLMReceiveMonitorBoundsOS_f)( int   inMonitorIndex,
                                              int   inLeftPx,
                                              int   inTopPx,
                                              int   inRightPx,
                                              int   inBottomPx,
                                              void* inRefcon);

struct  MonitorBoundsStructure    // #1
{
    int     MonitorIndex;
    int     LeftBx;
    int     TopBx;
    int     RightBx;
    int     BottomBx;
};

static void LuaReceiveMonitorBoundsOS_t(int inMonitorIndex, int inLeftBx, int inTopBx,
                                        int inRightBx, int inBottomBx, void* refcon)
{
    auto& MonitorBounds = *reinterpret_cast<std::vector<MonitorBoundsStructure>*>(refcon);

    MonitorBounds.emplace_back(
        MonitorBoundsStructure{
            inMonitorIndex,
            inLeftBx,
            inTopBx,
            inRightBx,
            inBottomBx
        }
    );
}

void XPLMGetAllMonitorBoundsOS(XPLMReceiveMonitorBoundsOS_f callback, void* inRefcon)
{
    callback(0,100,0,100,100, inRefcon);
    callback(1,99,1,99,99, inRefcon);
    callback(2,100,1,100,100, inRefcon);
}

static int LuaXPLMGetAllMonitorBoundsOSTest() {
    std::vector<MonitorBoundsStructure> MonitorBounds;  // #2

    XPLMGetAllMonitorBoundsOS(LuaReceiveMonitorBoundsOS_t, &MonitorBounds);  // #3

    for (auto& m : MonitorBounds) {
        std::cout << m.MonitorIndex << "\n";
    }

    return 1;
}

int main() {
    LuaXPLMGetAllMonitorBoundsOSTest();
}

выход

0
1
2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...