2012-12-17

Контр-интуитивное поведение Qt resource compiler

Списку программ с контр-интуитивным поведением прибыло.
#wc -c - кол-во байт в "выхлопе"

$rcc bin.qrc | wc -c 
44554395
$rcc -no-compress bin.qrc | wc -c
44554395
$rcc -compress 1 bin.qrc | wc -c
44554395
$rcc -compress 9 bin.qrc | wc -c
44554395
$rcc -help
...
Options:
...
  -threshold level     threshold to consider compressing files
  -compress level      compress input files by level
  -no-compress         disable all compression
...
$rcc -threshold 0 -compress 1 bin.qrc | wc -c
18441572

2012-12-04

OpenSource такой OpenSource

Ломать бинарную совместимость при смене версии с 0.8 на 0.9? Сжав зубы, такое можно "понять и простить".

Но ломать совместимость между libxxx-dev_1.0.1-1 и libxxx-dev_1.0.1-1.1, поменяв названия типов и не оставив define или typedef для старых имен?

И да, о #include <stdint.h> мы тоже не слышали:
typedef unsigned int uint32;

2012-12-03

когда коту делать нечего...

Emscripten is an LLVM to JavaScript compiler. It takes LLVM bitcode (which can be generated from C/C++ using Clang, or any other language that can be converted into LLVM bitcode) and compiles that into JavaScript, which can be run on the web (or anywhere else JavaScript can run).
Using Emscripten, you can
  • Compile C and C++ code into JavaScript and run that on the web
  • Run code in languages like Python as well, by compiling CPython from C to JavaScript and interpreting code in that on the web
