Embedded C ++: использовать STL или нет?

@SafeVarargs не мешает ему произойти, однако он требует, чтобы компилятор был более строгим при компиляции кода, который его использует.

http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html объясняет это более подробно.

Загрязнение кучи - это когда вы получаете ClassCastException при выполнении операции на общем интерфейсе, и он содержит другой тип, чем объявлено.

70
задан Community 23 May 2017 в 12:26
поделиться

9 ответов

Супербезопасно и потеряло большую часть того, что составляет C ++ (imo, это больше, чем {{ 1}} только определение языка) и , возможно, позже возникнут проблемы или , чтобы добавить много обработки исключений и , может быть, какой-то другой код сейчас?

У нас есть аналогичные дебаты в игровом мире и люди сходятся с обеих сторон. Что касается цитируемой части, почему вы должны беспокоиться о потере «большей части того, что составляет C ++»? Если это не прагматично, не используйте его. Не имеет значения, C ++ это или нет.

Проведите несколько тестов. Можете ли вы обойти управление памятью в STL способами, которые вас устраивают? Если да, то стоило ли это усилий? Многие проблемы, которые STL и ускорение предназначены для решения, просто не возникают, если вы проектируете так, чтобы избежать случайного распределения динамической памяти ... Решает ли STL конкретную проблему, с которой вы сталкиваетесь?

Многие люди вплотную занимались STL. окружающей среды и доволен этим. Многие просто избегают этого. Некоторые предлагают совершенно новые стандарты . Я не думаю, что есть один правильный ответ.

33
ответ дан 24 November 2019 в 12:58
поделиться

Я работаю над встраиваемыми системами реального времени каждый день. Конечно, мое определение встраиваемой системы может отличаться от вашего. Но мы в полной мере используем STL и исключения и не сталкиваемся с неуправляемыми проблемами. Мы также используем динамическую память (на очень высоком уровне; выделяем много пакетов в секунду и т.д.) и пока не прибегаем к каким-либо пользовательским аллокаторам или пулам памяти. Мы даже использовали C++ в обработчиках прерываний. Мы не используем ускорение, а только потому, что определенный государственный орган нам этого не позволяет.

По нашему опыту вы действительно можете использовать многие современные возможности C++ во встраиваемой среде до тех пор, пока используете свою голову и проводите собственные тесты. Я настоятельно рекомендую вам использовать C++ Effective C++ 3-е издание Скотта Мейера, а также стандарты кодирования C++ C++ Саттера и Александреску, чтобы помочь вам в использовании C++ со вменяемым стилем программирования.

Правка: После того, как я проголосовал за это 2 года спустя, позвольте мне опубликовать обновление. Мы значительно продвинулись в развитии и наконец-то попали в такие места в нашем коде, где стандартные контейнеры библиотек слишком медленные в условиях высокой производительности. Здесь мы фактически прибегли к пользовательским алгоритмам, пулам памяти и упрощенным контейнерам. В этом-то и прелесть Си++, но вы можете использовать стандартную библиотеку и получать все то хорошее, что она дает в 90% случаев использования. Вы не выбрасываете все это, когда сталкиваетесь с проблемами, а просто вручную оптимизируете проблемные места.

45
ответ дан 24 November 2019 в 12:58
поделиться

В других сообщениях рассматриваются важные вопросы распределения динамической памяти, исключений и возможного раздувания кода. Я просто хочу добавить: не забывайте о ! Независимо от того, используете ли вы векторы STL или простые массивы и указатели C, вы все равно можете использовать sort () , binary_search () , random_shuffle () , функции для создания и управления кучей и т. д. Эти процедуры почти наверняка будут быстрее и с меньшими ошибками, чем версии, которые вы создаете сами.

Пример: если вы не подумаете об этом внимательно, алгоритм перемешивания, который вы построите самостоятельно , скорее всего, даст искаженные распределения ; random_shuffle () не будет.

25
ответ дан 24 November 2019 в 12:58
поделиться

