Доступ к функции в объекте через `->` приводит к сбою (сбросу) Arduino
У меня есть несколько классов, которые вызывают друг друга, работающих на Arduino Mega. Я использую библиотеку ArduinoSTL, чтобы получить библиотеку std, в первую очередь std::vector.
Основная проблема заключается в следующем: мой объект Manager, созданный в глобальном пространстве Arduino, вызывается в
цикле()
. Объект Manager
в одной из своих функций порождает производный объект Derived derived
(конструктор также принимает pin int и значение задержки, но пока просто упрощает) и вызывает в нем функцию derived.startExecution()
. Все довольны. Затем я сохраняю указатель на объект в std::vector<base*> MyVector
через MyVector.push_back(&derived)
. Все довольны. Пока я не покидаю функцию, я могу вынуть указатель из векторного контейнера и вызвать другую функцию в объекте. Например: MyVector.back()->continueExecution()
и все отлично. Теперь проблема. Если я скопирую строку MyVector.back()->continueExecution()
в другую функцию, Arduino перезапустится. Я теряю рассудок. Я знаю, что проблема не в указателе, а в вызове функции с помощью указателя. Используя println & delay(500), в новой функции внутри Менеджера я могу сделать следующее без проблем (без перезагрузки):
- извлечение указателя из вектора. Все хорошо.
- назначьте указатель из вектора временному типу указателя, чтобы иметь возможность ссылаться на этот указатель. Все хорошо
- вызов функции в объекте вызывает мгновенный аппаратный сброс Arduino (ни одна строка не будет выполнена в вызываемой функции).
Все это приводит меня к выводу, что вызов функции в объекте вызывает проблему. Я переписал упрощенную версию кода ниже, и он хорошо работает на этом сайте (см.: https://godbolt.org/z/G3x556), но на Arduino он выходит из строя.
Что я могу сделать, чтобы понять, почему объект завершает работу программы? как я могу проверить, что объект в порядке, прежде чем вызывать функцию? Почему вызов функции в объекте, который должен быть живым, приводит к сбою системы? почему вызов работает в функции, которая сохранила его в векторе, но не в другой функции? Как я могу ответить на эти вопросы? Я достиг предела идей. Спасибо, что уделили мне время!
Мой код упрощен:
#include <iostream>
//#include <ArduinoSTL.h> //закомментировано для работы на сайте
#include <vector>
//базовый класс используется для того, чтобы иметь возможность помещать все в std::vector
//в ArduinoSTL lib.
class Base
{
public:
virtual void continueExecution()
{ std::cout << "Base" << std::endl; }
// полиморфный класс ДОЛЖЕН иметь виртуальный деструктор
virtual ~Base(){};
};
//многие из этих классов будут существовать в один прекрасный день, если я продолжу этот
class Derived : public Base
{
public:
Derived()
{
std::cout<< "Derived constructor" << std::endl;
}
void startExecution()
{
std::cout << "Derived object, start function"<< std::endl;
//начало работы
}
void continueExecution()
{
//продолжить по истечении времени
std::cout << "Derived continueExectution " << std::endl;
}
};
class Manager
{
public:
void beginExecutingDerivedObject()
{
//производный объект
Derived derivedObj;
derivedObj.startExecution();
myVector.push_back(&derivedObj);
//если я запущу строку, которая приведет к сбою кода ниже этого
//комментарий, все в порядке. Но это не то, что нужно.
myVector.back()->continueExecution();
}
void finishExecutionOfDerivedObject()
{
//СБОЙ КОДА ЗДЕСЬ. В тот момент, когда функция вызывается, происходит сброс
//происходит.
myVector.back()->continueExecution();
//любой код здесь может появиться на консоли, но это всего лишь
//дамп памяти. К этому моменту Arduino уже развел руками.
}
private:
//создать вектор
std::vector<Base*> myVector;
};
//main-это на самом деле arduino loop()
int main()
{
//этот класс менеджера находится в глобальном пространстве sketch
Manager manager;
//это вызывается вызовом функции в цикле()
manager.beginExecutingDerivedObject();
//это также вызывается вызовом функции в цикле()
manager.finishExecutionOfDerivedObject();
}
@Mike, 👍0
1 ответ
Лучший ответ:
Derived derivedObj;
- локальная переменная. Он удаляется при выходе из функции. Вы сохранили указатель на него, но теперь, когда этот объект исчез, ваш указатель не указывает ни на что интересное, так что делать с ним что - либо обречено на провал.
Вместо этого вам нужно создать новый
объект в куче, который уже будет указателем:
Derived *derivedObj = new Derived();
derivedObj->startExecution();
myVector.push_back(derivedObj);
А затем обязательно удалите
все объекты, которые вы удаляете из вектора, иначе вы навсегда потеряете эту память.
- Почему считается плохой практикой использовать ключевое слово "new" в Arduino?
- Работает с gcc, но не с Arduino. ошибка: taking address of temporary array
- Поддерживает ли Arduino C++ динамические массивы объектов ?
- Получить массив символов с помощью модуля SIM900
- Как объявить динамический массив?
- Динамическое изменение стека вызовов с помощью указателей
- Разбор массива объекта в конструкторе библиотеки
- Проблема с передачей указателя строки от дочернего к родительскому
Обратите внимание, что
std::vector<Base*> MyVector;
- это вектор указателей. Вы _could_ храните значения в векторе какstd::vector<Base> MyVector;
, но тогда вы не можете хранить экземпляры производных классов., @PMF@Mike В вашем случае это немного сложно, потому что вы должны делать это, когда удаляете элементы или очищаете список
MyVector
. (Повторите его с помощью цикла "for" и удалите все элементы, прежде чем очистить вектор). Использование STL (и некоторых других функций, которые вы используете выше) - довольно продвинутый материал для работы на Arduino, просто потому, что его память очень ограничена. Вероятно, вам следует сначала ознакомиться с некоторыми учебниками по C ++ и запустить несколько тестовых программ на ПК (где их гораздо легче отлаживать)., @PMFИнтеллектуальный указатель C ++ 11 shared_ptr упрощает его, но не знает, поддерживает ли их ArduinoSTL., @Majenko
@Majenko Ты РОК!!! Я совсем не знаю C ++, и его так трудно выучить на лету. Огромное спасибо за ваш ответ. Могу ли я испытать свою удачу и, пожалуйста, попросить пример того, как использовать слово delete? Я совершенно новичок в C ++ и очень ценю это. Не могли бы вы в своем примере предположить, что используется C ++ 99 (если мне посчастливится его получить)?, @Mike
Base *ob = MyVector[0]; MyVector.erase(0); delete ob;
, @Majenko@Majenko Я очень новичок в c ++, и у меня есть окончательное продолжение вашего примера
удалить
. В вашем примере сначала вы копируете указатель из вектора (так же, как:Base *myObj = MyVector.back();
. Затем вы стираете элемент в векторном указателе (то же самое, чтоMyVector.pop_back();
). Наконец, вы освобождаете память с помощью указателя. Я прав? Кроме того, когда мы "удаляем myObj", мы не удаляем указатель базового типа? разве мы не должны удалять фактический объект, или это действительно удаляет указатель И объект? Извините, что докучаю вам. Я очень ценю вашу помощь!, @Mikeудалить
- это то же самое, что "новый" - это то же самое, что "свободный" - это "malloc". Вы даете ему указатель (поскольку new предоставляет указатель), и он освобождает объект (вызывая деструктор), на который указывает указатель. Сновым
вы никогда не "имеете" объект. У вас всегда есть только указатель (с соответствующим типом)., @Majenko