.....

      • This is the Lua interpreter, compiled from C to JavaScript using Emscripten, running in your browser (without any plugins).
      • TrueType font rendering in JavaScript, using FreeType
      • lzma.js - LZMA ported to JS
      • sql.js - SQLite ported to JS

      Куда катится мир .. (с) nponeccop

      шиндовс вперде

      Админ кинул в общий чат ссылку на локальную репу обновлений для MacOS. Разговорились по этому поводу на кухне. Внезапно - в нашем офисе из 40+ человек винда стоит у шестерых(!). Остальное - Mac или Linux.

      2012-11-29

      аналог lock(C#) или @syncronized(ObjC) в С++

      Типичное использование бустовских мютексов выглядит как
      
      
      void SomeClass::SomeMethod() {
         //... some code
         {
            boost::mutex::scoped_lock lock(some_map_mutex_);
            some_map_.erase(foo);
         }
      } 
      

      Блок режет глаз и выглядит слегка чужеродно. Поэтому склепал вот такой вот велосипед

      #define using_lock(mtx) for(::boost::mutex::scoped_lock lock(mtx), *flag = &lock; flag; flag = 0)
      
      
      Использовать так
      
      
      
      using_lock(some_map_mutex_) {
         some_map_.erase(foo);
      }
      

      2012-11-26

      When ...

      When I see three layers of weird DSLs for configuring a single app

      When somebody says “it’s written in C, so it must be fast”

      When somebody tries to explain JavaScript’s prototype system

      When I hear your new PL doesn’t have exceptions and requires manual error handling instead

      When somebody says he doesn’t like exceptions because he likes to handle errors where they appear

      Moar here

      2012-11-13

      Интересная история о случае, когда в STL можно выстрелить себе в ногу. Когда хотели ускорить алгоритм, а в результате замедлили раз в сорок.
      ... есть благие намерения и известно, что требуются дополнительные приседания в виде преаллокации массива, но пуля прилетает туда же, куда и обычно. 

      2012-11-06

      Achtung, minen! или Shell + Space = @#$&

      Работа шелла с пробелами иногда ни разу не интуитивна.

      Дано
      $ cat count.sh
      echo "$# : '$1' '$2' '$3'"
      $ cat proxy.sh
      ./count.sh $@
      Пробуем
      $ ./count.sh 'a b' c
      2 'a b' 'c'
      $ ./proxy.sh 'a b' c
      3 'a' 'b' 'c'

      Теперь я знаю, как это лечится ("$@"), но чем думал автор, когда делал такое поведение?


      2012-10-24

      Торокан горд

      В качестве входных данных для одной из наших программ бета-тестер использовал статьи из википедии на коми-пермяцком языке.
      Фраза "Торокан нето гöрд торокан — сія геббез чукӧрись подаок." вынесла мозг целиком и полностью.
      P.S. Хром при написании этого сообщения предложил заменить "из википедии" на "из передовики".

      2012-10-03

      Все в порядке -- старый код тоже не работает!


      Полдня убил, чтобы понять, почему новый клиент (что я пишу сейчас) получает SIGPIPE при обмене данными с ядром из "релизной" версии. Пока не собрал из транка "старый" вариант фронт-энда. Который тоже упал.


      Вот скажите мне, зачем менять внутренний протокол обмена данными (между ядром и фронт-эндами) через пару недель ПОСЛЕ выпуска мажорной (X.0) версии продукта? Ядро просто "ниасиливало" команды в новом формате и закрывало соединение.


      2012-09-06

      прекрасное

      увидел в жуйке 



      2012-09-04

      А что, можно было?

      Чувствую себя слоупоком. Решив почти полторы сотни задач с Эйлера на Хаскелле, открыл для себя разницу между "ghc -O2" и runhaskell.
      runhaskell 136.hs
      - около 5 минут
      ghc -02 136.hs && ./136
      - 15 секунд.

      2012-08-31

      Элементы ФП в ObjC (BlocksKit)

      Когда-то жаловался, что ObjC у массива нету поиска по условию.
      Нашел фреймворк, который позволяет писать на ObjC "функциональненько".
      3 типа map (each:, apply:, map:), filter (select:, reject:), find(match:), any, all, none, fold (reduce:withBlock:). Плюс in-place варианты для мутабельных коллекций (performMap:, performSelect:, performReject:). Все принимают блок (ака лямбда).
      Имхо, эта штука должна быть в ObjC "искаропки".

      Юнит-тесты и iOS.

      Хотел в новом проекте под ios сделать все кошерно -- отделить логику от гуя, обложить логику юнит-тестами. Ага, щаз.
      Вынес логику как статическую либу -- потерялись некоторые методы. Проект компилируется без ошибок, а в рантайме падает - Unrecognized Selector. Как оказалось, без флага -ObjC линкер не подтягивает категории (аналог extension methods из C#) из статических библиотек. Благо сотрудник уже с таким сталкивался, подсказал.
      Начал пилить тесты. Инициализация MagicRecord (библиотека для active record) падает с исключением "URL is nil".  Не находит схему данных. Смотрю внутрь бандла теста - лежит. Оказалось, она пытается загрузить схему из ресурсов главного модуля. А для юнит-тестов главным модулем является программа otest из SDK.

      Upd. Юнит-тесты поборол. Решение со StackOverflow:

      Assuming you have an application target called "MyApp"
      1. Add a new target of type "other/Cocoa Unit Testing Bundle" to the project e.g "MyAppTesting". Here all Unit test files are located.
      2. Go to MyAppTesting Build Phases and add MyApp as Target Dependency. This assures that MyApp is build before building the MyAppTesting target.
      3. Open the Build Settings of MyAppTesting and change
        • Bundle Loader: $(BUILT_PRODUCTS_DIR)/MyApp.app/MyApp
        • Test host: $(BUNDLE_LOADER)
        That causes the tests to run within MyApp.
      4. Open the Build Settings of MyApp and change
        • Symbols Hidden by default: NO (for both)
        • Strip debug Symbols during Copy: Debug:NO
        By doing so you do not have to include every .m-file into the test target.

      2012-08-28

      osx gui trick

      System Preferences -> Keyboard -> Keyboard Shortcuts -> Application Shortcuts
      добавить шорткат: All Applications, Zoom, Cmd+Shift+Up

      После этого хоть как-то можно жить. Хотя до Win7 или Unity все еще далеко.

      2012-08-23

      Кавычки нам не нравятся

      gcc-llvm в макос игнорирует параметры -isysroot и -idirafter, если их параметр указать в кавычках.
      g++ -idirafter /opt/local/include
      работает, а
      g++ -idirafter "/opt/local/include"
      нет.
      И кто они после этого. 

      2012-08-22

      Java Borshch

      Заходит джавист в столовую и говорит "Паблик статик файнал Борщ борщ равно нью Борщ, пожалуйста" (c) твитор
      Upd. из жуйка: Заходит C-программист в столовую, а столовая его прибивает 11-м сигналом. Адресом ошибся.

      2012-08-13

      IT-ужастики

      Увидел в твиттере и жуйке:

      "Я знаю, что вы коммитили прошлым летом"
      "Техасский мердж бензопилой"
      "Страх и ненависть в репозитарии"
      "Коммит не туда."
      "От заката до коммита".


      2012-08-09

      libtool, мать его.

      2012 год на дворе.
      Космические корабли бороздят ...
      А факин libtool до сих пор не умеет готовить пути с пробелами.
      Ненависть!

      2012-08-06

      В копилку к OMG Ponies

      в дополнение к OMG Ponies!!! (Aka Humanity: Epic Fail)

      У одного из наших клиентов были проблемы с регистрацией продукта.
      Ключ принимался, но сервер активации давал отлуп.
      Локально проблема не воспроизводилась.
      Попросили удаленный доступ, зашли к нему на машину.
      Оказалось, что у пользователя сейчас 2555 год, ибо он находится в Таиланде, где официальным является Буддийский календарь.

      2012-08-02

      Вот что я ненавижу в программировании под linux/unix, так это PIC и RPATH.

      2012-07-04

      MS такой MS

      Для виртуальных дисков, созданных через subst, действует ограничение в 2Gb на файл, даже если подставляемый каталог лежит на NTFS-томе.
      Лечится net use v: \\127.0.0.1\c$\Users\bitfield\foldername, но это тоже извращение -- гонять данные через сетевую подсистему.

      2012-07-02

      Смайлики

      цитато из Makefile
      
      
      '^/\*' $< >$@

      2012-06-27

      записки из генераторной

      python-скрипт читает конфиг в ini-файле и создает файл, включаемый в Makefile.am.
      Тот после обработки automake дает Makefile, который при make создает из XML-файлов .cpp и .h (через qdbusxml2cpp).
      полученный h-файл обрабатывается moc, давая еще один .cpp.
      Потом все это компилируется...

      2012-06-18

      Небольшой опросец

      Други мои, работающие в сфере IT.
      А расскажите-ка, как у вас в конторах обстоит дело с паролями.
      А то я недавно осознал, что у нас тут творится треш и содомия -- отдельные аккаунты (пароли) на:
      1. Внутренний форум
      2. Багтрекер
      3. SVN-сервер
      4. Внутренний Jabber
      5. Сетевую шару.

      Или так и должно быть/у всех так, и мне просто хочется странного?


      2012-06-13

      sh такой sh

      Напоролся на интересное поведение в шелл-скрипте.
      Изначально скрипт был под bash, но из-за портирования под одну обрезанную платформу переключились на sh.

      $ false && echo WTF || echo ok
      bash: ok
      sh: ok

      $ false > /dev/null && echo WTF || echo ok
      bash: ok
      sh: ok

      $ false &> /dev/null && echo WTF || echo ok
      bash: ok
      sh: WTF

      Лекарство:
      $ false 1> /dev/null 2>&1 && echo WTF || echo ok
      bash: ok
      sh: ok

      2012-05-29

      Щи!!

      http://www.gamedev.ru/projects/forum/?id=160897
      Концепт игры весьма неплох.
      Но "главный жир" -- исходники.
      Самые яркие моменты можно увидеть в комментах.

      2012-05-16

      Просто оставлю это сдесь, дабы не потерялось

      OMG Ponies!!! (Aka Humanity: Epic Fail)

      2012-05-15

      Внезапно: чего не хватает в Хаскеле, языке, где все иммутабельно, так это нормальной поддержки энумов/констант в паттерн-матчинге.
      Кусок из Эйлер-84
      prob d 12 {-U1  -} = d 12 + cardP (d 7 + d 36)
      prob d 15 {-R2  -} = d 15 + cardP 2 * d 7
      prob d 17 {-CC2 -} = ccP * d 17
      prob d 19 {-D3  -} = d 19 + cardP (d 22)
      prob d 22 {-CH2 -} = chP * d 22
      
      Если б вместо чисел были константы, было б читабельнее.

      Upd. Я слоупок, есть же class Enum.

      2012-05-10

      Ruby+iOS

      Нашел интересный проект: www.rubymotion.com

      Компилятор (!) диалекта Ruby, построенного поверх ObjC runtime.
      Теперь под iOS можно писать на нормальном языке с преферансом и гимназистками богатой стандартной библиотекой, лямбдами, DSL, REPL и другими нямками.
      При этом оно понимает любые objc-фреймворки и позволяет почти прозрачно вызывать сишные функции.

      Из минусов:
      1. хотят много денег ( $200 $150) 
      2. использует ARC, поэтому циклические ссылки не разруливает :

      в копилку ненависти к objc

      У NSArray отстуствует метод поиска по предикату. Есть filteredArrayUsingPredicate: и filterUsingPredicate: (ну да,  длинные имена -- наше все) есть, а какого-нибудь findFirstUsingPredicate: - нету.

      вот и плодятся по коду кусочки вида

      id object = nil;
      for (id x in array)
        if (condition(x))
           break;
      
      
      Казалось бы, четыре строчки вместо одной, да и добавить такой метод -- не проблема, но раздражает, что нет "искаропки".

      Да и предикаты в obj-c -- это нечто.
      Пытались сделать LINQ, а получили недо-SQL в стрингах.

      Справедливости ради стоит заметить, что в языке есть "блоки" (которые почти лямбды из С++11), и предикаты можно создавать на их основе.



      2012-04-25

      ObjC vs Java

      Серия постов о том, чего, по мнению Java-программиста, не хватает в ObjectiveC.
      Ну, и мои мысли по этому поводу.
      TL;DR: Отсутствие namespace и ручное управление памятью -- зло. ObjC -- не мой любимый язык.
      1. дженерики  для динамического языка не очень критичны (в питоне, к примеру, их нет, а в ActionScript -- есть всего один дженерик)
      2. Нет абстрактных методов. Согласен. С точки зрения "классического" ооп, отсутствие abstract и protected методов не дает задать контракт между базовым и дочерними классами. Приходится извращаться с методами, бросающими исключение -- что работает только при нормальном покрытии юнит-тестами. 
      3. Хидер+Реализация(*.h/*.m) vs один файл. Спорное высказывание. Хотя с одним файлом работать и удобнее, наличие отдельно вынесенного публичного интерфейса есть хорошо.
      4. Пространства имен. ППКС. Отсутствие пакетов или пространств имен в объектно-ориентированном языке -- это, мягко говоря, извращение. 
      5. Исключения.  В ObjC они более "многословны", чем в других языках, на этом, имхо, все отличия и заканчиваются. 
      Из других минусов языка автор не назвал многословность (да-да, тот самый синтаксический оверхед :) ). Возможно, потому, что по сравнению с явой он не столь велик.
      Защитники ObjC скажут "зато имя метода отражает, что он делает", но методы вида
      - (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect ofDividerAtIndex:(NSInteger)dividerIndex или константы длиной в 65 символов это тот случай, когда, сфокусировавшись на деревьях, не видно леса.

      Кроме длинных идентификаторов, многословность вызвана еще одним недостатком языка:
      Авторы языка так и не смогли определиться с управлением памятью.

      В Managed языках все просто -- там изначально есть GC.

      В C++ есть деструкторы объектов на стеке, что привело к концепции "умных" указателей: сперва пусть кривой, но стандартный std::auto_ptr, потом появились труды Александреску, бустовкие intrusive_ptr и shared_ptr/weak_ptr, которые и стали стандартом сначала де-факто, а потом и де-юре.
      Move-semantic в С++11 с одной стороны, была революцией (как писали авторы стандарта -- "мы сломали почти все книги о эффективном программировании на С++"), с другой -- слегка поменялась форма, но не содержание -- заворачиваем объект в умный указатель и расслабляемся.

      В ObjC же управление памятью развивалось этапами.

      Изначально временем жизни управлял сам программист, создавая объект через метод класса alloc и управляя его жизнью, увеличивая счетчик ссылок через retain и уменьшая его вызовом release. То есть ручное управление временем жизни объектов. И сдесь разработчики допустили еще одну ошибку: они сделали создание объекта двухфазным: сперва выделение памяти (обычно alloc), потом инициализация (init или initWith...).  Изначально это было сделано для поддержки кастомного распределителя памяти (allocWithZone:), но, по-моему, этим никто никогда не пользовался. Получаем запись вида
      Type * x = [[Type alloc] initWith:y];

      И тут появляется хитрая политика владения: если в названии метода есть слова copy, alloc, new, то метод возвращает объект с увеличенным счетчиком ссылок, иначе -- с тем-же. То есть, налицо попытка решения технической задачи административным путем.  
      Ну, и проблему циклических ссылок никто не отменял. 

      Потом появилась концепция Autorelease Pool. Объекты, зарегистрированные в нем, удаляются при очистке пула, если на них больше никто не ссылается. Пулы образуют свой стек, что позволяет при выходе из метода, к примеру, подчистить за собой (ну, если не забыть вызвать у пула drain или release];
      У стандартных классов появились методы вида [Type typeWithY:y], возвращающие объект в полумертвом состоянии (уже зарегистрированным в текущем авторелиз пуле) 
      И вместо того, чтобы переделать стандартную библиотеку, объявив цепочку alloc-init deprecated, разработчки языка пошли по легкому пути и просто добавили autorelease в базовый класс.
      А теперь сравните код

      TypeX * x = [[[TypeX alloc] initWithTypeY:[[[TypeY alloc] initWithY:y] autorelease]] autorelease];
      
      и 
      
      TypeX x = TypeY(y); // Если на стеке
      
      
      // или, если объекты выделять в куче.
      std::shared_ptr<TypeX> x = std::make_shared<TypeX>(std::make_shared<TypeY>(y));


      В ObjC 2.0 добавили свойства, что позволило не копипастить типичный для геттеров и сеттеров код. Но управление членами класса осталось на том-же уровне (retain в init, release в dealloc, если забыл - то ССЗБ)

      Потом был GC, который объявили deprecated быстрее, чем он стал мейнстримом. Ну, не deprecated, но "ARC is preferable now". Automatic Reference Counting - это автоматическая вставка retain/release, если статический анализатор Clang считает, что они тут нужны. Если имена ваших методов следуют административным ограничениям (увеличивающие кол-во ссылок методы содержат слово alloc, copy, new, retain ; не меняющие -- не содержат; плюс несколько макросов/ключевых слов типа __strong или __weak), то все будет хорошо.

      Если у вас есть циклические ссылки или кто-то нарушил правила  - ой. Хорошо если просто утечка, но может быть и дабл-фри. Который крайне тяжело отлаживать, ибо падает обычно внутри Autorelease Pool.

      После того, как некоторое время пописал на ObjC, дико хочется обратно на C++.


      2012-04-24

      Эльфы 14-го уровня среди нас. Чувствую себя лузером со своими 4/115.

      2012-04-20

      [trick] чтение из /dev/[u]random

      Баг: генератор ключей выдает один и тот же ключ, если интервал между запусками достаточно мал.

      Лезу в код, вижу примерно такое.

      template <typename T>
      RandomGenerator::RandomGenerator() {
        T seed = 0;
        {
          std::ifstream in("/dev/urandom");
          in >> seed;
        }
        if (!seed)
          seed = clock(NULL);
        ... // далее seed используется, чтобы инициализировать один из бустовских ГПСЧ.
      }
      

      Далее этот класс инстанциируется для T = uint32_t.
      Первое, что бросается в глаза, что /dev/urandom мы открываем как текстовый файл. А потом пытаемся читать из него 4хбайтное целое.

      Добавил ios::binary -- лучше не стало.

      Вынес в отдельный файл, стал экспериментировать.
      Не читается uint32 из '/dev/random'.
      Поменял тип на char - читает.
      На short - опять не читает.
      И такое поведение одинаково на osx, linux и freebsd.

      А потом я вспомнил, что /dev/[u]random - это character device.

      2012-04-18


      Гуглил доку, случайно нажал "Перекласти цю сторінку"
      Заголовок таба "какао - миша вниз" вынес мозг. 

      о копипасте.

      На программистcкой клавиатуре сочетание Ctrl+C (Cmd+C) должно бить током.

      2012-03-27

      boost::filesystem fix

      Не прошло и полтора года (четырнадцать месяцев таки прошло), как приняли мой патч к boost.filesystem v3, исправляющий replace_extension.
      Ждем-с 1.50 и убираем костыли.

      2012-03-04

      ехал value через value

      Из "накоженного":
      serialize(stream, value.value.value);
      if (value.value.value)
          serialize(stream, value.value.kind);
      

      2012-02-23

      "оптимизаторы", блин

      Прочитал цитату на ITHappends
      Смотрю код высоконагруженного сервера. В ядре обсчёта вижу код типа:

      func() {
      ObjectGame* OG=MainOG;
      while(OG->next!=NULL)
      {
      ia=(int*)OG+12;
      i=*ia;
      /* что-то делает*/
      *ia=i;
      /* код функции, внутри функции ia претерпевает различные изменения*/
      OG=OG->next;
      }
      }


      С большими глазами иду к прогеру, который это всё написал. Спрашиваю: почему он не пользуется методами Set и Get, и вообще, почему именно 12 байт?

      На что он мне отвечает: «Внутри кода функции есть ветвящийся цикл, в котором перебираются многие параметры объекта. Если пользоваться методами Set и Get, а это переход по адресу, причём у каждого объекта он свой, конвейер процессора офигеет и сбросится. Это плюс 30 тактов на каждый переход. Всего таких объектов в секунду надо обсчитать порядка нескольких миллионов. Частота ядра — три миллиарда операций в секунду. Отсюда вывод: идите вы лесом со своим ООП!»

      Меня аж передернуло.

      >> ia=(int*)OG+12;
      а потом этот код скомпилировали другим компилятором, на другой платформе, под другую архитектуру или с другими настройками(тут даже переключение debug/release может выстрелить). И happy debugging готов. Функция продолжает считать быстро, но выдает ошибочный результат.

      >>  Если пользоваться методами Set и Get, а это переход по адресу, причём у каждого объекта он свой,
      Лолчто?

      Отсюда вывод: гнать нахер таких "оптимизаторов" из професии.


      2012-01-10

      status $ haskell + projectEuler

      Продолжаю на досуге мучить haskell и решать задачки с "Проекта Эйлер".
      Решил over 90 задач, уже в топ-50 по Украине
      Среди знакомых ников в первой сотне есть adept и jdevelop (оба тоже с haskell)
      Задачки разные -- в основном всякий матан: простые числа, числа фибоначчи, "фигурные" числа, функция Эйлера, Диофантовы уравнения, цепные дроби, комбинаторика... посчитать сумму, посчитать разность... посчитать кол-во, найти минимум ....
      Есть немного динпрога, часто в в виде задач на поиск пути.
      Пару задач уже встречал то-ли на ACM, то ли на тренировках к нему.
      Из более "прикладных" задач понравилось "54: даны карты двух игроков в покер. определить, сколько раз выиграл первый", "59: дан неизвестный текстовый файл, зашифрованный xor-ом c 3-хсимвольным неизвестным паролем, расшифровать брутфорсом" и "96: написать решалку судоку",

      "Pure C" Ненависти Псто.

      Пишу обвертку вокруг одной библиотеки, написанной на "сишечке".
      • Пяток структур и полсотни функций в каждом хидере, документирована от силы четверть. Итого -- тысячи функций, которые вроде бы умеют все, но чтобы сделать что-то, на пол-шага отличающееся от примеров, приходится достаточно долго курить, а клиентский код получается весьма обширным. В результате -- за деревьями не видно леса.   
      • Отсутствие модификаторов доступа в С -- мне как клиенту библиотеки непонятно, какие данные я могу менять напрямую, а какие -- через функции библиотеки. Можно было бы спрятать приватные данные в pimpl, но автор до этого не додумался.
      • Pure C реализации вектора/списка/хешмапы. Через void*, по другому ведь никак. Типобезопасность? Нет, не слышали. Хорошо, если комментарий есть -- "в этом списке char*, в этом -- struct foo*. В динамических языках хоть ассерт можно поставить, в С -- либо все ок, либо расстрел памяти.
      • Вау, автор додумался до идеи конструктора/деструктора. Поэтому для каждой струкутры есть
        struct lib_foo * lib_foo_new(/*параметры*/); 
        void lib_foo_free(struct lib_foo*);
        
        даже если это
        struct lib_foobar {
          int fb_foo;
          int fb_bar;
        };
        
        Соответственно, все обьекты выделяются через malloc в хипе, в том числе и члены членов членов членов главной структуры. 
      • А до виртуального деструктора автор не додумался (Или решил, что это оверхед). Поэтому при оборачивании обьекта в умный указатель приходится постоянно передавать ему делитер.
      • Привычка добавлять сокращенное имя структуры как префикс поля (те самые fb_) в примере выше. В результате -- в клиентском коде будет куча копи-пасты вида
        lib_foo_list * fill_foo(...) {
          lib_foo_list * foos = lib_foo_list_new();
          fill(foos->foo_list, ...)
          return foos;
        }
        
        lib_bar_list * fill_bar(...) {
          libbar_list * bars = lib_bar_list_new();
          fill(bars->bar_list, ...)
          return bars;
        }
        
        lib_baz_list * fill_baz(...) {
          libbaz_list * bazs = lib_baz_list_new();
          fill(bazs->baz_list, ...);
          return bazs;
        }
        
        которую не засунуть в шаблон.
      • Попытка сэкономить на копировании приводит к странному контракту функций - если функция завершилась успешно -- она владеет переданными обьектами. Если с ошибкой - то обьектами владеет клиентский код. Отсюда: 
        1. В клиенской функции нужна секция обработки ошибок. 
        2. Это не типичная для "сишечки"
          clear_foo:
            lib_foo_free(foo);
          clear_bar:
            lib_bar_free(bar);
            
          return err; 
          
          а нечто позапутанней с дополнительными return-ами или goto-ми
      • Еще запутанней с функциями, принимающими char*. Одна функция копирует переданную строку, соседняя -- ее "овладевает". Комментариев обычно нет, смотри примеры или исходный код. И да, строки мы копируем через strdup, а длину меряем через strlen.