Безопасно ли использовать std::array (из C++ STL) на Arduino? Использует ли он динамическое выделение памяти?
Я бы хотел использовать std::array в проекте, который должен быть очень стабильным, и вся память должна быть предварительно выделена, чтобы избежать фрагментации кучи.
Я считываю символы из последовательного порта по известному протоколу. Каждый полученный байт будет записан в массив символов достаточного размера, чтобы содержать максимально длинную строку, которую я получу. Затем я выполняю некоторые второстепенные операции «на лету» (т. е. пропускаю определенные символы, заменяю один другим и т. д.) и записываю их в другой последовательный порт.
Это устройство должно работать неограниченное время. Я не буду вызывать malloc или new в своем коде. Все мои объекты управления — это синглтоны (слышен вздох высокопоставленной толпы!), созданные во время установки и никогда не уничтожаемые.
Безопасно ли использование шаблона массива STL в этом контексте?
После прочтения этого сообщения и этот пост, единственные потенциальные проблемы, которые я вижу, это обработка исключений. Насколько я понимаю, исключение так же фатально, как и нарушение прав доступа. Я бы не стал пытаться восстановиться после исключения, поэтому меня не волнует, что Arduino их не поддерживает.
Но что произойдет, если программа попытается выбросить его? Разрешит ли компилятор arduino использовать std::array, если он поддерживает исключения? Существует ли удобный для Arduino шаблон массива, который использует массивы фиксированного размера и поддерживает итераторы?
Спасибо!
@Mustard Tiger, 👍1
Обсуждение1 ответ
Лучший ответ:
std::array
не использует динамическое выделение памяти для хранения своих элементов. Если вы используете статические или выделенные в стеке объекты std::array
, вам не нужно беспокоиться о фрагментации памяти (в отличие от std::vector
или String
, например).
Конечно, если вы размещаете массивы в стеке, у вас может возникнуть переполнение стека, если вы вызовете слишком много функций либо по дизайну, либо из-за ошибки.
Это подводит нас к проблеме исключений. Если вы заглянете в стандарт, то увидите, что большинство функций-членов std::array
помечены noexcept
, за заметным исключением методов доступа к элементам. Очевидно, что метод доступа at()
может генерировать ошибки, но вы ожидаете, что operator[]
этого не сделает.
На практике operator[]
помечен как noexcept
в той версии STL (GCC9), которая установлена на моем компьютере, поэтому, если вы проверите его в реализации STL, повторно используя, вы можете быть уверены, что он не будет бросать. Просто имейте в виду, что это не предусмотрено стандартом.
/usr/include/c++/9/массив
// Доступ к элементу.
_GLIBCXX17_CONSTEXPR reference
operator[](size_type __n) noexcept
{ return _AT_Type::_S_ref(_M_elems, __n); }
constexpr const_reference
operator[](size_type __n) const noexcept
{ return _AT_Type::_S_ref(_M_elems, __n); }
Отладочная версия также помечена как noexcept
, но она может сбросить/прервать работу, если индекс выходит за пределы:
/usr/include/c++/9/отладка/массив
// Доступ к элементу.
_GLIBCXX17_CONSTEXPR reference
operator[](size_type __n) noexcept
{
__glibcxx_check_subscript(__n);
return _AT_Type::_S_ref(_M_elems, __n);
}
constexpr const_reference
operator[](size_type __n) const noexcept
{
return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n)
: (_GLIBCXX_THROW_OR_ABORT(_Array_check_subscript<_Nm>(__n)),
_AT_Type::_S_ref(_M_elems, 0));
}
Реализации STL для Arduino, которые я нашел в Интернете, похоже, не имеют заголовка <array>
.
К счастью, вы можете легко создать свой собственный контейнер массива, например:
template <class T, size_t N>
struct Array {
// Хранилище
T data[N];
static size_t length() { return N; }
using type = T;
// Доступ к элементу
T &operator[](size_t index) { return data[index]; }
const T &operator[](size_t index) const { return data[index]; }
// Итераторы
T *begin() { return &data[0]; }
const T *begin() const { return &data[0]; }
T *end() { return &data[N]; }
const T *end() const { return &data[N]; }
// Сравнения
bool operator==(const Array<T, N> &rhs) const {
if (this == &rhs)
return true;
for (size_t i = 0; i < N; i++)
if ((*this)[i] != rhs[i])
return false;
return true;
}
bool operator!=(const Array<T, N> &rhs) const {
return !(*this == rhs);
}
};
void setup() {
Serial.begin(115200);
while (!Serial);
// Создаем массив
Array<int, 5> myArray = {1, 2, 3, 4, 5};
// В старых компиляторах используйте двойные фигурные скобки:
// Массив<int, 5> мой массив = {{1, 2, 3, 4, 5}};
// Перебираем массив
for (int element : myArray)
Serial.println(element);
// Доступ к элементам массива
myArray[2] = 30;
Serial.println(myArray[2]);
}
void loop() {}
- Как объявить динамический массив?
- Полностью ли поддерживается C++ STL на Arduino?
- Работает ли конструкция int array[100] = {0} на Arduino?
- Массив динамического размера в качестве члена класса
- Итерация массива объектов
- Как получить размер (sizeof) массива структур
- Работает с gcc, но не с Arduino. ошибка: taking address of temporary array
- Как использовать лямбда-функции в Arduino?
Я не ставлю это как ответ, потому что это не является прямым ответом на ваш вопрос. Кажется, что динамическое выделение памяти безопасно использовать std::array, однако вы все еще не знаете, что под капотом, возможно, проблема в потреблении памяти (размер стека локальных переменных вложенных функций, вызываемых публичными функциями для замены и повторение). Если вам нужны какие-то второстепенные функции, я бы написал их сам и полностью контролировал решения как по памяти, так и по производительности., @Michel Keijzers
«Я бы написал их сам и полностью контролировал как память, так и производительность». Это вечный вопрос. Мое время, потраченное на то, чтобы написать это самому, или мое потенциальное время, потраченное на выяснение того, куда ушла моя память. Тем временем я работаю над другими частями кода, но я надеюсь, что кто-то, кто уже совершил эту ошибку, может вмешаться, прежде чем я совершу ту или другую., @Mustard Tiger
@Michel Keijzers Кроме того, к вашему сведению, я использую это на Mega, поэтому у него больше памяти. Но все же это не так много, по большому счету., @Mustard Tiger