Пол Педриана из Electronic Arts писал в 2007 году длинный трактат о том, почему STL не подходит для разработки встроенных консолей и почему они должны были написать свой собственный. Это подробная статья, но наиболее важными причинами были:

  1. Распределители STL медленные, раздутые, и неэффективные
  2. На самом деле компиляторы не очень хороши для встраивания всех этих глубоких вызовов функций
  3. STL распределители не поддерживают явное выравнивание
  4. . Алгоритмы STL, которые поставляются с GCC и MSVC STL, не очень производительны, потому что они очень независимы от платформы и, следовательно, пропускают множество микрооптимизаций, которые могут иметь большое значение.

Несколько лет назад наша компания приняла решение вообще не использовать STL, вместо этого внедрив нашу собственную систему контейнеров, которые максимально производительны, легче отлаживать и более консервативны по памяти. Это была большая работа, но она многократно окупилась. Но у нас есть пространство, в котором продукты соревнуются в том, сколько они могут втиснуть в 16,6 мс при заданном размере процессора и памяти.

Что касается исключений: они медленные на консолях, и любой, кто говорит вам иное, не пробовал рассчитывать их время. Простая компиляция с их включенными замедлит всю программу из-за необходимого кода пролога / эпилога - измерьте это сами, если вы мне не верите. На исправных процессорах это даже хуже, чем на x86. По этой причине используемый нами компилятор даже не поддерживает исключения C ++.

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

19
ответ дан 24 November 2019 в 12:58
поделиться
  1. для управления памятью вы можете реализовать свой собственный распределитель, который запрашивает память из пула. И у всех контейнеров STL есть шаблон для распределителя.

  2. для исключения, STL не генерирует много исключений, как правило, наиболее распространенными являются: нехватка памяти, в вашем случае система должна перезагрузиться, поэтому вы можете выполнить сброс в распределителе. другие такие как вне диапазона, вы можете избежать этого пользователем.

  3. так что, я думаю, вы можете использовать STL во встроенной системе :)

5
ответ дан 24 November 2019 в 12:58
поделиться

Это в основном зависит от вашего компилятора и от объема памяти, который у вас есть. Если у вас более нескольких килобайт оперативной памяти, очень помогает динамическое распределение памяти. Если реализация malloc из стандартной библиотеки, которая у вас есть, не настроена на размер вашей памяти, вы можете написать свою собственную, или есть хорошие примеры, такие как mm_malloc от Ральфа Хемпеля , которые вы можете использовать для написания своего сверху операторы new и delete.

Я не согласен с теми, кто повторяет мем о том, что исключения и контейнеры stl слишком медленные или слишком раздутые и т. Д. Конечно, он добавляет немного больше кода, чем простой C malloc, но разумное использование исключений может сделать код очень ясно и избегайте слишком большого количества проверок ошибок в C.

Следует иметь в виду, что распределители STL увеличивают свои выделения в степени двойки, что означает, что иногда они будут выполнять некоторые перераспределения, пока не достигнет правильного размера, который вы можно предотвратить с помощью резерва , поэтому он становится таким же дешевым, как один malloc желаемого размера, если вы все равно знаете размер, который нужно выделить.

Например, если у вас большой буфер в векторе, в какой-то момент он может выполнить перераспределение и в конечном итоге будет использовать 1,5-кратный объем памяти, который вы собираетесь использовать в какой-то момент при перераспределении и перемещении данных. (Например, в какой-то момент ему выделено N байтов, вы добавляете данные через добавление или итератор вставки, и он выделяет 2N байтов, копирует первые N и освобождает N. В какой-то момент у вас выделено 3N байтов).

Так что, в конце концов, у этого есть много преимуществ, и если вы знаете, что делаете, то окупается. Вы должны немного знать, как работает C ++, чтобы использовать его во встроенных проектах без сюрпризов.

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

Возникло исключение в ARM realview 3.1:

