Перейти к содержанию
    

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Опять двадцать пять. Снова повторение одних и тех же мантр....и не вижу описываемых вами ужасов. Вот совсем не вижу. А преимущества плюсов вижу и постоянно использую.

На вкус и цвет...

 

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

Что там мешает плохому танцору?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

Например:

есть класс Hardware, где инициализируется и используется железо МК,

есть класс RTOS, инициализация которой должна пройти сразу после инициализации тактового генератора,

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

 

Если размещать объявление этих классов экземпляров в одном файле, то их конструкторы вызываются соотв. в порядке их размещения в файле (обычно их кладут в начале cpp файла),

а если файлов много и в каждом есть статические объекты (само собой все с квалификатором static), то в каком порядке будут вызываться конструкторы статически объявленных классов, одному богу известно.

Все зависит от пристрастий линкера и фазы луны. Я наступал на эти грабли, вдоволь накушался (((

 

Конечно, отложенная инициализация - неплохое решение (перенос содержимого конструктора в отдельный метод initialize(), который уже вызывается в определенном месте).

Но все равно возникает проблема видимости статически созданных классов в других файлах.

Можно пойти дальше - объявлять некоторые поля таких классов со словом static.

Но это по-сути выраждается в коряво имитируемый синглтон ))

 

В итоге все равно приходишь к полноценному готовому шаблону - синглтону ))

 

К слову, под синглтон идеально ложится класс RTOS, класс железа или чего-то, что в проекте ВСЕГДА будет существовать в единственном экземпляре.

Синглтон позволяет сам контроллировать вызов своей инциализации, причем делать это лишь один раз.

Например, инициализаця класса RTOS должно проводится всего один раз и всегда ДО создания объектов классов задач/потоков, семафоров, мьютексов и др. сервисов RTOS.

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

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

 

Снаружи любого проекта это выглядить очень просто и лаконично - задачи, сервисы RTOS можно объявлять где угодно:

статически (в начале файле cpp), динамически, размещать их в закрытой секции (private) соотв. класса, да хоть локально в соотв. функции ))

Голова никогда не болит где и в каком поредке они будут созданы, но будут проинициализированы и запущены в строго отведенных местах в заданном порядке (см. код из предыдущего моего поста).

 

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

Т.е. можно при желании создать несколько экзэмпляров RTOS, и переписать порт под многоядерную систему, где будут крутиться более одной оси .... ;)

На данный момент это пока что абсурд, но тем не менее!

 

Что там мешает плохому танцору?

Рукастый слесарь со стажем, который работал только стамеской и молотком, может сотворить настоящее чудо.

Когда потребуется сделать что-то подобное, то все по новой - долго, муторно, трудоемко :(

В этот раз чуда может не получится - скажем, отколется часть детали и все по-новой....

 

Другой же слесарь, который смотрит дальше того, что умеет, поступит иначе:

нарисует 3D модель (придется освоить соотв. инструменты), отдаст ее в деревообрабатывающий цех (придется научится правильно рисовать модели под особенности технологии),

ему на ЧПУ станке по дереву вырежут ему десяток таких чудесных деталей.

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

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

ЧПУ станок нарежет столько деталей, сколько нужно. В этом время этот слесарь занят следующей моделью.

 

Конечно, никто не мешает до конца жизни стучать молотком по стамеске :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Конечно, никто не мешает до конца жизни стучать молотком по стамеске :biggrin:

Завидую я вам. А у меня практически каждый проект - новый проект. А идей ещё больше. Заимствуются крохи. Причём то что заимствуется, как то без особых проблем.

Я ничего не говорил, по С++. Я им пользуюсь. Какие-то проекты, обслуживания прибора пишу на QT. Но как то всё равно язык не стал своим...

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

Типа базовый класс? Далее от него класс SPI?

А что вы за ось пользуете?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я - убей - не пойму, что мне даёт класс Hardware... Выглядит несколько надуманно.

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

Некоторые вынесены в отдельные классы, например, драйвер для общения по сети CAN, экземпляр класса просто "подключается" библиотеке, которая требует CAN driver для своей работы.

Общая система взаимодействия формируется постепенно - от проекта к проекту.

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

Там же библиотеки RTOS, драйверы на некоторую периферию.

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

Более того, они заранее скомпилированы и собраны в либы, чтобы в самих проектах компиляция проходила быстрее и меньше файлов болталось в дереве файлов. Только самое необходимое.

 

 

Типа базовый класс? Далее от него класс SPI?

Есть готовые открытые С++ либы под периферию разных процов. Погуглите ))

 

А что вы за ось пользуете?

Разные: https://electronix.ru/forum/index.php?s=&am...t&p=1475072

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Стиль написания, конструирование программы и язык всё же параллельны. А стабильность работы вообще к языку никакого отношения не имеет.

Не в плане спора, но как известно С++ ни в одном источнике, как ясный прозрачный и без проблемный не рассматривается. Ну это же объективно. Просто почитайте мнение специалистов.

В предпоследнем проекте у меня было 411 объектных файлов и более 50 тыс строк текста. Это прибор коммерческого учёта. Я не видел случаев его падения.

Там Си + FreeRTOS + LwIP. Драйвера в несколько уровней.

Например, обращение к флэшке SPI из различных задач - на ура. Мало того, использовались 2 аппаратных буфера поочерёдно для ускорения. В некоторых случаях заливка производилась потоковым способом. Всё работало как часики. При падении напряжения возникало прерывание, сохранялся контекст, сохранялись указатели архивов... Сделал - положить нельзя прибор. Только контрольный выстрел. ))

Меню там экранов штук сто - объектно построено.

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

А что вы так взъелись на динамическое выделение памяти? Тоже пробовал в проектах. В одном проете вообще на нём всё построено было. Причём там у меня дырки появлялись. Так я свой сборщик мусора сделал. Тоже претензий не было. Если всё продумать, то всё работает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В предпоследнем проекте у меня было 411 объектных файлов и более 50 тыс строк текста.

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

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

 

Вот подумываю один проект замутить на плюсах.

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

Неужели и вас тоже утомило работать "молотком по стамеске"? :biggrin:

 

А что вы так взъелись на динамическое выделение памяти?

Все просто - категорически не люблю мотаться по командировкам :)

 

Есть у меня испытанный в тестах неплохой диспетчер динамической памяти (TLFS), но пока нет ни одного проекта, где понадобилось применять динамическую память.

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

В моем случае такой подход выгоднее ))

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посмотрите с чего начиналась тема. Начали гнать на HAL от ST. Что по своей сути это такое? По сути это попытка создания универсальной библиотеки. Более того, в купе с генератором, это попытка создания универсального подхода. С моей точки зрения - он провалился. Хотя куча его использует и счастливы.

Что предлагаете вы? Вы пытаетесь создать туже универсальную библиотеку, с универсальным подходом. Только 2 отличия. 1 - на С++. 2 - вы не ST.

Простите - я лучше стамеской поработаю.

Любая универсальная библиотека будет избыточна. И должна быть избыточна. Потому что универсальность и избыточность это одно и тоже. Меня не напрягает избыточность сама по себе. Камни сейчас обеспечивают - я не парюсь. Но весь мой опыт написания универсальных вещей, говорит что они не нужны. В принципе не нужны. Посмотрите HAL от ST на USART. Пипец. Я даже не представляю приложение куда это можно воткнуть!!! Получается, что для применения этой универсальной вещи потребуется обёртка большая по объёму, чем если бы я с нуля написал неуниверсальный драйвер. Я уже писал по этому поводу. Я делаю 2 уровня дров. Железозависимая часть и железонезависимая. Ну например SPI и ADC. Этот же SPI и DATAFLASH.

USART -> MODBUS. Нижняя часть - это десяток строк. Дрова у меня в проекте занимают 2% по объёму и ещё меньше по времени. Отлаживаются на раз и к ним никогда не возвращаешься.

А остальная часть проекта это как раз то, что я постоянно меняю. Даже если прибор аналогичный.

Я видел несколько попыток создания универсальных платформ. В том числе на плюсах. Ни одна меня не впечатлила.

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

 

Теперь по поводу динамической памяти. В том проекте, о котором я писал примерно такое построение было... Поступают данные с внешнего интерфейса. Данные поступают в виде команд. Команды разной длины и разного времени жизни. Устройство выполняет команду и удаляет её. Получается, что одна команда могла выполниться и сразу удалялась, а другая выполнялась в течении длительного времени. В результате память дифрагментировалась. Поток команд был очень интенсивный. Объём памяти тогда на контроллере был 64к всего. Под кучу килобайт 30 было отведено. Уже не помню. Были бы проблемы это бы вылезло достаточно быстро. Устройство не выключалось. Работало круглосуточно. Не скажу что мы их много сделали. Ну несколько десятков было.

А вот на плюсах как раз трудноустранимые утечки случаются. Парень писал для нас OPC сервер. На QT4 + VS. Была утечка памяти. Устранил только когда свой QSerialPort написал. Хотя я с той же версией QT+GCC писал прогу удалённого управления прибором и проблем не было. При этом для связи использовали те же классы. Вот такой вот пример.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что предлагаете вы? Вы пытаетесь создать туже универсальную библиотеку, с универсальным подходом. Только 2 отличия. 1 - на С++. 2 - вы не ST.
Вы нифига ничего не поняли ))

 

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

Искать баги в лаконично и грамотно спроектированном коде значительно проще.

На С++ это сделать проще и нагляднее, чем городить огород из С-костылей (сужу исключительно по своему опыту).

 

