Приведение указателя к векторному типу в обратном вызове

Программист выходного дня, новичок в 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), код по крайней мере дойдет до того места, где структура внутри обратного вызова заполнена правильными данными, я ударяюсь о стену, возвращая эту структуру вызывающей функции, то есть мой приведенный void * to vector неверно по крайней мере.

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

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

Решение: Спасибо Теду Люнгмо за предоставленное решение, даже за то, что он написал тестовый код на своей собственной системе. Моя проблема, как я и подозревал, заключалась в приведении указателя на вектор. Я включил ответы как 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;
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
163
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
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

Спасибо за быстрый ответ. Я внес изменения в свой cast и push_back, как вы предложили, но получил ошибки сегментирования. Опять же, кажется, вопрос о push_back ...

IanQ 11.11.2018 16:32

У вас есть отладчик, чтобы вы могли точно видеть, где он обнаруживает ошибки? Я бы удалил из структуры член RefCon, а также returnData.RefCon = *(int *)refcon. Если int больше адреса, это вызывает неопределенное поведение.

Ted Lyngmo 11.11.2018 17:03

Добавлена ​​небольшая тестовая версия

Ted Lyngmo 11.11.2018 17:49

Я заставил его работать, как ваше первое предложение, так и последующее использование .emplace_back вместо push_back (что я очень предпочитаю). Проблема, с которой я столкнулся с вашим первым предложением, была связана с некоторым остаточным кодом, который я сохранил в функции обратного вызова, которая работала с простым указателем int, по-видимому, это мешает новому коду. Я плохо держал это там, я думал, что это безвредно, когда это не так. Большое спасибо за вашу помощь!

IanQ 12.11.2018 00:05

И забыл упомянуть, что это работает даже с участником RefCon, хотя, думаю, в конце концов удалю, так как оно мне не нужно.

IanQ 12.11.2018 00:27

Большой! Что касается push_back и emplace_back: в таких случаях, когда вы создаете что-то с единственной целью добавить это к вектору, emplace_back более эффективен, поскольку он обычно создает структуру на месте для вас. Когда вы сначала создаете структуру, а затем используете push_back, необходимо сделать копию структуры.

Ted Lyngmo 12.11.2018 10:29

Другие вопросы по теме