Вступ
Нещодавно при роботі над проектом навчальної практики виникла потреба з свого коду породжувати довільний процес і одночасно читати його stdout і stderr. Так як додаток пишеться виключно для linux, я вирішив заодно розібратися з epoll. Для запуску процесу на просторах інтернету була знайдена маленька бібліотека, робить саме те, що потрібно, та ще й обертаюча введення-виведення в звичні потоки із стандартної бібліотеки (мова про <iostream>).

Озброївшись кількома статтями про epoll, я вже було збирався писати код, якщо б не одне «але» — для epoll потрібний доступ до «сирим» файловим дескрипторам, а автор бібліотеки не надає public-доступу до них. Методи класу, повертають дескриптори, приховані під грифом «protected».

Що робити?
Найпростішим було б виправити код бібліотеки і перемістити потрібні методи public-секцію, ще краще було б форкнуть бібліотеку і реалізувати необхідний функціонал самому. Але перше було б негарно і обіцяло б конфліктами при оновленні бібліотеки, а друге зайняло б занадто багато часу на розбір коду бібліотеки і подальше тестування під кількома різними *nix-системами.

Тому в голову прийшла божевільна третя думка: чому б не спробувати як-то гарно «зламати» ООП і «легально» отримати доступ до protected-методом без втручання у вихідний код бібліотеки? Про те, які виникли перепони на цьому шляху і як допоміг C++14 в їх подоланні, і піде розповідь у даній публікації.

Читати далі →

Практика метапрограммирования на C++: бінарне дерево пошуку на етапі компіляції

Творці шаблонів в C++ заклали основу цілого напряму для досліджень і розробки: виявилося, що мова шаблонів C++ володіє повнотою по Тьюрингу, тобто метапрограми (програми, призначені для роботи на етапі компіляції) C++ в змозі обчислити всі вычислимое. На практиці міць шаблонів найчастіше застосовується при описі узагальнених структур даних і алгоритмів: STL (Standard Template Library) тому живий приклад.

Однак, з приходом C++11 з його
variadic
-шаблонами, бібліотекою
type_traits
, кортежами і
constexpr
'ами метапрограмування стало більш зручним і наочним, відкривши дорогу до реалізації багатьох ідей, які раніше можна було втілити тільки за допомогою розширень конкретного компілятора або складних багатоповерхових макросів.

У даній статті буде розроблена реалізація бінарного дерева пошуку часу компіляції: структури даних, що є логічним «розширенням» кортежу. Ми втілимо бінарне дерево у вигляді шаблону і попрактикуємось в метапрограммировании: перенесення рекурсивних і не тільки алгоритмів на мову шаблонів C++.

Читати далі →

Головоломка по асоціативних контейнерів STL або Як розв'язати одну задачу вісьмома різними способами

Введення
У даній статті я хочу розповісти про свої «пригоди» при рішенні задачі по STL, що виникла в ході роботи над невеличким проектом (C++11, Visual Studio 2015).

На перший погляд, завдання виглядала досить просто. Але при найближчому розгляді:
— у відкритих джерелах готового рішення не знайшлося;
— стандартні ООП-підходи на ній «забуксували»;
— виявилося, що навіть для досвідченого розробника завдання може представляти складність.

Я наведу кілька варіантів рішення. Частину з них я відкинув до реалізації, але деякі були реально написані. З одних прикладів можна отримати користь тільки типу «дивися і ніколи так не роби», інші ж цілком можуть знайти застосування на практиці.

Читати далі →

Універсальний конструктор Auto

З приходом C++11 з'явилася можливість оголошувати змінні типу auto, а компілятор сам визначив фактичний тип змінної, на основі типу инициализируемого значення. Це зручно, коли ми хочемо ініціалізувати змінну тип якої дуже складний, або невідомий, або він нам не дуже важливий, або просто для простоти.

Наприклад:

auto f = [](){}; //вказівник на функцію
auto r = foo(10); //тип повертається функцією foo
for (auto i = 0; i < 10; i++){} 

… і т. д. тобто в лівій частині рівності у нас автоматичний тип auto, а в правій частині значення чітко визначеного типу. А тепер уявімо, що у нас все навпаки:

int a = auto(10);

Читати далі →

Пишемо Rest API клієнт на Qt5

Введення

Останнім часом я займаюся розробкою настільного Rest API клієнта. Досить велика частина роботи полягає у взаємодію із сервером. Для оптимізації обробки запитів був написаний клас Requester, що володіє наступними особливостями:
  • можливість відправляти https так і http запити
  • використання однієї функції для всіх типів запитів
  • можливість отримати всі дані за запитом з сервера, а не одну сторінку(n записів)