--- OSD\#1504 throw fapi_error("OSDHANDLER_BitBlitFill",res);
   S:218E72F0 E1A00000  MOV      r0,r0
   S:218E72F4 E58D0004  STR      r0,[sp,#4]
   S:218E72F8 E1A02000  MOV      r2,r0
   S:218E72FC E24F109C  ADR      r1,{pc}-0x94 ; 0x218e7268
   S:218E7300 E28D0010  ADD      r0,sp,#0x10
   S:218E7304 FA0621E3  BLX      _ZNSsC1EPKcRKSaIcE       <0x21a6fa98>
   S:218E7308 E1A0B000  MOV      r11,r0
   S:218E730C E1A0200A  MOV      r2,r10
   S:218E7310 E1A01000  MOV      r1,r0
   S:218E7314 E28D0014  ADD      r0,sp,#0x14
   S:218E7318 EB05C35F  BL       fapi_error::fapi_error   <0x21a5809c>
   S:218E731C E3A00008  MOV      r0,#8
   S:218E7320 FA056C58  BLX      __cxa_allocate_exception <0x21a42488>
   S:218E7324 E58D0008  STR      r0,[sp,#8]
   S:218E7328 E28D1014  ADD      r1,sp,#0x14
   S:218E732C EB05C340  BL       _ZN10fapi_errorC1ERKS_   <0x21a58034>
   S:218E7330 E58D0008  STR      r0,[sp,#8]
   S:218E7334 E28D0014  ADD      r0,sp,#0x14
   S:218E7338 EB05C36E  BL       _ZN10fapi_errorD1Ev      <0x21a580f8>
   S:218E733C E51F2F98  LDR      r2,0x218e63ac            <OSD\#1126>
   S:218E7340 E51F1F98  LDR      r1,0x218e63b0            <OSD\#1126>
   S:218E7344 E59D0008  LDR      r0,[sp,#8]
   S:218E7348 FB056D05  BLX      __cxa_throw              <0x21a42766>

Это не кажется таким уж страшным, и внутри {} блоков или функций не добавляются накладные расходы, если исключение не генерируется.

3
ответ дан 24 November 2019 в 12:58
поделиться

Самая большая проблема с STL во встроенных системах - это проблема выделения памяти (которая, как вы сказали, вызывает множество проблем).

Я бы серьезно поработал над созданием вашего собственного управления памятью, основанного на переопределении операторов new / delete. Я почти уверен, что со временем это можно будет сделать, и почти наверняка оно того стоит.

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

Редактировать:
Поскольку многие люди написали комментарии, в которых говорилось, что обработка исключений не медленнее, я подумал, что добавлю эту небольшую заметку (спасибо людям, которые написали это в комментариях, я подумал, что неплохо бы добавить сюда).

Причина, по которой обработка исключений замедляет ваш код, заключается в том, что компилятор должен убедиться, что каждый блок ( {} ), от места, где создается исключение, до места, с которым оно обрабатывается, должен освобождать все объекты внутри него.Это код, который добавляется к каждому блоку, независимо от того, генерирует ли кто-нибудь исключение или нет (поскольку компилятор не может сказать во время компиляции, будет ли этот блок частью «цепочки» исключений).

Конечно, это может быть старый способ делать вещи, который стал намного быстрее в новых компиляторах (я не совсем в курсе оптимизаций компилятора C ++). Лучший способ узнать это - просто запустить пример кода с включенными и выключенными исключениями (и который включает несколько вложенных функций) и измерить разницу во времени.

1
ответ дан 24 November 2019 в 12:58
поделиться

Позвольте мне начать с того, что я не выполнял встроенную работу в течение нескольких лет и никогда не работал с C ++, поэтому мой совет стоит каждого цента » расплачиваться за это ...

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

STL сама по себе не генерирует исключения, так что это не должно вызывать беспокойства. Если ваши занятия не бросают, вы должны быть в безопасности. Разделите инициализацию объекта на две части, позвольте конструктору создать объект с голыми костями, а затем выполнить любую инициализацию, которая может завершиться ошибкой в ​​функции-члене, возвращающей код ошибки.

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

15
ответ дан 24 November 2019 в 12:58
поделиться

В дополнение ко всем комментариям, я бы предложил вам прочитать Technical Report on C++ Performance, в котором конкретно рассматриваются интересующие вас темы: использование C++ в embedded (включая системы жесткого реального времени); как обычно реализуется обработка исключений и какие накладные расходы она несет; накладные расходы при распределении свободного хранилища.

Отчет действительно хорош, поскольку развенчивает многие популярные слухи о производительности C++.

3
ответ дан 24 November 2019 в 12:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: