C ++ ссылки на экземпляры, созданные в области видимости функции - PullRequest
0 голосов
/ 13 декабря 2018

Контекст

Контекст проблемы в том, что я сейчас пишу небольшую библиотеку для использования с Arduino, чтобы действовать в качестве игрового контроллера.Однако проблема, с которой я сталкиваюсь, больше связана с C ++, чем с чем-то специфичным для Arduino.

Я включил заголовок библиотеки и исходный код ниже, а затем код Arduino.Я обрезал его там, где это возможно.

Проблема

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

Этидействия определяются в функции настройки Arduino.Например:

controller.addSwitchContinuous(10, 0);  // Pin 10; btn index 0

означает, что контакт 10 привязан к кнопке 0. Когда контакт 10 замкнут, это рассматривается как нажатие кнопки.Это прекрасно работает для одного действия, но когда я начинаю добавлять больше, только последнее действие действительно работает.Таким образом, в следующем примере распознается только вывод 9:

controller.addSwitchContinuous(10, 0);  // <-- Doesn't work
controller.addSwitchContinuous(9, 1);   // <-- Works

Это относится к любому произвольному числу действий:

controller.addSwitchContinuous(10, 0);  // <-- Doesn't work
controller.addSwitchContinuous(9, 1);   // <-- Doesn't work
controller.addSwitchContinuous(8, 2);   // <-- Doesn't work
controller.addSwitchContinuous(7, 3);   // <-- Works

Потенциальные причины

Я довольно новичок в C ++, поэтому я подозреваю, что что-то не так с указателями.Более конкретно, что-то не так с передачей экземпляра Joystick_.

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

Я могу подтвердить, что итерация в цикле JFSF :: выполняет итерацию по всем действиям, если я изменяю ее с помощью:

void JFSF::loop()
    {
        for (int n = 0; n < _nextActionIndex; n++)
        {
            if (_actions[n])
            {
                _actions[n]->loop();
                _joystick->setButton(n, PRESSED);  // Debug: Set button pressed, regardless of switch.
            }
        }
        if (_doSendState)
        {
            _joystick->sendState();
        }
    }

, тогда кнопки от 0 до n нажимаются, как и ожидалось.Возможно, что loop () не вызывается должным образом, но я ожидаю, что в этом случае он также потерпит неудачу для случая N = 1.Более того, тот факт, что последнее действие всегда завершается успешно, указывает на то, что итерация в порядке.

Полный код

// JFSF.h
#ifndef JFSF_h
#define JFSF_h

// ... include for Arduino.h and Joystick.h; bunch of defines

namespace JFSF_PRIV
{
class AbstractAction
{
public:
  virtual void loop();
};

/* A Switch that essentially acts as a push button. */
class SwitchContinuousAction : public AbstractAction
{
public:
  SwitchContinuousAction(Joystick_ *joystick, int pin, int btnIndex);
  void loop();

private:
  Joystick_ *_joystick;
  int _pin;
  int _btnIndex;
};

} // namespace JFSF_PRIV

class JFSF
{
public:
  JFSF(Joystick_ *joystick, bool doSendState); // doSendState should be true if Joystick_ does not auto send state.
  void loop();
  void addSwitchContinuous(int inputPin, int btnIndex);

private:
  Joystick_ *_joystick;
  JFSF_PRIV::AbstractAction *_actions[MAX_ACTIONS];
  int _nextActionIndex;
  bool _doSendState;
};

#endif

Исходный файл (обрезан):

// JFSF.cpp
#include "Arduino.h"
#include "Joystick.h"
#include "JFSF.h"

#define PRESSED 1
#define RELEASED 0

// Private classes
namespace JFSF_PRIV
{

SwitchContinuousAction::SwitchContinuousAction(Joystick_ *joystick, int pin, int btnIndex)
{
    _joystick = joystick;
    _pin = pin;
    _btnIndex = btnIndex;
    pinMode(_pin, INPUT_PULLUP);
}

void SwitchContinuousAction::loop()
{
    int _state = digitalRead(_pin) == LOW ? PRESSED : RELEASED;
    _joystick->setButton(_btnIndex, _state);
}

} // namespace JFSF_PRIV

