Цитата
Чем же так конструкторы не угодили? Это просто удобно и безопасно - автоматическая инициализация при создании объектов. А с отдельным init'ом обычное дело забыть сунуть туда инициализатор (люди постоянно ошибаются ).
Да, это удобно и на PC я их использую во всю. а вот конкретно на моей платформе с ними проблеммы...
Кога обьект размещен в статической памяти(у меня это только bss забиваемый при старте нулями), gcc создает:
1. константную таблицу init_array с указателями на функции(те самые конструкторы/инициализаторы указателей на vtables). Ессно, если в классе есть виртуальные функции, то GCC по любом создаст конструктор либо дополнит существующий кодом инициализации указателя на vtable
2. саму констнтую vtable
пример
Код
class A{
public:
virtual int a()=0;
};
class B :public A{
public:
B(){z=0x12345;};
int a(){return z++;};
private:
int z;
};
B bcc;
Код
Disassembly of section .text:
00008004 <_GLOBAL__sub_I_bcc>:
8004: f240 034c movw r3, #76; 0x4c
8008: f242 3245 movw r2, #9029; 0x2345
800c: 4903 ldr r1, [pc, #12]; (801c <_GLOBAL__sub_I_bcc+0x18>)
800e: f2c0 0301 movt r3, #1
8012: f2c0 0201 movt r2, #1
8016: e883 0006 stmia.w r3, {r1, r2}
801a: 4770 bx lr
801c: 00008038 andeq r8, r0, r8, lsr r0
00008020 <_ZN1B1aEv>:
8020: 6843 ldr r3, [r0, #4]
8022: 1c5a adds r2, r3, #1
8024: 6042 str r2, [r0, #4]
8026: 4618 mov r0, r3
8028: 4770 bx lr
802a: bf00 nop
Disassembly of section .rodata:
00008030 <_ZTV1B>:
8038: 00008021 andeq r8, r0, r1, lsr #32
Disassembly of section .init_array:
00010048 <__data_start-0x4>:
10048: 00008005 andeq r8, r0, r5
В итоге, функции по указателям в .init_array должны буть когда-то вызваны до использования обьекта.
НО. Некоторые обьекты нужно проинициализировать сразу после ресета(до старта ОС).
Некоторые после старта ОС но до старта конкретных драйверов периферии. почему - потому что в их конструкторах есть вызовы функций ОС, если их вызвать до старта ОС - будет креш.
А некоторые после старта всех драйверов и до выполнения первого юзерского треда(приложения). Аналогично - там могут быть обращения к дровам, выделение системных ресурсов(создание тредов, мютексов итд).
В итоге как мне знать когда вызвать ту или иную функцию(конструктор) из init_array ?
Потому я пошел по простому пути - отказался от конструкторов; обрабатываю init_array(туда компиллер кидает код инициализации указателей на vtable) еще до старта системы, что есть безопасно, тк в конструкторах нету системозависимого кода; А уже инициализацию обьектов провожу явно в нужном месте в нужное время посредством вызова init();
Думаю понятно изложил

Цитата
Необходимость в множественном наследовании зависит не от объёмов программы, а от её концепции и задач. Например, когда надо объединить функционал двух объектов, удобно отнаследоваться от них обоих. Кода это не добавляет.
Ну мож иногда и надо, я пока применению ему не нашел. а про 256кб упомянул с намеком на относительную простоту програм с данным обьемом

Цитата
Не, обработка исключений точно не катит в embedded - это самый тяжёлый механизм С++. Там при выбросе исключения происходит так называемая "раскрутка стека", это длительный процесс со слабопредсказуемыми времянками и значительным потреблением ресурсов - процессорного времени.
При выбросе исключения явно(путем возврата кода ошибки) тоже происходит раскрутка стека - мы же вернемся в самую первую функцию по цепочке из кодов ошибок: типа ошибка вылезла в недрах uartRead, выходим uartRead->SysCall->GsmModemMuxRead->GsmModemCommand->GprsWrapper->TermRead->main...
Хотя с вами соглашусь, "обработка исключений точно не катит в embedded"
Цитата
Полезная фишка там есть - rvalue reference (обозначается оператором &&). Позволяет избежать ненужного копирования в ряде случаев.
Я привык руцями управлять перегонкой данных, ссылки использую в очень редких случаях, в основном только указатели. при паре сотен байт стека, имхо, это дело надо контролировать самому...
Цитата
При embedded программировании надо, для начала, понять, как устроен конкретный компилятор и его startup файл
Привязыватся к компилятору - плохая идея. Мой код дожен компилится любым нормальным компилятором и работать.
Компилятор для меня - это именно КОМПИЛЯТОР, тобышь генератор кода, а не набор библиотек и прочей несовместимой хрени.
startup у меня свой равно как и ОС. Там и MPU задействован, и куча всяких вкусностей типа lock-free фишек итп, все это не совместимо ни с стандартной библиотекой ни с стартапами(которые тоже являются частью стдлиб), но зато очень удобно в ислопользовании.
Цитата
где и в каком порядке что должно инициализироваться
как я уже писал - компилятор никак не может знать что за чем должно инициализироватся, в сучаи одновременного создания обьектов,тобышь в статической памяыти, ни я не могу быть 100% уверен,что компиллер вдруг запустит конструктор не там, где нужно.
Если обьект создается в стеке - тогда да, там можно запросто юзать конструкторы/деструкторы,да и выделение глобальных системных ресурсов для обьекта в стеке конкретного треда/прерывания не целесобразно.