Читати далі →

Використання сучасного С++ для підвищення продуктивності

У даній статті я хотів би розповісти, як використання засобів сучасних стандартів З++ дозволяє підвищити продуктивність програм без яких-небудь особливих зусиль від програміста.

Читати далі →

Ніжна дружба агентів і виключень в SObjectizer

Рано чи пізно в програмі щось йде не так. Не відкрився файл, не створилася робоча нитка, не виділилася пам'ять… І з цим треба якось жити.
В невеликому однопоточному додатку досить просто: можна перервати всю роботу і рестартовать. Це один із факторів, завдяки якому Erlang здобув собі заслужену популярність, адже ідеологія fail fast є одним з наріжних каменів Erlang-а з його легковажним процесами. Якщо ж додаток велике, складне і багатопотокове, то не розумно рестартовать усі додаток, якщо лише одна з його ниток зіткнулася з проблемами. Ще гірше в ситуації з реалізацією Моделі Акторів, у яких сотні тисяч акторів можуть працювати на десятках робочих ниток. Проблема одного актора навряд чи повинна позначатися на всіх інших актора.
У даній статті ми розповімо, як ми підійшли до обробки помилок у своєму фреймворку SObjectizer.
Винятків – так, кодами повернення – ні!
Коли SObjectizer-4 з'явився в 2002-му році, ми зробили велику помилку – зволіли використовувати коди повернення винятків. І весь подальший досвід розробки на SObjectizer-4 знову і знову переконував у однієї простої істини: якщо помилка може бути прогнорирована розробником, то вона буде ним проігнорована. Тому при створенні SObjectizer-5 ми вирішили використовувати виключення для інформування про помилки.

Читати далі →

Рядка в кодовій пам'яті AVR

У нашій компанії ми пишемо програми для контролерів серії AVR. У цій статті я опишу як ми в нашій компанії створюємо рядки, розташовані в кодовій пам'яті.

Нам потрібно, щоб наступний код не видавав помилок, а в результаті ми отримали набагато більш потужний інструмент, ніж припускали.

const char *pStr = PSTR("Привіт"); // У цьому місці помилка.
// error: statement-expressions are not allowed outside functions nor in template-argument lists

int main() {...}

Читати далі →

SObjectizer: проблема перевантаження агентів та засоби боротьби з нею

У попередніх статтях ми кілька разів згадували про таку проблему, як перевантаження агентів. Що це таке? Чим це загрожує? Як з цим боротися? Про все це ми і поговоримо сьогодні.
Проблема перевантаження агентів виникає, коли якомусь агентові надсилається більше повідомлень, ніж він встигає обробляти. В результаті черги повідомлень постійно збільшуються в розмірах. Зростаючі черзі витрачають пам'ять. Витрата пам'яті веде до уповільнення роботи програми. Через уповільнення проблемний агент починає обробляти повідомлення довше, що збільшує швидкість зростання черг повідомлень. Що сприяє більш швидкому витраті пам'яті. Що веде до ще більшого уповільнення програми. Що веде до ще більш повільної роботи проблемного агента… Як підсумок, додаток повільно і сумно деградує до повної непрацездатності.
Проблема посилюється ще і тим, що взаємодія за допомогою асинхронних повідомлень і використання підходу fire-and-forget прямо таки провокує виникнення перевантажень (fire-and-forget – це коли агент A отримує вхідні повідомлення M1, виконує його обробку і відсилає вихідне повідомлення M2 агенту B не піклуючись про наслідки).
Читати далі →

Вбудовування функціональних об'єктів, функцій і лямбд через шаблони і уніфікація за допомогою virtual на C++

У цій статті показані деякі механізми, що дозволяють отримати досить продуктивний (вбудовується під час компіляції) і легко масштабований код для управління викликами різних об'єктів за допомогою стандартних технологій З++.

Про завдання
Деякий час назад з'явилася необхідність реалізувати невеликий модуль, який в залежності від користувача (runtime) інформації буде виконувати різні дії всередині ядра програми. При цьому основними вимогами були максимальна продуктивність (оптимизируемость) коду, відсутність сторонніх залежностей і просте масштабування на випадок додавання функціоналу.

Для більшої простоти і читабельності в прикладах коду будуть показані тільки найбільш складні ключові механізми. Приклади машинного коду наводяться для компілятора майкрософт при оптимізації О2.

Читати далі →