JFSF::JFSF(Joystick_ *joystick, bool doSendState)
{
    _joystick = joystick;
    _nextActionIndex = 0;
    _doSendState = doSendState;
}

void JFSF::addSwitchContinuous(int inputPin, int btnIndex)
{
    JFSF_PRIV::SwitchContinuousAction newBtnAction(_joystick, inputPin, btnIndex);
    _actions[_nextActionIndex++] = &newBtnAction;
}

void JFSF::loop()
{
    for (int n = 0; n < _nextActionIndex; n++)
    {
        if (_actions[n])
        {
            _actions[n]->loop();
        }
    }
    if (_doSendState)
    {
        _joystick->sendState();
    }
}

Для полноты картины, это код для Arduino, но это всего лишь объявления:

#include <JFSF.h>

// ... A bunch of const declarations used below. These are pretty self explanatory.

// See: https://github.com/MHeironimus/ArduinoJoystickLibrary#joystick-library-api
Joystick_ joystick(HID_REPORT_ID,
  JOYSTICK_TYPE_JOYSTICK, // _JOYSTICK, _GAMEPAD or _MULTI_AXIS
  BTN_COUNT, HAT_SWITCH_COUNT,
  INCLUDE_X_AXIS, INCLUDE_Y_AXIS, INCLUDE_Z_AXIS, 
  INCLUDE_RX_AXIS, INCLUDE_RY_AXIS, INCLUDE_RZ_AXIS,
  INCLUDE_RUDDER, INCLUDE_THROTTLE, 
  INCLUDE_ACCELERATOR, INCLUDE_BRAKE, INCLUDE_STEERING);

JFSF controller(&joystick, !DO_AUTO_SEND_STATE);

void setup() {
  joystick.begin(DO_AUTO_SEND_STATE);
  controller.addSwitchContinuous(10, 0);  // <-- Doesn't work
  controller.addSwitchContinuous(9, 1);   // <-- Works
}

void loop() {
  controller.loop();
}

Ссылки

ArduinoJoystickLibrary (Источник для Joystick_) можно найти здесь: https://github.com/MHeironimus/ArduinoJoystickLibrary#joystick-library-api

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Спасибо @ user463035818 и @drescherjm за выявление актуальной проблемы.

В итоге я исправил ее, просто переместив создание объекта Action в код Arduino (где он по сути глобален) и передав ссылкик этим объектам к контроллеру.

В коде это переводится как:

JFSF.cpp

void JFSF::addAction(JFSF_PRIV::AbstractAction *action){
    _actions[_nextActionIndex++] = action;
}

Код Arduino (ino)

// See code in original post

JFSF controller(&joystick, !DO_AUTO_SEND_STATE);

JFSF_PRIV::SwitchContinuousAction btnOne(&joystick, 10, 0);
JFSF_PRIV::SwitchContinuousAction btnTwo(&joystick, 9, 1);

void setup() {
  joystick.begin(DO_AUTO_SEND_STATE);
  //  controller.addSwitchContinuous(10, 0);  // Pin 10; btn index 0
  //  controller.addSwitchContinuous(9, 1);   // Pin 9 ; btn index 1 
  controller.addAction(&btnOne);
  controller.addAction(&btnTwo);
}
// loop() is unchanged
0 голосов
/ 13 декабря 2018

Я не совсем понимаю ваш код.Пожалуйста, прочитайте Как создать минимальный, полный и проверяемый пример .В любом случае, следующее, безусловно, неверно и, вероятно, является причиной вашей проблемы:

void JFSF::addSwitchContinuous(int inputPin, int btnIndex)
{
    JFSF_PRIV::SwitchContinuousAction newBtnAction(_joystick, inputPin, btnIndex);
    _actions[_nextActionIndex++] = &newBtnAction;
}

Давайте перепишем ее немного для ясности:

void foo(){
    T bar;
    container[index] = &bar;
}

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

Короче говоря: среди новичков c ++ часто встречается злоупотребление указателями.Скорее всего, вы должны сделать container контейнером объектов, а не указателей и использовать автоматическое управление памятью вместо того, чтобы пытаться бороться с ним.

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