С появление дешевых армов появилась возможность эффективно использовать С++ для разработки более сложных проектов чем ранее. Вопрос о применимости С++ для меня лично не стоит. С другими мнениями разного уравня осознания материала рекомендую ознакомится в соседней ветке http://electronix.ru/forum/index.php?showtopic=91629
покуда в ней коллеги ломают копья, мы не ломаем а строим.
Почему это выгодно.
1. даже 32К ОЗУ это на мой взгляд колосальное пространство. (я не имею ввиду буфера и тд - тесть то от чего не избавишся, я имею ввиду только то что С++ не жрет память просто так и грамотно написанные алгоритмы на С и С++ на выходи дадут идентичный асм).
2. Наличие фенечек ООП дает возможность сократить сами исходниуи, сделать их прозрачными и тд.
3. Мы не зачто не платим.
4. куча другого что Вы и сами знаете без меня.
Нюансы применительно к программам для stm32
1 если вы не пользуетесь динамическим выделение памяти но все работает сразу (особо отмечу что crt код должен вызывать _init_array для вызова конструкторов глобальных и статических объектов, конструкторы объектов на стеке компиллер вызоват сам)
2, если всетаки нужно new и delete, а я подразумеваю здесь что это так, то ничего страшного нет - достаточно написать свой менеджер памяти - он может быть очень простой. и переопределить operator new, operator delete с вызовами функций этого менеджера.
3. выключить нахрен поддержку эксепшенов и RTTI
вот в этом месте Вы получите возможности С++. я на этой стадии уже 2 год - полет нормальный, проекты строю по своему шаблону
FreeRTOS
C++ обертка которая реализует классы задача,очередь,шедуллер,семафор и тд для FreeRTOS
менеджер памяти взятый из примеров FreeRTOS со соими костыликами которыми я его расширил.
написанные ране классы и алгоритмы.
Всебы хорошо но грызла меня мысль а что если с С++ прокатило (да еще как замечательно!) может еще и STL забобахать! поскольку я програмирую и для больших систем в программах лдя которых применение STL жизненно необходимо, пришлось поизучать концепции положенные в STL. неделю назад я пришел к осознанию что люди которые придумали С++ и расширили его шаблонами и поверх еще накрутили STL - потому что им удалось реализовать подход - какой бы сложный инструмент не былбы - платить только за тоо что используеш. с другой стороны и в микроконтроллерных программах приходится реализовавть алгоритмы и методы которые закодированы в STL. мой опыт показал чтьо то что я дедад руками - всегда хуже

