Приемлемо ли новое без удаления?
Я знаю, что не рекомендуется использовать команду new
для динамического создания данных, однако, если я никогда не буду использовать команду delete
, приведет ли это к потере памяти пробелы/другие проблемы?
Справочная информация
Причина, по которой мне необходимо создавать экземпляры динамически, заключается в том, что я хочу сначала протестировать свое приложение на ПК. И я хочу, чтобы несколько классов имели больше свойств для версии для ПК, чем для версии Arduino (например, для хранения имен или информации для отображения графического интерфейса ПК). Классы версии для ПК будут унаследованы от (настоящих) классов Arduino, но с добавленными свойствами.
В некоторых классах мне нужно создать список, и я не могу использовать тип с жестко запрограммированными значениями для заполнения массива.
Пример:
У меня есть класс LightSetup, содержащий список Pars (светодиодов):
class LightSetup
{
protected:
Par* _pars[NR_OF_PARS];
Par — это реальная версия Arduino, для ее заполнения мне нужно:
LightSetup::LightSetup()
{
for (int n = 0; n < NR_OF_PARS; n++)
{
_pars[n] = new Par(1 + 8 * n);
}
}
В версии для ПК вместо нового Par я использую новый TestPar. А в заголовке я не могу это определить без такого указателя:
Par _pars[NR_OF_PARS];
Иначе он не может содержать экземпляры TestPar.
@Michel Keijzers, 👍0
Обсуждение2 ответа
Лучший ответ:
Конечно. Использование new
или malloc
для первоначальной настройки на самом деле ничем не отличается от статического распределения. Нет ничего плохого в использовании malloc
или new
, только в многократном использовании с free
или delete
.< /п>
Выделение блока кучи и сохранение его навечно не приводит к фрагментации кучи. Только повторное выделение и освобождение размеров переменных (например, причины String
) начинают создавать проблемы. Выделение памяти в начале вашей программы и оставление ее выделенной, если вы не выделяете слишком много, конечно, не является проблемой.
Спасибо за подтверждение. Единственный недостаток, который я вижу, это то, что используемая память не рассчитывается по глобальным переменным в Arduino IDE., @Michel Keijzers
Ага. Отсюда и подталкивание следить за тем, чтобы вы не выделяли слишком много :), @Majenko
Возможно, в целях отладки я покажу объем зарезервированной памяти после новых операторов., @Michel Keijzers
В деструкторе вам понадобится
LightSetup::~LightSetup()
{
for (int n = 0; n < NR_OF_PARS; n++)
{
delete _pars[n];
}
}
и каждый раз, когда вы заменяете _pars, вам нужно удалить старый. Это можно сделать автоматически с помощью unique_ptr.
Однако для вашей цели это звучит так, будто #if
лучше подходит для того, чтобы во время компиляции различать, какой тип вы фактически храните внутри этого массива.
#if ON_ARDUINO
Par _pars[NR_OF_PARS];
#else
TestPar _pars[NR_OF_PARS];
#endif
Что ж, деструктор никогда не будет вызываться, поскольку в моем приложении Arduino цикл будет выполняться вечно, так что это не проблема. Но я проголосовал за последнюю часть, возможно, это даже лучше, чем новая команда (хотя она немного загромождает код). Однако, если это единственное изменение, все проще. Спасибо, @Michel Keijzers
Я согласен с @ratchet по поводу #if, поскольку описанный вами случай касается не динамической типизации, а скорее разницы в платформах. Если вам не нужен один и тот же двоичный файл для запуска на обеих платформах (если это вообще возможно), вам лучше подойдет условная компиляция. Это также устраняет необходимость возиться с деструктором., @Kelly S. French
- Помогите уменьшить размер скетча!
- Если код, используемый для ардуино, может быть встроен в постоянную вызываемую память, есть ли способ создать ОС для Arduino, которая запускается по вызову?
- Получить доступ к EEPROM ATtiny с помощью кода Arduino?
- Глобальные переменные занимают много места в динамической памяти.
- Выделение строковой памяти Arduino
- Как очистить кучу памяти в esp32
- Есть ли способ подключить оперативную память компьютера к Arduino?
- Последовательная печать из флэш-памяти (F() macro, PROGMEM, sprintf_P, SPTR)
Вы можете избежать проблемы с новым удалением кучи, используя класс шаблона. Вот пример: https://github.com/mikaelpatel/Cosa/blob/master/cores/cosa/Cosa/IOBuffer.hh#L29., @Mikael Patel
@MikaelPatel Спасибо за этот комментарий, это тоже звучит как хорошая идея ... забыл о шаблонах (последний раз использовал их 20 лет назад ;-))., @Michel Keijzers
Другим примером является класс шаблона GPIO, который компилирует цифровое чтение/запись в одну инструкцию: https://github.com/mikaelpatel/Arduino-GPIO/blob/master/src/Hardware/AVR/GPIO.h, @Mikael Patel
Должен сказать, что когда я впервые прочитал заголовок, я был вполне уверен в ответе: «Это никогда не приемлемо», но вы дали мне интересный сценарий для размышления. Это необычный случай, но действительный., @Kelly S. French
@MikaelPatel Спасибо ... мне нужно это проверить получше, выглядит очень полезно., @Michel Keijzers
@KellyS.French На самом деле я пришел к этой идее, потому что в моих профессиональных проектах мы заранее создавали экземпляры всех объектов, не из-за проблем с удалением/нехваткой памяти, а из-за производительности ( отсутствие создания новых объектов во время критических частей выполнения)., @Michel Keijzers
Вот еще один пример: Java позволяет вам предварительно выделить блок памяти (начальный размер кучи?) во время загрузки точно по той же причине, чтобы сократить выделение памяти во время выполнения. На самом деле это может стать хорошим общим вопросом о StackOverflow для общего случая, и я бы посоветовал вам написать об этом., @Kelly S. French
@KellyS.French Спасибо за это, хотя я не могу использовать Java для Arduino (по крайней мере, в Arduino IDE)., @Michel Keijzers