Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как писать на С++ при создание приложений под ARM
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2, 3, 4
zltigo
QUOTE (haker_fox @ Jun 22 2011, 14:30) *
Я дальше ....

Уж больно у меня стимул был велик - в 80-е годы заполучить ПЕРСОНАЛЬНЫЙ!! КОМПЬЮТЕР! дома!!! По этой причине моей первой программой на ASM 8088 стал BIOS sm.gif. Ох, помнится, и попотел я.... А еще он мог, как с родными работать с 800K дискетами sm.gif sm.gif.
brag
Пописал немного кода на С++ использованием динамического полиморфизма и шаблонов...
компиллер юзал gcc-4.6.1. всякую динамическую дрянь, rtti ессно поотключал.
Про конструкторы и деструкторы правда пришлось забыть, тк память под обьект обычно выделяется статически(читай, во время ресета контроллера),
а инициализировать его можно аж после загрузки какой-то части ОС, при чем для разных классов это может быть по разному (на пример гуи должен стартовать после драйверов итп).
Хотя завести init() вместо конструктора для каждого класса и вызвать в нужном месте для нужного обьекта не составляет особого труда.

Ради интереса взял кусок своей старой чисто-сишной гуи-либы под 128х64 монохромный дисплей и переписал на С++.
В сишной версии рулили всем указатели на таблицы функций(таких как draw,keypressed,...)
После переноса этого на плюсы, все было заменено на классы с виртуальными ф-ями и рулить стали указатели на обьекты.
Хохма - асм-код остался Идентичен по размеру и инструкциям, только адреса поменялись! А исходник на плюсах стал меньше и гораздо красивее.
Оказывается, я уже давно юзаю оо, но все руцями sm.gif

Далее перевел на плюсы с использованием шаблонов thread-safe queue, сишная версия которого пестрела макросами для реализации поддержки разных типов данных(время на написание этих макросов ушо больше, чем бы я писал отдельные функции для каждого типа sm.gif)
Тут сгенерированный код остался Полностью Идентичен сишной версии sm.gif

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