итак следующая ступень развития!
STL на микроконтроллерах быть!
сначала результаты и потом как этого добится.
вот рабочий код на котором я тестировал возможность применить STL
Код
#include "supc++.h" // inline переопределение operator new и оператор delete
#include "supstl.h" // inline определение аллокатора пригодного для нас
#include <string.h>
#include <map> // шаблон std::map
using namespace std;
char heap[4*1024]; // кучка для менеджера памяти
void *HeapMalloc( size_t WantedSize ) // наипростейшая реализация
{
static char* ptr = heap;
char* tmp = ptr;
ptr += WantedSize;
return (void*)tmp;
}
void HeapFree( void* pv ) наипростейшая реализация
{
// заглушка
}
class TTestObject // класс тестовых объектов котрые будут засовыватся в мапу
{
public:
TTestObject()
{
vals = new char[4];
strcpy( name , "noname" );
}
TTestObject(const TTestObject& src)
{
vals = new char[4];
strcpy( name , src.name );
memcpy( vals , src.vals , 4 );
val = src.val;
}
TTestObject(const char* name)
{
vals = new char[4];
strcpy( this->name , name );
}
~TTestObject()
{
delete vals;
}
TTestObject& operator= (const char* rhs) { strcpy ( name , rhs ); return *this; }
operator char*() { return name; }
char name[16];
char* vals;
char val;
};
typedef pair<const char*,TTestObject> TMyMapPair;
typedef map<const char*, TTestObject, compareT , KgpAllocator<TMyMapPair> > TMyMap;
typedef TMyMap::iterator TMayMapIterator;
volatile char* obj_name;
TTestObject extern_obj("extr obj"); // глобальный
//----------------------------------------------------------------------------
int main(void)
{
(void)obj_name;
// пустой main 696 байт ( таблица векторов, ctr код)
//мапа на стеке
TMyMap mymap; // +104 байта
// добавляем в мапу запись 0 с неименованным объектом
mymap.insert ( TMyMapPair ("ключ_0", TTestObject() ) ); // + 720 байт (код STL std::map::insert и внутренняя реализация дерева )
// добавляем в мапу запись 1 с неименованным объектом другим способом
mymap["ключ_1"] = extern_obj; // + 392 байт (код STL std::map::operator[] и внутренняя реализация дерева )
// добавляем в мапу запись 2 с именованным объектом
mymap["ключ_2"] = TTestObject("object #2"); // + 128 байт ( конструктор TTestObject(char*) )
// доступ к объекту записей (чтение имени объекта)
obj_name = mymap["ключ_0"]; // + 24 байт
// доступ к объекту записей (чтение имени объекта)
obj_name = mymap["ключ_1"]; // + 8 байт
// доступ к объекту записей (запись имени объекта)
mymap["ключ_1"] = "object #1"; // + 40 байт
// доступ к объекту записей (запись самого объекта)
mymap["ключ_0"] = extern_obj;
// доступ к объекту записей (чтение самого объекта присваивание его другому)
extern_obj = mymap["ключ_1"]; // + 16 байт
// проход по записям
char index = 0;
for ( TMayMapIterator it = mymap.begin(); it != mymap.end(); it++ ) // +24 байт
{
it->second.val = index++;
}
mymap.erase("ключ_0"); // +680 байт
mymap.clear(); // +24 байт
return 0;
}
#include "supstl.h" // inline определение аллокатора пригодного для нас
#include <string.h>
#include <map> // шаблон std::map
using namespace std;
char heap[4*1024]; // кучка для менеджера памяти
void *HeapMalloc( size_t WantedSize ) // наипростейшая реализация
{
static char* ptr = heap;
char* tmp = ptr;
ptr += WantedSize;
return (void*)tmp;
}
void HeapFree( void* pv ) наипростейшая реализация
{
// заглушка
}
class TTestObject // класс тестовых объектов котрые будут засовыватся в мапу
{
public:
TTestObject()
{
vals = new char[4];
strcpy( name , "noname" );
}
TTestObject(const TTestObject& src)
{
vals = new char[4];
strcpy( name , src.name );
memcpy( vals , src.vals , 4 );
val = src.val;
}
TTestObject(const char* name)
{
vals = new char[4];
strcpy( this->name , name );
}
~TTestObject()
{
delete vals;
}
TTestObject& operator= (const char* rhs) { strcpy ( name , rhs ); return *this; }
operator char*() { return name; }
char name[16];
char* vals;
char val;
};
typedef pair<const char*,TTestObject> TMyMapPair;
typedef map<const char*, TTestObject, compareT , KgpAllocator<TMyMapPair> > TMyMap;
typedef TMyMap::iterator TMayMapIterator;
volatile char* obj_name;
TTestObject extern_obj("extr obj"); // глобальный
//----------------------------------------------------------------------------
int main(void)
{
(void)obj_name;
// пустой main 696 байт ( таблица векторов, ctr код)
//мапа на стеке
TMyMap mymap; // +104 байта
// добавляем в мапу запись 0 с неименованным объектом
mymap.insert ( TMyMapPair ("ключ_0", TTestObject() ) ); // + 720 байт (код STL std::map::insert и внутренняя реализация дерева )
// добавляем в мапу запись 1 с неименованным объектом другим способом
mymap["ключ_1"] = extern_obj; // + 392 байт (код STL std::map::operator[] и внутренняя реализация дерева )
// добавляем в мапу запись 2 с именованным объектом
mymap["ключ_2"] = TTestObject("object #2"); // + 128 байт ( конструктор TTestObject(char*) )
// доступ к объекту записей (чтение имени объекта)
obj_name = mymap["ключ_0"]; // + 24 байт
// доступ к объекту записей (чтение имени объекта)
obj_name = mymap["ключ_1"]; // + 8 байт
// доступ к объекту записей (запись имени объекта)
mymap["ключ_1"] = "object #1"; // + 40 байт
// доступ к объекту записей (запись самого объекта)
mymap["ключ_0"] = extern_obj;
// доступ к объекту записей (чтение самого объекта присваивание его другому)
extern_obj = mymap["ключ_1"]; // + 16 байт
// проход по записям
char index = 0;
for ( TMayMapIterator it = mymap.begin(); it != mymap.end(); it++ ) // +24 байт
{
it->second.val = index++;
}
mymap.erase("ключ_0"); // +680 байт
mymap.clear(); // +24 байт
return 0;
}
тут не приведено сожржение хидеров с аллокатором и операторами new и delete
результаты по жирности кода:
пустой main 696 байт
манипуляции с мапой (добавление чтение и тд) - добавилось 1446 байт
удаление и очистка еще 704 байт
тоесть на круг я заплатил приметно 2300 байт за стандартную реализацию map и получил возможность рулить объектами с помощью строковых ключей. Скорость я однако еще не мерял - пожже.
если Вы не используете часть функций то объем будет менше на их код. Похожий тест я делал и для вектора std::vector но там еще проще и компактнее - мапа достаточно сложная штука (в ней реализовано крсно черное дерево) поэтому я решил на ней тестировать.
теперь подведем итоги.
1.компилятор GCC, сборка моя
2. необходимо выключить ключами генерацию кода поддержки исключений и RTTI
3. необходимо поправить скрипт линкера чтобы он выкидывал нафег скции с структурами данный опятьже поддержки исключений
4. написать свой аллокатор для шаблонов STL, стандартный совсем не подходит для эмбеддед. я даже не знаю будет ли он работать - не пробывал
5. переопределить операторы new delete
6. подсунуть операторам new delete функции выдедения и освобождения из подходящего менеджера памяти
8. Вы можете убедится что такой код замкнутый - не пользуется ничем извне - тоесть никаких загадочных 'unresolved symbol _sbrk_r_' быть не может - мы все сами определили, если не так то чтото неправильно линкуется или еще чтото.
7. наслаждатся красивым кодом .
скорее всего гденибудь чтонибудm вылезет - например std::string использовать "из коробки" не получилось - он уже есть специфицированный параметром типа char шаблон basic_string<charT, traits, Alloc> с заданным по умолчанию аллокатором который нам никак не подходит, а вот сделать свой my_string как специфисированый basic_string<charT, traits, Alloc> со своим аллокатором можно - получим такой же функционал. но это мелочи. грабли наверно в переди

Хотелось бы обсудить предмет. Как дела обстоят у коллег пользующих проприетарные пакеты типа IAR и тд?
прошу прощения за длинность - но короше ужать не смог.
ps. люди которые выдумали С++ и шаблоны очень любили тех для кого они это делали (тоесть нас), проблемв в том что не всем дано познать эту любовь!