Нету у меня единой обертки под все железные дела, есть лишь заранее скомпилированные либы на базе индусской PeriphLib под разные ST-процы (сижу плотно на них).

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

Все остальное - по максимому чужое. Изобретать велосипед - уже не тот возраст ))

Так как поддержка PeriphLib прекращена, похоже, придется переключаться на HAL, но по возможности по максимому буду использовать только объявления регистров и ессно cmsis.

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

 

Любая универсальная библиотека будет избыточна.
Еще раз - речь не об этом ))

Я ни сколько не призываю использовать мой код (попросите, не дам),

Я лишь продемонстрировал как применяется на примере класс синглтон и самое главное пример модульного построения проекта на основе одного из моих проектов.

 

Есть у меня также самописный Iterator (изумительная вешь, я в восторге от ее простоты и функциональности!),

Queue для управления списками (самописный простой),

набор разных цифровых фильтров (шаблоны, т.е. не привязаны к типам данных)

есть само собой Singleton, от которого наследуются все синглтоны (модули проекта)....

Все это - шаблоны классов, т.к. просто hpp файлы. Вообще не зависят ни от какого железа.

 

Готовые чужие реализации мне не понравились - слишком толстые и перегруженные всякой ненужной трухой.

Впрочем, такого добра у каждого программиста полно. У каждого - свой ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

На счёт того, что плюсы дают преимущество в проектировании - возможно. Так как более высокоуровневый язык, проще позволяет описать именно верхний уровень. Но это справедливо будет только при хорошем владении инструментом. Иными словами - вот человек неверно спроектировал проект. И что? При переходе на С++ ошибки исчезнут? Думаю их добавится.

На плюсах даже подход меняется..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Синглтон позволяет сам контроллировать вызов своей инциализации, причем делать это лишь один раз.
Вот на реализации этого и страдает мое чувство прекрасного. Он каждый раз проверяет - создан ли объект, и если не создан - то создает. То есть программа может годами работать после запуска, все инициализации давно прошли, а он продолжает тратить время на ставшие уже ненужными проверки при каждом обращении к каждой сущности. Я понимаю, что это тяжелое наследие моего ассемблерного прошлого, что ресурсов у современных МК завались, но побороть себя пока не могу. Хотя с проблемами порядка инициализации сталкиваюсь постоянно, да. Пока я думаю о запихивании всего в один класс Application - там порядок вызова конструкторов однозначно определен порядком объявления, а уж наличие в программе одного объекта Application я как-нибудь вручную обеспечу.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Редкая проверка битового флага отнимает совсем немного времени :)

 

К тому же далеко не везде и не так уж часто нужно проверять факт существования некоторых сущностей.

 

Вот пример: синглтон rtos - класс Kernel.

При создании мьютекса в конструкторе вызывается инициализация Kernel.

Т.е. проверка только на этапе запуска системы (я динамически практически никогда не создаю объекты rtos).

По сути в данном случае все эти проверки производятся только при подаче питания.

 

void Kernel::initialize(void)
{
    if (!isInitialized)
    {
        __disable_irq();
        initializeHardware();
        initializeModules();
        isInitialized = true;
    }
}

 

class Mutex
{
public:
    Mutex(void)
    {
        Kernel::getInstance().initialize();
        handle = xSemaphoreCreateMutexStatic(&controlBlock);
    }
....

 

 

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

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

Синглтоны, имхо, тут оказались самым уместным решением.

И обязательно - возможность отложенной инициализации, у меня каждый модуль имеет метод initialize(), пусть пустой, но он должен быть.

(в будущем это даст возможность запихать их в container и инициализировать все скопом через foreach).

 

 

 

 

 

 

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

Ну, "не так страшен черт, как его малюют" :)

 

Ну или костыли,которых не любят все.
Никто не любит костыли, просто, многие ленятся отказаться от них ;)

 

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

Не стоит бояться новых инструментов, уверяю вас - привыкание приходит быстро :)

 

Иными словами - вот человек неверно спроектировал проект. И что? При переходе на С++ ошибки исчезнут? Думаю их добавится.

Разумеется! Тупой переход с C на C++ в лоб ничего полезного не даст, а даже наоборот.

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

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

Но делать с таким расчетом, что накопленные навыки (библиотеки) могут пригодится в других проектах.

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На С++ это сделать проще и нагляднее, чем городить огород из С-костылей (сужу исключительно по своему опыту).

Опыт у всех разный и, соответственно, результаты и выводы. Вообще, универсально-идеального подхода/решения нет и не будет. Suum cuique.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще, универсально-идеального подхода/решения нет и не будет. Suum cuique.

На самом деле есть идеально-универсальные решения, но они всегда основываются на новых более функциональных инструментах :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На самом деле есть идеально-универсальные решения, но они всегда основываются на новых более функциональных инструментах :)

Блажен, кто верует, тепло ему на свете!

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...