Еще
От множественного наследования отказался сразу. Имхо,для 256кб флеша оно не надо, да и во многих оо-языках его нету
Обработку исключений не пробовал. по идее, если ее правильно реализовать в компиляторе - производительность должна повысится, в свравнении с техникой возврата кода ошибки, неговоря уже о красоте кода( куча дефайнов с кодами ошибок, куча if,goto, путаница где вызвать printf, где нет итп). Хотя оно не избавляет от проблем выделения/освобождения ресурсов: выделили 10 ресурсов, 11й не вышло - надо освобождать все обратно, а обработчик знать не может что там выделено и сколько, особенно,если там куча вложенных функций, которые тоже что-то выделяли. в итоге городить if/goto всеравно прийдется...
Перегрузка операторов и потоков пока вроде не нужна. не нашел места применения. думалось заюзать перегрузку +-=/*% для работы с большими числами(скажем в 2048бит, нужно для таких алгоритмов, как RSA,DSA,...), но очередность там не однозначная получается,многое зависит от компилятора(особенно он любит пихат оператор = там,где не надо), в итоге пожирается память, вызывается довольно тяжелые функции лишний раз, а красота кода не сильно улучшается.
на пример а=(b*c)%m
у меня:
mul(t,b,c);
mod(a,t,m);
а иногда, если размер a больше чем размер b+c
mul(a,b,c);
mod(a,a,m);

у gcc
mul(t,b,c);
mod(t1,t,m);
equ(a,t1,m);
а иногда еще хуже, когда несколько вложенных скобок...

по поводу C++11, имхо для embedded ничего полезного. кроме как инициализация отдельных полей структур по имени(уже давно есть в C, в C++ никак не перекочует). Еще в c++ нету VLA (variable length array) - создние в стеке массива неконстантной длины.в c99 это есть и прекрасно работает(при аккуратном использовании) - экономит память.
777777
Цитата(dxp @ Jun 20 2011, 11:32) *
  1. Почему вы ставите знак равенства между С++ и ООП?

Потому что С++ - это язык ООП. Всё остальное, что в нем есть - это (ненужные) навороты, главная его особенность - объектная ориентированность.

Цитата(andrewlekar @ Jun 22 2011, 13:00) *
Что-то я не слыхал, чтобы в С++ где-то резко сократились ошибки памяти. Наоборот, прибавилось ошибок. Утечки памяти - фирменная фича неуправляемого С++.

О как! Сильно сказано. Только вот как раз ООП и придумано для того, чтобы можно было не сократить, а полностью ликвидировать утечки памяти - просто нужно тщательно продумать структуру программы и распределение объектов. И выделять память в конструкторе объекта, а удалять в деструкторе. Тогда их не будте никогда. Разве что у тех программистов, которые так и не поняли смысл объектно-ориентированного программирования.

Цитата(andrewlekar @ Jun 22 2011, 11:38) *
С++ позволяет множественное наследование, вот и упомянул. Просто перечисление объективных недостатков языка.

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

Цитата(andrewlekar @ Jun 22 2011, 11:38) *
Адресная арифметика - это также и чисто микроконтроллерная область. И хоть вы на чём пишите, залезать в неё придётся.

Зачем? Вот убей не пойму, почему когда пишут прикладную программу для обычного компьютера, она не требуется, а в микроконтроллерах непременно нужна?

Цитата(andrewlekar @ Jun 22 2011, 11:38) *
А неаккуратная работа с памятью более вероятна как раз в С++, потому что там куда чаще встречается динамическое размещение объектов.

Динамическое размещение объектов встречается везде, но в C нет средств для аккуратной работы с ними, а в C++ есть.

Цитата(andrewlekar @ Jun 22 2011, 11:38) *
На С++ голову уж слишком сильно нужно включать.

Да, это серьезный недостаток! На С можно писать и без головы, только... не хотелось бы мне пользоваться таким устройством.
dxp
Цитата(brag @ Sep 22 2011, 05:05) *
Про конструкторы и деструкторы правда пришлось забыть, тк память под обьект обычно выделяется статически(читай, во время ресета контроллера),
а инициализировать его можно аж после загрузки какой-то части ОС, при чем для разных классов это может быть по разному (на пример гуи должен стартовать после драйверов итп).
Хотя завести init() вместо конструктора для каждого класса и вызвать в нужном месте для нужного обьекта не составляет особого труда.

Чем же так конструкторы не угодили? Это просто удобно и безопасно - автоматическая инициализация при создании объектов. А с отдельным init'ом обычное дело забыть сунуть туда инициализатор (люди постоянно ошибаются sm.gif ).

Цитата(brag @ Sep 22 2011, 05:05) *
От множественного наследования отказался сразу. Имхо,для 256кб флеша оно не надо,

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

Цитата(brag @ Sep 22 2011, 05:05) *
Обработку исключений не пробовал. по идее, если ее правильно реализовать в компиляторе - производительность должна повысится, в свравнении с техникой возврата кода ошибки, неговоря уже о красоте кода( куча дефайнов с кодами ошибок, куча if,goto, путаница где вызвать printf, где нет итп).

Не, обработка исключений точно не катит в embedded - это самый тяжёлый механизм С++. Там при выбросе исключения происходит так называемая "раскрутка стека", это длительный процесс со слабопредсказуемыми времянками и значительным потреблением ресурсов - процессорного времени.

Цитата(brag @ Sep 22 2011, 05:05) *
по поводу C++11, имхо для embedded ничего полезного.

Полезная фишка там есть - rvalue reference (обозначается оператором &&). Позволяет избежать ненужного копирования в ряде случаев.

Цитата(777777 @ Sep 22 2011, 11:49) *
Потому что С++ - это язык ООП. Всё остальное, что в нем есть - это (ненужные) навороты, главная его особенность - объектная ориентированность.

Правда? Т.е. сами по себе классы нафиг не нужны? И перегрузка имён функций/операторов не нужна? И возможность объявлять объекты в любом месте программы не нужна? И наследование (без виртуальных функций) не нужно? И шаблоны не нужны?

Да будет вам известно, что исходно С++ появился именно как объектный язык, и ОО составляющая была в него добавлена значительно (годы) позже.

С++ никогда не был чистым ОО языком - ООП в нём - это лишь один (и не очень обширный) из его аспектов.

Либо (если не согласны в вышеперечисленным) вы не вполне понимаете, что такое ООП.
sergeeff
Код
Про конструкторы и деструкторы правда пришлось забыть, тк память под обьект обычно выделяется статически(читай, во время ресета контроллера)


При embedded программировании надо, для начала, понять, как устроен конкретный компилятор и его startup файл, где и в каком порядке что должно инициализироваться. Тогда вы будете управлять процессом проектирования, а не идти на поводу "левых" demo проектов.
brag
Цитата
Чем же так конструкторы не угодили? Это просто удобно и безопасно - автоматическая инициализация при создании объектов. А с отдельным 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();
Думаю понятно изложил wink.gif

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

Ну мож иногда и надо, я пока применению ему не нашел. а про 256кб упомянул с намеком на относительную простоту програм с данным обьемом sm.gif

Цитата
Не, обработка исключений точно не катит в embedded - это самый тяжёлый механизм С++. Там при выбросе исключения происходит так называемая "раскрутка стека", это длительный процесс со слабопредсказуемыми времянками и значительным потреблением ресурсов - процессорного времени.

При выбросе исключения явно(путем возврата кода ошибки) тоже происходит раскрутка стека - мы же вернемся в самую первую функцию по цепочке из кодов ошибок: типа ошибка вылезла в недрах uartRead, выходим uartRead->SysCall->GsmModemMuxRead->GsmModemCommand->GprsWrapper->TermRead->main...
Хотя с вами соглашусь, "обработка исключений точно не катит в embedded"

Цитата
Полезная фишка там есть - rvalue reference (обозначается оператором &&). Позволяет избежать ненужного копирования в ряде случаев.

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

Цитата
При embedded программировании надо, для начала, понять, как устроен конкретный компилятор и его startup файл

Привязыватся к компилятору - плохая идея. Мой код дожен компилится любым нормальным компилятором и работать.
Компилятор для меня - это именно КОМПИЛЯТОР, тобышь генератор кода, а не набор библиотек и прочей несовместимой хрени.
startup у меня свой равно как и ОС. Там и MPU задействован, и куча всяких вкусностей типа lock-free фишек итп, все это не совместимо ни с стандартной библиотекой ни с стартапами(которые тоже являются частью стдлиб), но зато очень удобно в ислопользовании.

Цитата
где и в каком порядке что должно инициализироваться

как я уже писал - компилятор никак не может знать что за чем должно инициализироватся, в сучаи одновременного создания обьектов,тобышь в статической памяыти, ни я не могу быть 100% уверен,что компиллер вдруг запустит конструктор не там, где нужно.
Если обьект создается в стеке - тогда да, там можно запросто юзать конструкторы/деструкторы,да и выделение глобальных системных ресурсов для обьекта в стеке конкретного треда/прерывания не целесобразно.
ReAl
Насколько я понимаю, вот тут конструктор object будет вызван в момент первого вызова GetObject(), а не ещё до main() в порядке, определяемом линковкой файлов.
Код
Object& GetObject()
{
    static Object object;
    return object;
}

Только радости от этого по сравнению с object.init() мало -- добавляется кусочек кода в каждом использовании, функции object при вызове GetObject().send() не проинлайнятся, ...
brag
Цитата
Насколько я понимаю, вот тут конструктор object будет вызван в момент первого вызова GetObject(), а не ещё до main() в порядке, определяемом линковкой файлов.

Зависит от компилятора... счас проверим на GCC
Цитата
Только радости от этого по сравнению с object.init() мало -- добавляется кусочек кода в каждом использовании, функции object при вызове GetObject().send() не проинлайнятся, ...

по моему init() гораздо красивее этой конструкции...возможности языка нужно применять не ради самих возможностей, а для дела(пользы). благо, Страуструп заложил в язык 2 важные вещи:
1. Он должен быть пригоден для системного программирования (те в окружении неизвестному компилятору,не зависящему одно от другого)
2. Мы не должны платить за то, чего не используем. не конструктора - не паримся с его поддержкой, нет new/delete - не паримся с поддержкой динамики итд...
dxp
Цитата(brag @ Sep 22 2011, 19:11) *
НО. Некоторые обьекты нужно проинициализировать сразу после ресета(до старта ОС).
Некоторые после старта ОС но до старта конкретных драйверов периферии. почему - потому что в их конструкторах есть вызовы функций ОС, если их вызвать до старта ОС - будет креш.
А некоторые после старта всех драйверов и до выполнения первого юзерского треда(приложения). Аналогично - там могут быть обращения к дровам, выделение системных ресурсов(создание тредов, мютексов итд).
В итоге как мне знать когда вызвать ту или иную функцию(конструктор) из init_array ?

Ну, объекты, которые "завязаны" на аппаратуру, организовывать соответствующим образом, но все подряд-то ни к чему под одну гребёнку гладить. Большинство объектов в программе, как правило, не привязаны к аппаратуре, для них можно спокойно использовать конструкторы без ограничений.

Цитата(brag @ Sep 22 2011, 19:11) *
Ну мож иногда и надо, я пока применению ему не нашел. а про 256кб упомянул с намеком на относительную простоту програм с данным обьемом sm.gif

256 кБ - весьма приличный объём, если писать код своими руками (а не забить его библиотечными функциями). А по меркам embedded так даже и нифига себе. sm.gif

Цитата(brag @ Sep 22 2011, 19:11) *
При выбросе исключения явно(путем возврата кода ошибки) тоже происходит раскрутка стека - мы же вернемся в самую первую функцию по цепочке из кодов ошибок: типа ошибка вылезла в недрах uartRead, выходим uartRead->SysCall->GsmModemMuxRead->GsmModemCommand->GprsWrapper->TermRead->main...

Ну, некоторое сходство есть, но при исключениях там генерируется гора служебного кода, что тащит неслабый оверхед, при организации программы через возврат кода ошибки всё получается на пару порядков скромнее (хотя и не так удобно и красиво внешне).

Цитата(brag @ Sep 22 2011, 19:11) *
Я привык руцями управлять перегонкой данных, ссылки использую в очень редких случаях, в основном только указатели. при паре сотен байт стека, имхо, это дело надо контролировать самому...

Rvalue reference - это совсем не те ссылки, которые в нынешнем С++. Это совсем другая штука. sm.gif Обычные ссылки, кстати, тоже, имхо, зря обделяете вниманием - они в ряде случаев дают более простую семантику и более безопасный код.



Цитата(brag @ Sep 22 2011, 19:47) *
по моему init() гораздо красивее этой конструкции...

init() обладает одним существенным недостатком - нужно не забывать корректировать его при изменениях в совсем других частях программы. В общем, это в значительной степени отказ от идеи абстракции (и инкапсуляции) данных в виде законченных объектов, т.е. в некотором роде даунгрейд в С. По мере роста сложности программ, это не добавляет радости.
brag
Цитата
Object& GetObject()
{
static Object object;
return object;
}

Хе, еще хуже. Компиллер создает в bss переменную-флаг был ли создан обьект или нет.
Далее он проверяет этот флаг. если он не установлен - вызывает функцию __cxa_guard_acquire, которая должна заблокировать этот обьект(типа открыть мютекс) и далее запускает конструктор. потом вызывает __cxa_guard_release и возвращает указатель/ссылку на обьект. sm.gif
Ессно тело этих функций лежит на нас. И ессно это гемор, проще вызвать init(...) в нужном месте і все
dxp
Цитата(brag @ Sep 22 2011, 20:13) *
Хе, еще хуже. Компиллер создает в bss переменную-флаг был ли создан обьект или нет.
Далее он проверяет этот флаг. если он не установлен - вызывает функцию __cxa_guard_acquire, которая должна заблокировать этот обьект(типа открыть мютекс) и далее запускает конструктор. потом вызывает __cxa_guard_release и возвращает указатель/ссылку на обьект. sm.gif

Естественно, это стандартная реализация инициализации статических объектов функции (а блокировка зависит от того thread safe этот код или нет).

Цитата(brag @ Sep 22 2011, 20:13) *
Ессно тело этих функций лежит на нас.

Это почему это? Компилятор делает это самостоятельно и совершенно прозрачно от программиста, в этом и преимущество.

Цитата(brag @ Sep 22 2011, 20:13) *
И ессно это гемор, проще вызвать init(...) в нужном месте і все

Вообще-то, приведённый код - это реализация паттерна Singleton. Очень хорошая штука к месте. Применяется, главным образом, для борьбы с зависимостью от порядка компиляции объектов. Большого оверхеда не тянет.
brag
Цитата
Большинство объектов в программе, как правило, не привязаны к аппаратуре, для них можно спокойно использовать конструкторы без ограничений.

обьекты, выделены статически, в той или иной мере зависят от состояния ОС, если в них используются ее функции. а большинсво они такие и есть(тк глобальный обьект - должен быть thread-safe обьект) потому так и получается, что в embedded-проекте все оно под одну гребенку для статика. выделять под каждый кусок проекта отдельные секции тоже не в кайф и не всегда катит - у тредов есть shared-memory...

Цитата
256 кБ - весьма приличный объём, если писать код своими руками (а не забить его библиотечными функциями). А по меркам embedded так даже и нифига себе.

да ну. TwoFish,RSA-2048,ECDSA,sha-256,дрова(включая usb-msc,usb-cdc,transflash,всякие там верхнего уровня прибамбасики типа акселерометра с простенькими dsp-алго),всякие там парсеры и немного полезного(не служебного) кода - 110кб сожрало. при чем все ручками, ни единой библиотечной функции,каждый алго вылизивался руками для достижения требуемых условий по производительности. и это нету еще gui с кучей текста(пусть даже на одном инглише,не говоря о 2-3 языках)

Цитата
Rvalue reference - это совсем не те ссылки, которые в нынешнем С++. Это совсем другая штука. Обычные ссылки, кстати, тоже, имхо, зря обделяете вниманием - они в ряде случаев дают более простую семантику и более безопасный код.

разеремся,как поддержка нормальная появится wink.gif

Цитата
init() обладает одним существенным недостатком - нужно не забывать корректировать его при изменениях в совсем других частях программы.

зачем? раз его реализовал, равно как и конструктор и вызываешь где нужно.
Цитата
В общем, это в значительной степени отказ от идеи абстракции (и инкапсуляции) данных в виде законченных объектов, т.е. в некотором роде даунгрейд в С. По мере роста сложности программ, это не добавляет радости.

немного да, помнить все же про обьект(но никак не про внутренности класса,что уже не трогает инкапсуляцию) нужно будет. и вызвать init перед первым его использованием. в embedded надо помніть о гораздо более важных и запутанных вещах, что init никак проблем не создаст. а если его забыть, то прога ляжет сразу и ошибка найдется легко.
sergeeff
Цитата(brag @ Sep 22 2011, 16:32) *
init никак проблем не создаст. а если его забыть, то прога ляжет сразу и ошибка найдется легко.


Вовсе не обязательно. У нас в одном проекте через месяц программист нашел эту ошибку. А до этого все как-то жило себе и ничего.
brag
Цитата
Естественно, это стандартная реализация инициализации статических объектов функции (а блокировка зависит от того thread safe этот код или нет).

конечно thread-safe, иначе запарки с конструкторами небыло бы, вернее с необходимостю явного вызова конструктора, переименованного в init(..);.

Цитата
Это почему это? Компилятор делает это самостоятельно и совершенно прозрачно от программиста, в этом и преимущество.

и от куда он знает как у нас реализована блокировак и как ею пользоватся? по моему он никак не догадывается, что у меня есть функции CreateKernelObject(MUTEX_TYPE),OpenMutex(ko),CloseMutex(ko) итд...



Код
Вовсе не обязательно. У нас в одном проекте через месяц программист нашел эту ошибку. А до этого все как-то жило себе и ничего.

Заполните .bss каким-нибдь криптографическим рандомом :D (кроме шуток) и бага вылезет моментально sm.gif

Цитата
Применяется, главным образом, для борьбы с зависимостью от порядка компиляции объектов. Большого оверхеда не тянет.

Чет не вьехал.. что за зависимость от порядка компиляции обьектов и когда она возникает?
Dima_G
Компилятор ничего не знает о потоках, процессах и тд!
Ни PC, ни эмбеддед. Соответственно, никаких блокировок не должен использовать.
Singleton - удобный способ создания одного(И только одного) объекта класса. Если на пальцах - при первом вызове "псевдоконструктора" происходит создание объекта, при последующих - возвращается ссылка на первый объект.
Помимо этого у него ест еще одно полезное свойство - не нужно хранить указатель на объект. Мы его получаем по имени класса.

По поводу порядка инициализации. Порядок инициализации объектов определен лишь в пределах одной единицы трансляции. Соответственно, имя два cpp файла нельзя сказать, статические переменные какого файла будут проинициализированны первыми.
Я с этим борюсь так: у каждого сервиса есть 4 унаследованных метода: Init, Run, Stop, Done. Рассылкой multcast сообщений я их по очереди вызываю. Те сначала вызываются все методы Init, потом все методы Run и тд.
Это вызывается лишь в одном месте программы, тем самым избегаю случая "забывания вызывания Init"

Вот моя реализация синглтона
CODE
///@class TClSingleton
///@brief Use access to object instance.
///After first call Instance() method, create instance of object.
///All next call Instance() method will return pointer to first object
///Typical use:
/// <pre>
///@code
///class SignleObject: public TClSigneton<SingleObject>
///{
/// friend class TClSigneton<SingleObject>;
/// . . . . .
/// protected:
/// SignleObject();
///}
///......
///SignleObject* pclObject_ = SignleObject::Instance(); // Will be created object, or return pointer on early created oblect
///......
///@endcode
/// </pre>
template <class ClSignleObject>
class TClSingleton
{
public:
/// Static method. Will be used in inheritor
/// @return Pointer to object instance
inline static ClSignleObject* Instance();

protected:
/// Protected default constructor
TClSingleton(){}
};

///@brief Realization of instance() method
template <class ClSignleObject>
inline ClSignleObject* TClSingleton<ClSignleObject>::Instance()
{
TClCriticalSection<true> clCS_;

static ClSignleObject* pclInstance_s = new ClSignleObject();
return pclInstance_s;
}
brag
Цитата
Компилятор ничего не знает о потоках, процессах и тд!
Ни PC, ни эмбеддед. Соответственно, никаких блокировок не должен использовать.

Qt+gcc еще как знает sm.gif

Цитата
Я с этим борюсь так: у каждого сервиса есть 4 унаследованных метода: Init, Run, Stop, Done. Рассылкой multcast сообщений я их по очереди вызываю. Те сначала вызываются все методы Init, потом все методы Run и тд.
Это вызывается лишь в одном месте программы, тем самым избегаю случая "забывания вызывания Init"

зависит от конкретной реализации. в моем случае проще,безопаснее вызвать конструктор явно в нужном месте, чем городить какие-то хитрые конструкции только ради саих этих конструкций и авто-вызова конструктора. забыть вызвать (псевдо)конструктор довольно сложно, тк он асоциирован с подключением конкретного модуля(если я юзаю usb-msc, как же я могу забыть его проинициализироват? а он сам в свою очередь унаследован от usb,и других классов выше, и сам вызовет нужные псевдо-конструкторы по иерархии)
Dima_G
Цитата(brag @ Sep 22 2011, 22:05) *
Qt+gcc еще как знает sm.gif

Лично налетал на гонки в синглтоне. Компилятор gcc.
Возможно, я просто не умею его готовить.. Но - осадочек остался. Сейчас только критическая секция.

Цитата(brag @ Sep 22 2011, 22:05) *
зависит от конкретной реализации.

Я бы сказал - зависит от подхода. sm.gif
sergeeff
Цитата(brag @ Sep 22 2011, 18:05) *
Qt+gcc еще как знает sm.gif


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


А кто мешает в этом самом нужном месте вызвать:

Код
Class *pAAA = new AAA;


Вызывается сам конструктор, а не какой-то там Init().
777777
Цитата(dxp @ Sep 22 2011, 11:25) *
Правда? Т.е. сами по себе классы нафиг не нужны? И перегрузка имён функций/операторов не нужна? И возможность объявлять объекты в любом месте программы не нужна? И наследование (без виртуальных функций) не нужно? И шаблоны не нужны?

Что значит "не нужны"? Что значит "сами по себе"? (почти) всё перечисленное - свойства ООП. Поскольку все это есть в С++, то он является объектно-ориентированным языком.

Цитата(dxp @ Sep 22 2011, 11:25) *
Да будет вам известно, что исходно С++ появился именно как объектный язык, и ОО составляющая была в него добавлена значительно (годы) позже.

Мне кажется при построении этого предложения вы где-то допустиои опечатку.

Цитата(dxp @ Sep 22 2011, 11:25) *
С++ никогда не был чистым ОО языком - ООП в нём - это лишь один (и не очень обширный) из его аспектов.

Изначально он назывался "Си с классами". Потом он получил название С++, а постепенно в него напихали всего, что было модно на текущем этапе развития программирования. Поэтому трудно говорить о том, был ли он когда-нибудь "чистым" ОО языком весьма проблематично.

Цитата(dxp @ Sep 22 2011, 11:25) *
Либо (если не согласны в вышеперечисленным) вы не вполне понимаете, что такое ООП.

Я понимаю, фаллометрия очень важна для посетителей этого форума.
brag
Цитата
Лично налетал на гонки в синглтоне. Компилятор gcc.
Возможно, я просто не умею его готовить.. Но - осадочек остался. Сейчас только критическая секция.

посему я предпочитаю ручной контроль thread-safety

Цитата
Class *pAAA = new AAA;
Вызывается сам конструктор, а не какой-то там Init().

а реализовывать оператор new кто будет? и какими средствами и зачем, на платформе с 64кб оперативки, половина которой ушла под буфферы и стеки...
brag
еще вопрос по поводу реюза кода. Как, на пример, в gcc, сделать так, чтобы без модификации исходного кода пихать код и данные в разные секции?
На пример, есть такой класс
Код
class Twofish{
public:
    void Key(const U32 *key32);
    void Encrypt(U32 *oblk32,const U32 *iblk32,U32 nblocks,U32 *iv32);
    void Decrypt(U32 *oblk32,const U32 *iblk32,U32 nblocks,U32 *iv32);
private:
    U32 sboxKey[TWF_KEY_BITS/64];
    struct{
        U32 inWhiten[TWF_BLOCK_BITS/32];   // input/output whitening
        U32 outWhiten[TWF_BLOCK_BITS/32];
        U32 round[2*TWF_ROUNDS];  // round subkeys
    }subKeys;
};

Нужно, его так заточить, чтобы разные экземпляры его обьектов были в разных секциях...

скажем есть в одном файле
Twofish twf1;
в другом
Twofish twf2;

надо, чтобы :
код twf1 лежал в секции .text
данные twf1 лежали в секции .bss
код twf2 лежал в секции .text1
данные twf2 лежали в секции .kbss2
при чем, с возможностью наследования
AHTOXA
Цитата(brag @ Sep 22 2011, 23:45) *
Нужно, его так заточить, чтобы разные экземпляры его обьектов были в разных секциях...

-fdata-sections?
brag
а код? -ffunction-sections , а потом это все вручную собирать в линкер-скрипте...проще уж хедеры править
brag
Реализовал через манипуляцию ld -r, линкер-скрипты, objcopy -G
Dima_G
Цитата(brag @ Sep 22 2011, 23:09) *
а реализовывать оператор new кто будет? и какими средствами и зачем, на платформе с 64кб оперативки, половина которой ушла под буфферы и стеки...

Почитайте про "Placement new". Это прояснит многие вопросы, в том числе и про выделение в разных секциях
andrewlekar
Цитата(777777 @ Sep 22 2011, 10:49) *
О как! Сильно сказано. Только вот как раз ООП и придумано для того, чтобы можно было не сократить, а полностью ликвидировать утечки памяти - просто нужно тщательно продумать структуру программы и распределение объектов. И выделять память в конструкторе объекта, а удалять в деструкторе. Тогда их не будте никогда. Разве что у тех программистов, которые так и не поняли смысл объектно-ориентированного программирования.

Ах, оставьте свой религиозный пыл для неофитов. sm.gif

Цитата(777777 @ Sep 22 2011, 10:49) *
То есть если в некоем языке есть фича которую вы не понимаете или с которой у вас когда-то были проблемы - то это плохой язык. Вот тот у которого нет такой фичи - хороший.

А теперь прокомментируйте, почему в более современных Java и C# множественное наследование вырезано.

Цитата(777777 @ Sep 22 2011, 10:49) *
Зачем? Вот убей не пойму, почему когда пишут прикладную программу для обычного компьютера, она не требуется, а в микроконтроллерах непременно нужна?

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

Цитата(777777 @ Sep 22 2011, 10:49) *
Динамическое размещение объектов встречается везде, но в C нет средств для аккуратной работы с ними, а в C++ есть.

Нет не везде. У меня в коде не было динамического размещения объектов, пока не пришлось туда запихать lwIP.

Цитата(777777 @ Sep 22 2011, 10:49) *
Да, это серьезный недостаток! На С можно писать и без головы, только... не хотелось бы мне пользоваться таким устройством.

Передергиваете, батенька. Есть такое понятие, как сложность языка. Проще говоря, сколько дров вы наломаете, прежде чем на нем что-то напишете и сколько денег потеряете, разбираясь с багами во время работы готового кода. У C++ сложность, на мой взгляд, самая высокая из современных языков. Даже хаскелл уступает в этом плане.
dxp
Цитата(777777 @ Sep 22 2011, 22:40) *
Что значит "не нужны"? Что значит "сами по себе"? (почти) всё перечисленное - свойства ООП. Поскольку все это есть в С++, то он является объектно-ориентированным языком.

Как и предполагалось, вы неверно понимаете термин "объектно-ориентированный". Для вас класс С++ - уже ОО, а это не так. ООП - это когда программа построена на основе полиморфного поведения объектов, т.е. когда явно присутствует иерархия классов с виртуальными функциями - методами. Именно это и только это в С++ является объектно-ориентированным подходом. Просто классы даже с наследованием, но без виртуальных функций, не несут ООП, это обычный объектный подход.

Цитата(777777 @ Sep 22 2011, 22:40) *
Я понимаю, фаллометрия очень важна для посетителей этого форума.

С этим вы к себе обратитесь.
777777
Цитата(andrewlekar @ Sep 23 2011, 08:49) *
Ах, оставьте свой религиозный пыл для неофитов. sm.gif

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

Цитата(andrewlekar @ Sep 23 2011, 08:49) *
Потому что специфика применения микроконтроллеров, ограниченность ресурсов, как правило отсутствие виртуальной памяти, нехватка времени и людей. Если у вас со всем этим проблем не наблюдается, так можете без адресной арифметики писать код.

Я надеялся увидеть конкретный пример.

Цитата(andrewlekar @ Sep 23 2011, 08:49) *
Передергиваете, батенька. Есть такое понятие, как сложность языка. Проще говоря, сколько дров вы наломаете, прежде чем на нем что-то напишете и сколько денег потеряете, разбираясь с багами во время работы готового кода. У C++ сложность, на мой взгляд, самая высокая из современных языков. Даже хаскелл уступает в этом плане.

Да, здесь вы конечно правы. Но самолетом управлять тоже сложно, но несмотря на это никто их за это не критикует и не требуют запретить.


Цитата(dxp @ Sep 23 2011, 08:50) *
Как и предполагалось, вы неверно понимаете термин "объектно-ориентированный". Для вас класс С++ - уже ОО, а это не так. ООП - это когда программа построена на основе полиморфного поведения объектов, т.е. когда явно присутствует иерархия классов с виртуальными функциями - методами. Именно это и только это в С++ является объектно-ориентированным подходом. Просто классы даже с наследованием, но без виртуальных функций, не несут ООП, это обычный объектный подход.

Во-первых, я нигде не писал, что язык с классами - уже ОО.

Во-вторых, я даже не представляю где вы выкопали такое определение. Обязательными составными частями ОО всегда считались инкапсуляция, наследование, полиморфизм. Все они есть в С++, о чем еще может быть спор? Или если некая конкретная программа не использует полиморфизм, то она уже не объектно-ориентированная? Но речь вроде бы о языке, а не о программах.

Наконец, последние слова меня привели в полное замешательство: "...без виртуальных функций, не несут ООП, это обычный объектный подход". Это не опечатка? ООП и "объектный подход" чем-то отличаются?
dxp
Цитата(777777 @ Sep 23 2011, 12:52) *
Во-вторых, я даже не представляю где вы выкопали такое определение. Обязательными составными частями ОО всегда считались инкапсуляция, наследование, полиморфизм.

Только полиморфизм. Динамический. Икапсуляция и абстракция - это объектный подход.

Цитата(777777 @ Sep 23 2011, 12:52) *
Или если некая конкретная программа не использует полиморфизм, то она уже не объектно-ориентированная?

Именно так.

Цитата(777777 @ Sep 23 2011, 12:52) *
ООП и "объектный подход" чем-то отличаются?

Я уже неоднократно и подробно излагал на этом форуме по поводу парадигм программирования, в последний раз не более полугода назад. Повторять лень. Если интересуетесь, поищите по форуму.

Насчёт того, что классы С++ - это уже ООП, это распространённая ошибка. Сравните С++ с true ОО языком - например, со SmallTalk.
brag
Цитата
очитайте про "Placement new". Это прояснит многие вопросы, в том числе и про выделение в разных секциях

Я их смотрел, когда под плюсы код переводил. Особо от них легче не становится - надо выделять буфферы в статике, не забыть вызвать тот самый new, да и еще с thread safety, скорее всего, возится прийдется. в итоге аналог init(...) получается, только кроме того, надо держать еще указатель на обьект, а это аж 4 байта памяти sm.gif

Цитата
У C++ сложность, на мой взгляд, самая высокая из современных языков. Даже хаскелл уступает в этом плане.

не знаю что вы там сложного нашли.. Классы? так те же структуры. шаблоны? по моему гораздо сложнее их на С реализовывать через убогие макросы. несколько лишних ключевых слов? можно и не запоминать, есть для этоо тетрадка.
Мне после С так вообще такой же, только удобнее. там где были f(&inst) стали inst.f(),
где было куча макросов - стали шаблоны. где были таблицы с функциями - вообще похерились, и генерит их теперь компилятор.
Хотя вру, иногда приходилось писать под Qt, мож по этому мне плюсы не такие уж сложные sm.gif
MALLOY2
Ссылка в тему С++ & Cortex
brag
Хe, и множественному наследованию (по крайней мере двойному) нашлось применение.

Есть некий класс A. он должен принимать сообщения заданного формата и отправлять ответы тоже заданного формата, но через независящий от класса А и неизвестный ему интерфейс(это может быть sms,sockets,keyboard/display,...)
Код
class A{
private:
     CommIf *commif;
}

Класс CommIf тот самый интерфейс
Код
class CommIf{
public:
    virtual int cmdCbkSend(const void*,U32)=0;
};

Класс а читает с какого-нибудь thread-safe fifo данные, первое слово в этом fifo - у казатель на что-то производное от CommIf.
Код
Fifo.read(&commif,sizeof(commif));

Далее в fifo могут лежать произовльные данные, их можно от туда дочитывать итд. далее,если ему надо отправить ответ - он просто вызывает commif->cmdCbkSend() и кормит ему буффер с данными

Теперь реализация самого интерфейса(будь то смс или соктеы,..)
Код
class Smsiface : public Sms,public CommIf{
public:
   // reimplemented virtuals for CommIf
    int cmdCbkSend(const void *d,U32 n){return sendSms(0,d,n);}
protected: // reimplemented virtuals for Sms
    void smsReceived(int ep,const void *data,U32 len);
};

void Smsiface::smsReceived(int ep,const void *data,U32 len){
    CommIf *commif=static_cast<CommIf*>(this);
    Fifo.write(&commif,sizeof(commif));
}


Все. Смсы,сокеты,итд живут в отдельных тредах независимо друг от друга и от класса A(который тоже живет в отдельном треде).
Подобную хрень я делал и на С, но там запарится можно, пока все отладишь, все хождения по указателям, а на плюсах написал и работает wink.gif
andrewlekar
Множественное наследование от интерфейсов разумеется разрешено. А вот множественное наследование реализации запрещено в современных ОО языках. Так что тут вы велосипед изобрели. sm.gif

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

Ну а у меня наоборот: где была невнятная иерархия классов, требующая в дополнение к собственно программе диаграмму зависимостей, появился чистый и понятный код на сях. Где были утечки памяти, вопросы, где вызывать delete, а где delete[], нарушение инкапсуляции (да, в с++ трудно добиться честной инкапсуляции) - всё стало статично и разбито на независимые модули.
BlackHead
Вот набрёл на библиотеку С++
http://xpcc.sourceforge.net/api/main.html

Есть кое-что и для ARMов
kikos
Лет 20 назад один из заказчиков (пожилой американский менеджер) заранее потребовал писать код безо всяких ++. На вопрос почему, сказал, что за жизнь насмотрелся на море плохого С++ кода.
А теперь я могу вслед за ним повторить эту фразу. Более того, почти в 60% случаев кажется , что C++ используют не язык, а как средство самоутверждения.

так что лучше не писать на С++ при создание приложений под ARM... biggrin.gif

Сергей Борщ
QUOTE (kikos @ Oct 31 2011, 16:32) *
На вопрос почему, сказал, что за жизнь насмотрелся на море плохого С++ кода.
За жизнь много раз приходилось пробовать невкусный чай (кофе). Так что ж теперь, не пить чай(кофе) совсем?
Forger
Цитата(Сергей Борщ @ Oct 31 2011, 17:49) *
За жизнь много раз приходилось пробовать невкусный чай (кофе). Так что ж теперь, не пить чай(кофе) совсем?

+100
ReAl
Цитата(kikos @ Oct 31 2011, 15:32) *
Более того, почти в 60% случаев кажется , что C++ используют не язык, а как средство самоутверждения.
«лет 20 назад» в около микроконтроллерном мире многие похожее и про С говорили.

А сколько тот менеджер в жизни видел некрасивых женщин, у него не интересовались?
IgorKossak
Господа критикующие, напоминаю, тема звучит Как писать на С++ при создание приложений под ARM, Примеры
Это означает, что автора интересует ответ на вопрос именно как писать на С++, а вовсе не причины почему этого не следует делать.
Я не призываю переносить религиозную полемику в другую тему ибо поезд уже ушёл и огромное количество разработчиков давно и успешно программируют под МК именно на C++.
И пугать нас своей шоблой пожилых американских менеджеров также не нужно.
brag
Как можно реализовать такую вещ без кривоты, rtti, библиотек:
Код
class Base{
public:
    Base(Base *array){ _a=array;}
    Base *getItem(int n){ return &_a[n]; }
private:
    Base *_a;
};

class Derived: public Base{
public:
    Derived(Derived *array) : Base(array){}
private:
    int other;
};

Derived aaa[]={Derived(0),Derived(0),Derived(0)};
Derived d(aaa);


Ессно, при вызове d.getItem(1) мы получим мусор, вместо &aaa[1]. Сейчас сделал через массив указателей - вместо Base *array передается и хранится Base * const *array, но задолбало лепить эти массивы вручную, а на такое компиллер матерится, типа юзание временного обьекта:
Код
Derived *aaa[]={&Derived(0),&Derived(0),&Derived(0)};
Forger
Цитата(brag @ Dec 10 2011, 06:55) *
Как можно реализовать такую вещ без кривоты, rtti, библиотек:

Для полноты картины, расскажите, для чего вам нужна такая конструкция?
Что это на самом деле?
neiver
Массив указателей на объекты базового класса - это как раз правильное решение.
А когда вы пытаетесь индексировать массив объектов производного класса
Derived aaa[]={Derived(0),Derived(0),Derived(0)};
как массив объектов базового класса, то происходит "срезка". Объекты базового и производного класса имеют разные размеры.

Цитата
Derived *aaa[]={&Derived(0),&Derived(0),&Derived(0)};
а на такое компиллер матерится, типа юзание временного обьекта

И правильно матерится. На стеке создаются три временных объекта, указатели на них заносятся в массив, после чего эти объекты уничтожаются и их место в стеке освобождается. В результате указатели в массиве указывают куда-то, где раньше был стек и ваши объекты. Сейчас там корректные данные, потом будет мусор.
Правильно создать массив объектов производного типа и массив указателей базового типа...
brag
Цитата
Для полноты картины, расскажите, для чего вам нужна такая конструкция?
Что это на самом деле?


Это для построения gui. вот пример использования:
Код
....

static MenuItem* const settingsItemsList[]={
    &settingsItems[0],&settingsItems[1],
    &settingsItems[2],&settingsItems[3],
    &settingsItems[4],&settingsItems[5],
    &settingsItems[6],&settingsItems[7]
};
static Menu settingsMenu(Rect(0,8,96,56),0,settingsItemsList,sizeof(settingsItemsList)/sizeof(MenuItem*));

static MenuItem mainItems[]={
    MenuItem(0,"Normal",&normalMenu),
    MenuItem(0,"Professional",&proMenu),
    MenuItem(0,"Settings",&settingsMenu),
};
static MenuItem* const mainItemsList[]={ &mainItems[0],&mainItems[1],&mainItems[2] };
static Menu mainMenu(Rect(0,8,96,56),0,mainItemsList,sizeof(mainItemsList)/sizeof(MenuItem*));


Сам конструкторы выглядят так:
Код
class Menu: public Widget{
public:
    Menu(const Rect &geom,Widget *parent=0,MenuItem* const *children=0,int nchild=0);
...

Код
class MenuItem: public Widget{
public:
    MenuItem(Menu *parent=0,const char *text=0,Menu *target=0);
...

Код
class Widget : public PaintDevice{
public:
    Widget(Widget *parent=0,Widget* const *children=0,int nchild=0);
....


Цитата
Массив указателей на объекты базового класса - это как раз правильное решение.

правильное, только вот ни препроцессор, ни самя язык похоже не позволяет его создать "автоматом", в отличия, скажем, массива указателей на строки:
const char* const stringptrs[]={"kolbasa1","kolbasa2","kolbasa3"};
вот такое хотелось бы иметь и для обьектов...

Цитата
Правильно создать массив объектов производного типа и массив указателей базового типа...

массив указателей должен тоже быть производного типа, тк он передается производному классу сначала:
Menu(const Rect &geom,Widget *parent=0,MenuItem* const *children=0,int nchild=0);
dxp
Цитата(brag @ Dec 10 2011, 22:37) *
массив указателей должен тоже быть производного типа, тк он передается производному классу сначала:
Menu(const Rect &geom,Widget *parent=0,MenuItem* const *children=0,int nchild=0);

Если я правильно понял, что требуется работа с коллекцией объектов, то я для таких целей юзаю stl::list<Widget*>. Да, там будет аллокация памяти, но размер ноды небольшой (три указателя) и траблов с фрагментацией в этом случае, вроде, не ожидается.
brag
Цитата
Если я правильно понял, что требуется работа с коллекцией объектов, то я для таких целей юзаю stl::list<Widget*>. Да, там будет аллокация памяти, но размер ноды небольшой (три указателя) и траблов с фрагментацией в этом случае, вроде, не ожидается.

stl не канает, из доступных вещей есть только проц, голый компилятор и моск.
dxp
Цитата(brag @ Dec 11 2011, 01:11) *
stl не канает, из доступных вещей есть только проц, голый компилятор и моск.

О как! А куда ж стандартная библиотека-то делась? Компилятор один, что-ли, присутствует? sm.gif К тому же, stl - открытая вещь, можно взять и отдельно. Правда, может потребоваться доводка напильником. А может и не потребоваться.
brag
да просто проект такой, что проще свое написать, чем прикручивать что-то туда и потом парицца с синхронизацией, гонками итп...
kan35
Писать на С++ под ARM точно так же как на любую другую архитектуру. О чем тут вообще можно рассусолить на 7 страниц?
alx2
Цитата(brag @ Dec 10 2011, 07:55) *
Как можно реализовать такую вещ без кривоты, rtti, библиотек:

Наверное как-то так:
CODE
template <typename T>
class Base{
public:
Base() : _a(NULL) {}
Base(T *array) : _a(array) {}
T *getItem(int n) const { return &_a[n]; }
private:
T * _a;
};

class Derived: public Base<Derived>{
public:
Derived() {}
Derived(Derived *array) : Base<Derived>(array){}
private:
int other;
};

int main()
{
Derived array[3];
Derived d(array);
return printf("%p = %p\n", d.getItem(1), &array[1]);
}

Хотя лучше, как Вам уже посоветовали, использовать stl.
Цитата(brag @ Dec 11 2011, 03:59) *
да просто проект такой, что проще свое написать, чем прикручивать что-то туда и потом парицца с синхронизацией, гонками итп...

Если вы способны писать код классом выше чем годами и тысячами людей проверенные реализации stl, почему Вы задаете такие вопросы? sm.gif
Если Вы используете многопоточность, неиспользование stl не гарантирует отсутствие в вашем коде гонок и не избавляет от необходимости "парицца с синхронизацией". Также как использование stl не способствует появлению гонок.
Синхронизация потоков в обоих случаях остается вашей заботой.
brag
Спасибо.
но это тоже не то, массив указателей все же должен быть, тк там могут быть наследники разных типов разного уровня и все они должны корректно обрабатываться базовым классом...

Цитата
Если вы способны писать код классом выше чем годами и тысячами людей проверенные реализации stl, почему Вы задаете такие вопросы?

Никто этого не говорил, просто так проще, во первых. в системе совсем иные механизмы распределения памяти(скажем, аналога malloc нету) и других ресурсов, что несовместимо с stl, по крайней мере с ее частями....
на основе динамики (stl::list<Widget*>) не идет.
И на основе статики тоже - памяти мало, надо экономить. Константый массив указателей в flash - самое оно, создавать бы его еще красиво...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.