Инструменты пользователя

Инструменты сайта



// C++: операторы сравнения для структур

Памятка:

Т.е. используя std::tie() вполне, без труда и пыли, можно сделать операторы сравнения для сложных структур. Сложности могут возникнуть, если нужно переопределить операторы сравнения для отдельных элементов (например: критерии сравнения строк).

Почему tie, а не напрямую tuple? tie захватывает аргументы по ссылке - экономия на копировании.

// C++17 Features

Пока лучший, что я нашёл, обзор новых фич C++17 с примерами и информацией о поддержке в компиляторах:

А вот обзор от команды Яндекса, которая теперь представляет РГ21 C++ Россия:

Вот и другие авторы начинают подтягиваться, в том числе - официальные источники:

// C++: алгоритмы с бинарным предикатом и значением

Или век живи - век учись.

Проблема описана здесь: https://stdcpp.ru/proposals/1386b162-0cde-49b7-a41e-90f2d9ee477c.

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

// CMakeProjectManager2: теперь и с Server Mode

Вот и прошло почти два месяца с последних изменений.

Время было потрачено:

  1. для ожидания некоторой стабилизации апстрима, так как, по сути, они требовали писать абсолютно новый код для реализации текущего функционала, а в условиях сильных и фатальных изменений, переписывать свой код на каждый чих… у меня столько времени нет.
  2. была предпринята неудачная попытка продвинуть код в апстрим.
  3. ну и изучался новый код, когда выпадало время, плюс раздумья - как применить функциональность и для серверного режима работы CMake.

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

Есть и изменения. Малой кровью была создана обёртка поверх Server Mode Reader'а, которая предоставляет всего его внутренние профиты за исключением классического вида дерева файлов.

Соответственно изменения, сделанные для старого ридера (Tealeaf Reader), который используется для версий CMake младше 3.7, в части отображения всех файлов, добавления, удаления и переименования теперь применимы и для Server Mode Reader.

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

Функциональность же передачи Toolchain файлов выла дропнута. Можно делать настройки через Kit или же вручную создать параметр CMAKE_TOOLCHAIN_FILE и задать нужный. Главное не забудьте сделать Build → Clear CMake Configuration после этого. Ну и будьте готовы, что парсер C++ вас перестанет понимать, как минимум, частично.

Пакеты для Ubuntu 14.04 и 16.04 и производных уже доступны через PPA. Не забываем внимательно читать описание репозитория.

В ближайших планах подготовить ветку для стабильной версии QtC - 4.2. Там окажется только текущая функциональность и нового появляться не будет (если только кто-то не возьмёт её на сопровождение). Есть вероятность, что серверный режим будет выключен, так как он требует много смежных изменений и бекпортирования. Явные косяки тоже будут переноситься. В будущем, планирую саппортить только текущую версию QtC. Для старых не планирую даже исправления ошибок переносить. На всё это нужно время.

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

Ну и с ошибками и предложениями: https://github.com/h4tr3d/cmakeprojectmanager2/issues

// CMakeProjectManager2 возвращается

В продолжение Qt Creator, CMake и судьба CMakeProjectManager2.

Ревью https://codereview.qt-project.org/#/c/180827/ расставило точки над i: "Project View == Build System View", билд система не может отображать все файлы проекта? Значит не будем показывать. Билд система не предоставляет возможности добавлять, переименовывать и удалять файлы в проекте? Значит не будем даже пытаться предоставить возможность это делать. Не удобно? Ничего, целостность концепции важнее.

Хотя… мне одному кажется, что абстракции тут текут? Ведь Project View сам по себе подразумевает именно проект?

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

Ну и обоснование всего одно: «Я боюсь баг-репортов».

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

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

Ну а родной менеджер начнёт поддерживать данную функциональность, только кода CMake Server Mode сподобится на это. Удачи в ожидании :) Особенно при том условии, что конкуренты (KDevelop, Clion) это умеют делать.

// Qt Creator, CMake и судьба CMakeProjectManager2

Проект в стадии прекращения работы над ним…

// C++ и хорошие практики

Существуют хорошие практики программирования и их стоит изучать. Часть из них применима не всегда. Часть стандартов хорошо себя зарекомендовала, но стоят денег, например MISRA C++, но, помимо цены, ещё и достаточно консервативен и покрывает только язык до стандарта C++11 (выпущен в 2008 году).

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

  • The C++ Core Guidelines - естественно на первом месте, руководство от, можно сказать, создателей, корифеев языка. Основные составители Бьярне Страуструп, Герб Саттер и, конечно, сообщество. Развивается оперативно и быстро адаптируется под новые фишки стандарта.
  • High Integrity C++ Coding Standard - коротко и по делу. Немного пояснения: https://en.wikipedia.org/wiki/High_Integrity_C%2B%2B. Сейчас покрывает C++11. На этот стандарт даёт отсылки MISRA C++ 2008.
  • Все книги из Скотта Майерса из серии Эффективное программирование на C++.

Ну и на затравку: писать надёжный софт на C++ можно - C++ on Mars: Incorporating C++ into Mars Rover Flight Software ;-)

И стоит помнить, что есть практики, есть стандарты, но не стоит выключать свой мозг и обкладываться паттернами, бустом и прочими непотребствами, если вам нужно вывести всего лишь «Hello, world!».

// IncludeOS

Не мог обойти вниманием сиё творение.

Ребята запилили на суровом C++11/14 однозадачную сервисо-ориентированную операционку. Суть: операционка с минимальным футпринтом (образ 707кб), которая обслуживает ровно одну задачу (в их терминологии - сервис) и работает под управлением виртуальной машины: KVM, VirtualBox, используя возможности аппаратной виртуализации.

Сама операционка внутри представлена в виде асинхронного фреймворка, призванного, в первую очередь, строить сетевые приложения. Т.е. внутри реализован стек TCP/IP (судя по описанию, пока только IPv4, но IPv6 активно пилится). Многопоточность не поддерживается, реализован подход с кооперативной многозадачностью, которых очень хорошо ложится на асинхронную модель. Есть базовая поддержка файловых и дисковых операций (как минимум есть поддержка RAM-диска и файловых систем Ext4 и FAT).

При всём этом доступны для использования libc++ от LLVM (в том числе исключения), stdc в лице newlib.

В общем, интересное решение для сервис-ориентированных архитектур, для создания выделенных микросервисов. Плюс приятная лицензия: Apache2.

Ну и ссылки:

// Awesome C++

Вырвано из G+:

С сайта:

A curated list of awesome C/C++ frameworks, libraries, resources, and shiny things

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

Список раньше хостился на GitHub, теперь обрёл второе рождение в виде сервиса.

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

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

// std::string_view и временные объекты

Идея поста родилась при употреблении чая во внутрь на южной кухне.

Недавно смотрел один доклад (точнее бегло просматривал) про Rust и в момент, когда начался рассказ про life-time, глаз зацепился за такой опасный пример из мира C++:

string get_url()
{
  return "http://htrd.su";
}
 
string_view get_schema(string_view v)
{
  // тут какие-то действия, я их опущу
  auto result = v;
  return result;
}
 
int main()
{
  auto v = get_schema(get_url());
}

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

В общем, из природы string_view следует и проблемы в коде выше: get_url() вернёт временный объект, который будет уничтожен в конце выражения, а следовательно, v будет ссылаться на невалидный участок памяти.

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

// C++ и 2D графика

Навеяно.

Из того, что мне понравилось:

    • Язык: C
    • Реализация: библиотека
    • Реально проста для простых применений. Куча примеров и статей в интернете. Поддерживает достаточно большое число платформ и компиляторов.
    • Язык: C++
    • Реализация: header-only
    • Библиотека отличается феноменальной простотой установки: только один заголовочный файл и всё. Минусом будет только тот факт, что нужно будет указать правильные флаги линковщика для целевой платформы. Но при этом весь базовый функционал для рисования и процессинга изображений присутствует. Дружится с OpenCV. Думаю, стоит рассматривать вариант этой библиотеки, когда нужно что-то по-быстрому нарисовать.
    • Язык: C++
    • Реализация: библиотека
    • С данной библиотекой особо не имел дел. Но примеры представляют её эдаким вариантом SDL, но на C++. Стоит попробовать.

Кроме того, на ресурсе cppreference.com есть свой список библиотек под различные задачи (в дополнение к предыдущему посту), и, в частности, для графики.

ЗЫ по ссылке выше есть интересная библиотечка для пользовательского интерфейса (GUI): nana, стоит пощупать. А так же для TUI: cwidget.

ЗЗЫ прочие ссылки:

// Коллекция ресурсов по современному C++

На RSDN промелькнуло, может ещё кому полезно будет:

Кто хочет дополнить - шлите мёрж-реквесты.

Прочие полезные ссылки, спасибо @sikmir:

// std::cout, std::cerr и std::clog

Сначала немного информации из мира С.

При запуске приложения (речь идёт о POSIX) вместе с ним открывается 3 файловых дескритоптора:

  • 0 - ассоциирован со стандартным вводом (stdin)
  • 1 - ассоциирован со стандартным выводом (stdout)
  • 2 - ассоциирован со стандартным выводом в поток ошибок (stderr)

В стандартной библиотеки Си используется FILE*-based буфферизируемый доступ к файлам и терминалу. В stdio.h объявлены следующие глобальные символы, которые отражают стандартные потоки ввода вывода:

  • stdin
  • stdout
  • stderr

Соответственно их свободно можно использовать вместе с семейством функций fread()/fprintf(), обеспечивая буфферизированный доступ.

Сами файловые дескрипторы POSIX объявляет через макросы в unistd.h:

  • STDIN_FILENO
  • STDOUT_FILENO
  • STDERR_FILENO

Соответственно их свободно можно использовать со всем семейством функций read(), write() и, даже, select()/epoll() и fcntl() (например, при помощи fcntl(O_NONBLOCK)+select+read можно реализовать аналог getch() из старого доброго Borland C++). Доступ через эти функции не буфферизирован.

Доступ к одному потоку разными механизмами в одной программе лучше не осуществлять: буферизация это уровень библиотеки C и внутреннего устройства FILE. write() или read() ближе к системным вызовам и ничего про это знать не обязаны. Как результат можете получить перемешивание текста даже в однопоточном приложении. Это не отменяет того файла, что сам fwrite() может, в конце концов, вызвать write().

На этом экскурс закончим и вернёмся в C++.

В C++ для работы с потоками служит библиотека iostream. Причём доступ к конкретному стриму может быть как буфферизируемым так и не буфферизируемым (зависит от потребностей).

Библиотека декларирует объекты, связанные со стандартными потоками:

  • std::cin - стандартный ввод
  • std::cout - стандартный вывод
  • std::cerr - стандартный вывод ошибок и
  • std::clog - для логирования

Про std::cin особо гооврить (пока?) не будем - он один, в своём роде. А вот про оставшиеся три стоит.

Итак, начнём с std::cout и std::cerr. В C++ они, помимо того, что связаны с разными дескрипторами, несколько отличаются поведением:

  • std::cout - буферизируемый
  • std::cerr - не буферизируемый

Такое отличие явственно следует из семантики использования: ошибку нужно увидеть сразу без ожидания каких-то дополнительных действий со стороны программиста типа std::flush или std::endl (он, кстати, делает и flush, поэтому, для большей производительности строки в нормальном выводе стоит заканчивать '\n', а не std::endl).

Ок, а что за std::clog? А это всего-лишь std::cerr + буферизация. И снова, семантика использования проста: диагностика может чуть и подождать, что бы не понижать производительность вывода, но смешиваться с нормальным выводом не есть хорошо, мы, ведь, можем использовать приложения в пайпе и, желательно, разделить диагностику и ошибки от обычного вывода.

Собственно, немного обобщая:

  • std::cout - используется для обычного вывода результатов работы программы на экран, эти данные могут быть переданы дальше по пайпу для обработки.
  • std::cerr - вывод сообщений об ошибке в обработке, что бы не подмешивались в основной поток и не ломали логику работы других программ в пайпе. При этом сообщение выводим максимально скоро.
  • std::clog - используем для разного рода диагностических сообщений, но когда использование std::cerr замедляет вывод из-за более частого дёргания системных вызовов, при этом, не подмешиваемся в основной поток и не мешаем работе других приложений в пайплайне.

Хорошим тоном, так же, является вывод справки по программе в std::cout, если вызвано с параметрами -h|–help - тогда её удобно смотреть в, например, less без дополнительных телодвижений, а вот справку по опциям, в случае неправильной установки какого-то параметра (или пропуска обязательного), лучше выводить (тут особой разницы не вижу) в std::cerr или std::clog.

И, на последок, лекция по поводу тормозов iostream и вообще, а как оно там внутри устроено:

// Source Specific Multicast и Asio

Недавно на ru.SO проскочил вопрос: как можно подключиться к SSM (Source Specific Multicast) группе?

Нюанс в том, что для этого используется опция `MCAST_JOIN_SOURCE_GROUP` для которой нет объекта-обёртки. Но, как оказалось, такой объект пишется самостоятельно на раз-два. Под катом я продублирую свой ответ, как пример подхода реализации нужного функционала. Пример не самый идеологически правильный, но, как оказалось, рабочий. Автор сам предложил свой вариант с захватом сырого хендла. Такой подход тоже имеет смысл в некоторых ситуациях5).

5)
у меня случилось однажды так подружить сетевые абстракции Asio и libev, реализовав, тем самым, реактор на Asio :-)

// Обновление Qt Creator

Пока LOG, Habrahabr и другие гудят по поводу смены лицензионной политики в части Qt (переход на LPGL3) и QtC (переход с LGPL2.1 на GPL3 /именно GPL/ с исключением для плагинов), у меня дошли руки обновить PPA: https://launchpad.net/~adrozdoff/+archive/ubuntu/qtcreator-git

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

// C++11: несуразность std::thread

Пост-вопрос.

Может кто объяснить, почему в стандарт вошла настолько обрезанная версия реализации std::thread? Ведь предлагаемый интерфейс не предоставляет абсолютно никаких средств передачи параметров потоку в момент создания, к примеру, тот же размер стека, что крайне актуально на всяких RTOS. При этом Boost.Thread такую возможность предоставляют средствами boost::thread::attributes:

    template <class F>
    explicit thread(attributes& attrs, F f);
 
    template <class F>
    thread(attributes& attrs, F &&f);
 
    template <class F, class ...Args>
    explicit thread(attributes& attrs, F&& f, Args&&... args);

Средства хоть и лимитированные, но доступ к native_handle атрибута позволяют тюнить параметры на конкретной платформе. Но в стандартной библиотеке нет и их. Нипанимать. Explain. Explain.

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

// C++: категории итераторов

Добротное разъяснение (кому непонятно это и это (ну и по ссылкам отсюда)) категорий итераторов на ru.SO:

// Про использование ссылок и указателей в C++

Данная статья практически на 100% отражает и мой подход к использованию ссылок и указателей, рекомендую к ознакомлению:
http://eao197.blogspot.ru/2015/11/progthoughts-c.html

Тезисно:

  • void f(const T &p) ожидает реально существующий объект, но не изменяет его;
  • void f(T &p) ожидает реально существующий объект и изменяет его;
  • void f(const T *p) ожидает объект или nullptr, если объект существует, то не изменяет его;
  • void f(T *p) ожидает объект или nullptr, если объект существует, то изменяет его;
  • void f(unique_ptr<T> p) ожидает объект или nullptr; если объект существует, то забирает ответственность за его удаление;
  • void f(shared_ptr<T> p) ожидает объект или nullptr; если объект существует, то разделяет владение этим объектом (что дает право функции f() сохранить p у себя для дальнейшего использования или передать кому-то еще).

// C++: inline namespace

Как-то упустил сей момент:

Вообще FAQ стоит перечитать.

// C++11: std::error_code & std::error_condition в GCC 4.8/4.9 и 5.1

Кусок кода:

    auto ecod = make_error_code(std::errc::resource_unavailable_try_again);
    auto econ = make_error_condition(std::errc::resource_unavailable_try_again);
    assert(ecod == econ);

Согласно документации ассерт не должен срабатывать. Компилятор GCC 4.8 и 4.9 в Linux Mint собирает код и выдаёт такое при запуске:

$ ./webserver
webserver: webserver.cpp:661: int main(int, char**): Assertion `ecod == econ' failed.
Aborted

Внезапно.

GCC 5.1 собирает и нормально обрабатывает ситуацию.

// AvCpp: API-2 rework, веха вторая

Продолжаем отслеживать судьбу изменений, описанных в AvCpp: API-2 rework, веха первая.

Как обычно, объём работ отличается от того, что было запланировано. Итак, что сделано:

  1. Работа со словарями и поддержка оных во всех местах, где только можно. Это вызвало необходимость разнести открытие входного потока и поиск информации о стриме (Снова FFmpeg и low-latency). Как следствие, добавился новый вызов: av::FormatContext::findStreamInfo(). Он может принимать коллекцию словарей для каждого стрима в потоке.
  2. Начата работа над фильтрами. Уже появилась базовая инфраструктура. Но пока нет понимания в каком виде оно должно получиться на выходе.
  3. В рамках чистки кода тотально переработана обработка ошибок. Теперь это делается через std::error_code, который передаётся опциональным аргументом в те функции фейл которых может приводить к неоднозначностям в будущем. Если переменная для кода ошибки не передана, будет выброшено исключение av::Exception которое будет содержать данный код. Планируется, что набор исключений расширится под каждую сущность. Данные изменений повлекли достаточно сильные изменений в API, требующие изменений в коде приложений, которые их используют. При обработке ошибок стоит учитывать категорию оных. На дынный момент используется, как минимум три:
    • avcpp_category() - для внутренних ошибок AvCpp
    • ffmpeg_category() - для ошибок, пришедших от FFmpeg
    • system_category() - для системных ошибок, в основном так рапортуются ошибки выделения памяти при помощи встроенных av_alloc() (когда владение принимается FFmpeg'ом и он сам освобождает, как следствие, использовать new/new[] нет возможности). Целесообразность использовать std::bad_alloc обдумывается.

Ну и главное, реорганизация бранчей:

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

Что осталось:

  1. Интерфейс опций
  2. Доделать фильтры
  3. Ревизия и чистка кода в т.ч. примеров.

Планируется, что это будет сделано в следующей, третье вехе.

Как обычно, за отзывы, багрепорты и пул-реквесты буду благодарен.

// AvCpp: API-2 rework, веха первая

Для начала, что такое AvCpp - это C++ враппер над FFmpeg, позволяющий несколько упростить работу непосредственно с функциями FFmpeg.

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

Изначально структура классов опиралась на Xuggle API, ведь когда начинал его делать, многое не понимал - почему оно так. Со временем такой подход перестал мне нравится, начали вылазить всякие неприятные оверхеды, баги. Так появился подпроект API-2, цели которого:

  1. Уйти где только можно от shared_ptr (это получилось почти везде).
  2. Использовать по максимуму возможности новых версий FFmpeg, где появился reference-counting для AVFrame/AVPacket, при этом предоставить возможности создавать «тяжёлые» копии, где нужно.
  3. Более логично организовать мапинг сущностей FFmpeg в AvCpp, к примеру, если раньше AVCodecContext мапился в av::StreamCoder, то теперь av::CodecContext, аналогично для AVFormatContext (av::Container vs av::FormatContext).
  4. Корректно реализовать аудио-ресемплер
  5. Добавить побольше примеров использования API2
  6. Работа с av_options для поддерживаемых сущностей
  7. Поддержка передачи параметров через словари
  8. Тотальная переработка фильтров
  9. Чистка кода, удаление ненужных сущностей

На текущий момент на бранче api-2 уже лежат почти все эти наработки. Нереализованными остались последние 4 пункта. Приэтому, попутно, устранено несколько багов, особенно связанных с последовательностью уничтожения разных объектов (например Stream2 и FormatContext: стримом владеет FormatContext, Stream2 только предоставляет доступ к нему, при этом, даже если уничтожить объект контекста, объект Stream2 может теперь корректно рапортовать, что он инвалидировался).

Вторая веха, судя по всему, будет реализация поддержки AVOptions/AVDict, третья веха - фильтры (к слову их сейчас нет вообще в рамках API-2). Последующие вехи пока не сформированы, скорее всего нужно будет подумать над возможностями использования аппаратного ускорения для декодирования (оно достаточно некрасиво и в самом FFmpeg реализовано - нужно делать много телодвижений).

В любом случае, я уже настоятельно рекомендую начинать использовать ветку api-2. В скором времени она заместит master-ветку, а текущий мастер переедет на ветку legacy.

За отзывы, багрепорты и пул-реквесты буду благодарен.

// C++11: паттерн Transaction

Переосмысление реализации паттерна Transaction, опубликованного в "Inside C++", в рамках стандарта C++11 с блек… variadict templates и хранением данных на стеке.

// Practical Guide to Bare Metal C++

Недавно наткнулся на эту книжку на GitBook: http://arobenko.gitbooks.io/bare_metal_cpp/

Доступна для онлайн-чтения, в виде форматов ePUB, MOBI и PDF. Рассматриваются вопросы уменьшения размера приложений, написания своих реализаций ABI функций, что позволяет более детально понимать, а что там вообще внутри происходит, что бывает полезно и обычных приложениях. Вместе с ней обязательно ознакомиться с Scott Meyers. Effective C++ in an Embedded Environment.

Книга больше ориентирована на ARM, в частности Raspberry PI, но идеи адаптировать к другим платформам труда не составит.

// MinGW и локали

Если коротко, то всё, что связано с std::locale в MinGW не работает. Точка.

Зато вполне себе работает функционал из Си:

std::locale::global(std::locale("")); // не установит текущую локаль
setlocale(LC_ALL, ""); // установит текущую локаль, у меня это Russian_Russia.Cp1251

// Пополняем шпаргалки по C++: неявно-генерируемые перемещающий конструктор и оператор присваивания

Статью изначально публиковал на хабре: http://habrahabr.ru/post/232775/. Здесь - для единства мыслей :)

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

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

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

Шпаргалки представлены в виде PDF файлов для печати на принтере A4, в виде картинки PNG, а также исходников в SVG.

// C++14: Done

Стандарт отправился в печать: https://isocpp.org/blog/2014/08/we-have-cpp14

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

// erase_if

Условное удаление по значению из всяких там map и иже с ними. А так же, бонусом, наиболее оптимальный вариант условного удаления для вектора.

// Const correctness

Ничего нового, просто ссылки:

  1. http://www.cprogramming.com/tutorial/const_correctness.html - для чего нужно и почему, а так же логическая и побитовая константность.

Если коротко, то что даёт применение ключевого слова const везде, где это уместно:

  1. Уберегает вас от некоторых ошибок, связанных с внезапным изменением данных в каких-то вызовых. Т.е. добавляет безопасности.
  2. Автодокументирование кода: вы выдите const ⇒ вы знаете, что данные не меняются ни в этом вызове, ни далее по иерархии.

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

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

Обычно последнее связано с полями, которые имеют спецификатор mutable. Для чего они нужны? Самый простой пример: экземпляр класса может использоваться из разных потоков. Писать может один поток, а читать другой. Логично, что метод для чтения будет константным. Так же логично, что чтение и запись следует защитить мьютексом. Но если мы попробуем заблокировать мьютекс в константном методе, получис ошибку компиляции. Понятно, что изменение мьютекса никак не влияет на логическую константность класса, поэтому его можно объявить mutable и спокойно защищать им данные.

Из примера выше можно сделать такое неформальное заключение:

Побитовая константностью - неиболее сильная. Логическая - более слабая.

// std::begin() и std::end()

С приходом нового стандарта эти две свободные функции появились в STL, в библиотеке итераторов (#include <iterator>). Кроме того, в примерах кода часто можно увидеть, что они используются на STL контейнерах вместо собственных методов .begin() и .end():

#include <iostream>
#include <vector>
#include <iterators>
 
using namespace std;
 
int main()
{
  vector<int> v{1, 2, 3, 4, 5};
 
  for (auto it = begin(v); it != end(v); ++it)
  {
    cout << "Number: " << *it << endl;
  }
 
  return 0;
}

Мне хорошо понятно, что эти функции отлично подходят для RAW-массивов, т.е. если в примере выше заменить:

vector<int> v{1, 2, 3, 4, 5};

на

int v[] = {1, 2, 3, 4, 5};

или даже

int v[]{1, 2, 3, 4, 5};

То весь остальной код менять не нужно. Удобно, причём мы защищены от подсовывания указателя вместо массива. Но почему они применяются для STL контейнеров?

Поиск по интернету дал только один ответ: для унификации. И только.

Т.е. ни по «кошерности» ни по скорости два этих подхода не отличаются. Чисто для единства вида.

Если у кого есть другие предположения - милости просим в дискуссию.

Ссылки

// Qt Creator и C++11

Небольшая заметка о том, как форсировать поддержку C++11 в парсере для различных билд-систем. Заметки касаются master-снапшота QTC (брать тут: http://download.qt-project.org/snapshots/qtcreator/master/latest/ или собирать из исходников).

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

// C++ и копирование перекрывающихся областей

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

В мире С++ никто не запрещает пользоваться этими функциями (часто эти функции используют различные механизмы оптимизации и могут статься быстрее своих собратьев из мира C++), но есть и более родное средство, работающее через итераторы: std::copy. Это средство применимо не только к POD типам, а к любым сущностям, поддерживающим итераторы. О деталях реализации в стандарте ничего не сказано, но можно предположить, что разработчики библиотеки не настолько глупы, что бы не использовать, оптимизированные memcpy()/memmove() когда это возможно.

Но по наитию, хочется посмотреть, а что там с пересекающимися областями (overlapping memory blocks)? Ведь задача, на самом деле, не такая уж редкая. К примеру, хотим мы читать MPEG-TS пакеты (размер каждого 188 байт, каждый пакет начинается с 0x47 /sync byte/) из какого-то потока, и есть вероятность, что первое (а может и последующее, либо имеем дело с M2TS контейнером, размер блока которого 192 байта и лишние 4 байта в большинстве случаем мы можем игнорировать) чтение может попасть на середину пакета. В таких случаях обычно делается так: вычитываем блок 188 байт, далее ищем байт синхронизации, если он в нулевой позиции - всё отлично, если нет, то данные от него и до конца, нужно переместить в начало блока, в освободившееся место нужно дочитать недостающу порцию, после чего пакет считается вычитанным и можно отдавать его на обработку.

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

Т.е. видим, что есть перекрытие. Логично, было бы применить какой-то аналог memmove(), но в стандартной библиотеке есть только std::move который делает совершенно не то. Но при этом, читая описание для std::copy (http://www.cplusplus.com/reference/algorithm/copy) видим следующую строчку:

The ranges shall not overlap in such a way that result points to an element in the range [first,last).

т.е. на самом деле, если начало области (result) куда копировать, лежит вне области [first,last), то всё должно быть ок. И это реально так.

Но посмотрим такую схему копирования с перекрытием:

пока не обращаем внимание на то, что result тут в конце. Смысл картинки в том, что блок памяти нужно сдвинуть с начала на какое-то смещение вперёд, соответственно если это смещение меньше размера сдвигаемого блока, то адрес назначения у нас будет лежать в пределах [first,last), таким образом условие применимости std::copy не соблюдаются. И если применить его, мы просто затрём данным в перекрывающейся области.

Но тут на помощь нам приходит его собрат, как раз решающий эту проблему: std::copy_backward, всё отличие этой функции в том, что он осуществляет копирование с конца. Т.е. для случая изображённой на второй картинке, он возьмёт (далее очень грубо, т.е. на самом деле last и result это указатели на конец блока, а ближайшие данные находятся по last-1 и result-1) элемент из last и ложится в result, далее из last-1 в result-1, далее из last-2 в result-2 и так далее.

Видно, что при такой схеме копирования, когда мы начнём писать в перекрывающуюся область, данные в ней уже будут обработаны. Т.е. для нас всё хорошо. Забавно, что условие применимости при перекрывающийся областях для std::copy_backward слово в слово повторяет данное условие для std::copy.

Итак, резюмируя, простое правило:

  • Если result < first («сдвиг блока к началу /или влево/»), то применяем std::copy, в качестве result указываем НАЧАЛО блока-назначения.
  • Если result > first («сдвиг блока к концу /или вправо/»), то применяем std::copy_backward, в качестве result указываем КОНЕЦ блока-назначения.

Текст является творческим переосмыслением англоязычной статьи: http://www.trilithium.com/johan/2006/02/copy-confusion, картинки взяты от туда же, пример из собственного опыта.

Референс:

PS Статья была опубликована на Habrahabr: http://habrahabr.ru/post/218451

// C++11 regex

В синтаксисе регулярок в GCC 4.8.1/libstdc++4.8 нет поддержки квадратных скобок: []. Пришлось использовать Boost.Regex

Ах да, пруф: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631

// Эффект плазмы

Во многих системах есть хранитель экрана который показывает примерно следующее:
plasma_effect.jpg

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

// На заметку: чисто виртуальные функции с определением

Да, речь про такое:

struct Foo {
  virtual ~Foo()      = 0; // [1]
  virtual void proc() = 0; // [2]
};
 
// [3]
Foo::~Foo() {
  // some actions
}
 
// [4]
void Foo::proc() {
  // some actions
}

[3] и [4] для [1] и [2] соответственно могут находится в другом файле.

Информации в интернете много, поэтому заметка для себя, ибо где-то пропустил в изучении. Далее мои домысли и моё понимание проблемы.

Начнём с [2].

Такое нужно:

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

Например:

struct Bar : Foo {
  virtual void proc() {
    // здесь полностью своя реализация
  }
};
 
struct Baz : Foo {
  virtual void proc() {
    // а здесь мы позвали реализацию по умолчанию.
    Foo::proc();
  }
};
 
struct Bak : Foo {
  // а такой класс мы инстанцировать не сможем
};

А теперь про [1]

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

/tmp/cc42YqK5.o: In function `Bar::~Bar()':
main.cpp:(.text._ZN3BarD2Ev[_ZN3BarD5Ev]+0x1f): undefined reference to `Foo::~Foo()'
collect2: error: ld returned 1 exit status

Т.е. тело у деструктора должно быть всегда (ну не совсем, см. ниже). Так когда возникает необходимость сделать деструктор базового класса чисто виртуальным с определением? Мне в голову пришло только:

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

Поясню. Если сделать так:

struct Virtuable {
  virtual ~Virtuable() {}
};

Все классы-наследники автоматом будут с виртуальными деструкторам, но при этом мы можем сделать такое:

Virtuable f;
Virtuable *p = new Virtuable;

Т.е. мы можем создать объекты-пустышки. А зачем нам это? Если же объявить класс так:

struct Virtuable {
  virtual ~Virtuable() = 0;
};
 
Virtuable::~Virtuable() {}

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

Имхо, может быть полезно во всяких фабриках.

// Онлайн компиляторы C/C++ и не только

Иногда нужно быстро проверить работоспособность какой-то идеи или алгоритма. Хорошо, когда у вас Linux и какая-то система из семейства Unix с установленным компилятором (имхо, в 90% случаев это будет правдой), вам просто нужно открыть консоль вызвать vim/emacs/joe/mcedit/etc набросать программку и вызвать компилятор. Но иногда вы в гостях/командировке/интернет-кафе, в общем тогда, когда компилятора нет под рукой, но есть доступ в интернет. Тут помогут онлайн-компиляторы.

// Забавный баг

Есть некая система (embedded), у которой вся память поделена на пулы различного размера и способы выделения память (фиксированный размер, переменный размер). Есть механизм для выделения памяти из этих пулов (на основе размера аллокации подбирает подходящий пул и делает от туда выделение) и возвращение её туда, примем его таким:

void *pool_alloc(size_t size); // выделение памяти из пула
void *pool_calloc(size_t size); // выделение памяти из пула и зануление её
void pool_free(void *ptr); // возврат (освобождение) памяти в пул

есть так же определённые операторы new/new[]/delete/delete[] для использования этого механизма в C++ коде (код сильно упрощён):

void* operator new (size_t size)
{
    return pool_alloc(size);
}
 
void* operator new[] (size_t size)
{
    return pool_alloc(size);
}
 
void operator delete (void *ptr)
{
    pool_free(ptr);
}
 
void operator delete[] (void *ptr)
{
    pool_free(ptr);
}

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

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

struct BigStruct 
{
    // a lot of fields
};

Соответственно память под эту структуру выделялась и освобождалась так:

...
big_struct_ptr = (struct BigStruct*)pool_calloc(sizeof(struct BigStruct)); // память сразу занулялась
...
pool_free(big_struct_ptr);
...

Время шло, код постепенно «переписывался» на C++. В кавычках, потому как это «переписывание» сводилось к изменению расширения файла на .cpp и исправлению очевидных ошибок и предупреждений (тут, с одной стороны, используется -Werror как опция для GCC, с другой стороны, предупреждение включены далеко не все). И вот, в один прекрасный момент, весь код, который использует эту структуру, уже компилируется C++ компилятором. Как результат, при очередной фиче или багофиксе в структуре появляется поле типа

std::vector<Foo> some_field;

То есть, одним мановением руки, структура перестаёт быть POD-типом, но… Механизм выделения и освобождения памяти для неё не меняется!

Теперь сделайте паузу и пофантазируйте, к чему это приводит.

На практике, это решение жило около двух лет (на момент написания статьи) и никак себя не проявляло. А приводило оно к постепенной утечке памяти: для std::vector не вызывался ни конструктор ни деструктор. Отсутствие вызова конструктора проходило незаметно, в этом конкретном примере «спасало» то, что память занулялась и у класса нет vtable. А вот отсутствие вызова деструктора приводило к тому, что все аллокации, сделанные внутри вектора, не освобождались. Маскировало эту проблему то, что аллокации были очень маленькие (около 4 байт), и их было немного за весь период нормальной работы аппарата от момента включения до выключения.

Выявило нагрузочное тестирование, где один алгоритм прогонялся атипичное, для нормальной работы, количество раз (помогло логирование вызовов new при помощи gcc'шной __builtin_return_address(), objdump -d и базовые знания ассемблера).

// Build Boost on Windows with MinGW

Чисто заметка, без вдавания в детали.

Для начала нужно поставить MinGW и MSYS.

Сделать это можно двумя путями. Первый, это поставить и то и другое средствами mingw-get-inst: http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/

Но там только GCC 4.7.2, а мне нужен был GCC 4.8 (где брать свежие сборки MinGW я уже ранее писал, замечу только, что брать нужно версию с поддержкой threads-posix и dwarf, если вдруг захочется использовать бинарные сборки Qt). MSYS поставил при помощи mingw-get (http://sourceforge.net/projects/mingw/files/Installer/mingw-get/, а можно и вручную, скачивая и распаковывая файлы отсюда: http://sourceforge.net/projects/mingw/files/MSYS/). Распаковываем его, к примеру, в C:\msys, далее:

cd C:\msys\bin
mingw-get.exe update
mingw-get.exe install msys

После этого MSYS будет расположен в C:\msys\msys\1.0. Если потребуется ещё что-то от msys: mingw-get list вам в помощь.

Далее сборка Boost (у меня 1.53.0).

Распаковываем его, например в D:\boost_1_53_0

Настраиваем пути до компилятора (делаем это из запущенной копии cmd):

set PATH=c:\msys\msys\1.0\bin;c:\mingw\bin;%PATH%

Тут обращаю ваше внимание на один факт, за который разработчикам буста нужно малость по рукам настучать: буст соберётся хорошо только в случае, если MinGW поставлен в C:\MinGW и ни как иначе!

После чего собираем bjam:

cd D:\boost_1_53_0\tools\build\v2
bootstrap.bat gcc
b2 --prefix=C:\boost install
set PATH=%PATH%;C:\boost\bin

Теперь мы готовы собирать сам буст:

cd D:\boost_1_53_0\
bjam -j2 toolset=gcc --build-type=complete --prefix=C:\boost install

Вместо -j2 ставим нужное количество потоков сборки.

После продолжительной сборки буст будет расположен:

  • заголовки: C:\boost\include\boost-1_53
  • библиотеки: C:\boost\lib

И полезные параметры при сборке:

-Wno-unused-local-typedefs -DGLIBCXX_FORCE_NEW -D_WIN32_WINNT=0x0501 -DBOOST_THREAD_USE_LIB -DBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN

Для совсем ленивых, напоминаю про альтернативную сборку MinGW от Стефана, в ней он уже обновил GCC до 4.8 и Boost до 1.53. Кстати, Стефан работает в Microsoft :-D

// C++ Template Metaprogramming

Что-то не нашёл официального русского перевода книги, только сделанный в частном порядке (читать сложновато): http://enotcpp.blogspot.ru/2011/11/c-template-metaprogramming-david.html

На английском: http://ultra.sdk.free.fr/misc/docs/Addison.Wesley.C++.Template.Metaprogramming.Concepts.Tools.and.Techniques.from.Boost.and.Beyond.pdf или среди торрентов: http://rutracker.org/forum/viewtopic.php?t=1140883

// Binary Logic Bit Operations In C and C++

На заметку: http://www.somacon.com/p125.php там же удобный калькулятор для перевода констант между четырмя популярными системами счисления (BIN, OCT, HEX, DEC)

// Qt Creator: "the debugger could not load the debugging helper library" на Windows XP

Решение подсказывают тут и тут. Если коротко: нужен GDB скомпилированный с поддержкой Python и Qt Creator на это расчитывает. По первой ссылке его рекомендуют брать в QtSDK, но качать его сильно накладно. Недолгое гугление привело на эту ссылку: http://origin.releases.qt-project.org/gdb/windows-xp/.

Устанавливатся просто: скачиваем, распаковываем, в настройках китов в Qt Creator (Tool → Options… → Build & Run → Kits) выбираем новый отладчик (для MinGW) и живём.

PS другие версии: http://origin.releases.qt-project.org/gdb/ PPS более корректные ссылки: http://builds.qt-project.org/job/gdb-windowsxp/ и http://builds.qt-project.org/job/gdb-windows/

// Scott Meyers. Effective C++ in an Embedded Environment

This PDF document contains the presentation materials from Scott Meyers' two-day training course Effective C++ in an Embedded Environment. It provides an in-depth examination of how C++ can be applied in embedded systems, including costs of language features, ROMing, ISRs, memory management, safety-critical and real-time considerations, and more.

Формат: презентация в PDF, чётко и по делу.

Для желающих получить без оплаты: effectcppemb.pdf

// OpenCV Cheat Sheet (C++)

Текщущая версия 2.4: http://docs.opencv.org/trunk/opencv_cheatsheet.pdf

Она же на этом ресурсе: opencv_cheatsheet.pdf

// Простой враппер для встроенных типов в C++

В C/C++ определение переменной не есть её инициализация. Верно для фундаментальных (или встроенных) типов. Для пользовательских типов всегда (если не указано ничего иного) вызывается конструктор по умолчанию, в котором можно принять необходимые меры по инициализации.

Враппер помогает решать задачи инициализации переменной при её объявлении, а так же при использовании в контейнерах типа std::map или std::multimap, когда нужно проверить переменную для ключа, которого ещё нет (при обращении через operator[] создастся новое значение, для которого вызовется конструктор по умолчанию).

Код:

/**
 * Can be used for built-in types only (like int, char, long and so on)
 */
template <typename T, T initialValue = 0>
struct BuiltInTypeWrapper
{
    BuiltInTypeWrapper()
        : value(initialValue)
    {}
    BuiltInTypeWrapper(T v)
        : value(v)
    {}
 
    bool isValid() const
    {
        return (value != initialValue);
    }
 
    void reset()
    {
        value = initialValue;
    }
 
    operator T&()
    {
        return value;
    }
 
    operator T const&() const
    {
        return value;
    }
 
    BuiltInTypeWrapper& operator=(T v)
    {
        value = v;
        return *this;
    }
 
    T value;
};

Для временных меток в FFMPEG можно использовать так:

/**
 * Simple wrapper for time stamp values
 */
typedef BuiltInTypeWrapper<int64_t, AV_NOPTS_VALUE> TsWrapper;

т.е. при объявлении переменной типа TsWrapper она автоматом станет инициализирована в AV_NOPTS_VALUE.

А просто для int так:

typedef BuiltInTypeWrapper<int> Integer;

При этом при объявлении переменной типа будет она будет инициализирована в 0.

За счёт определения оператора приведения типа и перегруженному оператору присваивания использование обёрнутого значения мало отличается от необёрнутого:

typedef BuiltInTypeWrapper<int64_t, AV_NOPTS_VALUE> TsWrapper;
...
 
void foo(int64_t &v)
{
    clog << v << endl;
}
 
...
 
TsWrapper wrappedValue;
int64_t   value = 255;
 
wrappedValue = value;      // 1
if (wrappedValue == value) // 2
...
 
foo(wrappedValue)          // 3
wrappedValue++;            // 4, аналогично для префиксной формы
wrappedValue--;            // 5, аналогично для префиксной формы
wrappedValue += 5;         // 6
wrappedValue -= 5;         // 7  

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

Кто какие нюансы видит?

PS тестировалось на gcc 4.7.2

// MinGW32: как избавиться от зависимостей в виде libgcc_*.dll и libstdc++-*.dll?

Почти всегда программа (особенно маленькие и без инсталлятора) для win распространяется в виде законченного бандла со всеми DLL и прочим потребством. Проблема, что программа, скомпилированная примерно так:

i486-mingw32-g++ -o foo.exe foo.cpp

как минимум требует двух DLL: libgcc_*.dll и libstdc++-*.dll, что бы избавится от них можно использовать опции -static-libgcc и -static-libstdc++:

i486-mingw32-g++ -static-libgcc -static-libstdc++ -o foo.exe foo.cpp

// Boost shared_ptr, bind и thread

Правило: при использовании boost::bind будьте предельно осторожны при передаче аргументов в виде boost::shared_ptr (как и других типов умных указателей): по умолчанию используется семантика копирования, поэтому в полученном функторе будет храниться копия вашего указателя с увеличенным счётчиком ссылок. Данный факт, вкупе с использованием совместно с boost::thread, может стать иточником утечки ресурсов.

Ниже более детально.

// Охранные классы в boost::thread

Для начала, охранные классы, это не что иное как различные *_lock классы, реализующие идиому RAII, захватывающие мутекс в конструкторе (lock()) и освобождающие его в деструкторе (unlock()) - паттерн «блокировка в области видимости». Не смог придумать более корректного перевода.

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

// Паттерн Iterator

Полезно, когда нужно перебирать последовательно какие-то данные, мне, в частности, потребовалось для перебора кодеков и форматов во C++ враппере для FFMPEG, а так же получения набора параметров и именованных констант, которые они могут принимать.

Основные идеи данного паттерна изложены по этой ссылке: http://sourcemaking.com/design_patterns/iterator, а возможные реализации на C++ здесь:

Сведения эти - общетеоретические. Более практическое описание с разделением итераторов на типы приведено на cplusplus.com: http://www.cplusplus.com/reference/std/iterator/, в частности вводятся понятие следующих типов итераторов (а так же наглядная таблица, по которой можно понять какие методы и операторы должны определяться в классе-итераторе):

А что бы несколько привести итераторы к одному виду, существует класс в стандартной библиотеке, называется ~std::iterator~, почитать можно здесь: http://www.cplusplus.com/reference/std/iterator/iterator/, там же приведён простой пример итератора.

// Using Internet Sockets

Работая над программой столкнулся с проблемой в части функционала сокетов, пока искал в интернетах возможный пути решения проблемы, натолкнулся на интересное руководство: Beej's Guide to Network Programming. Using Internet Sockets

Руководство доступно в в различных форматах (по ссылке выше можно найти подходящие), вот самые удобные, на мой взгляд:

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

Стоит отметить, что помимо всяких Linux/Unix есть информация и про Windows, в частности будет полезно при разработке кроссплатформенных сетевых приложений.

Ещё, среди кучи ссылок, в тексте обнаружилась такая полезная: UNIX Socket FAQ - тоже кладезь знаний.

В дополнение, книжка «Linux Socket Programming by Example», можно купить на Амазоне: http://www.amazon.com/Linux-Socket-Programming-Example-Warren/dp/0789722410 или:

// На правах заметки: Статический анализ кода C++

Давно пользуюсь услугами cppcheck, но решил поглядеть что есть ещё (как оказалось, лучше, по сути, ничего и нету). Наткнулся на статью по теме на хабре: http://habrahabr.ru/post/75123

Тезисно:

  • Педантичные ключи для gcc (сам автор отсылает за подробностями: http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html), особо хочется отметить неизвестный мне ключ -Weffc++, включает проверку на соответствие рекомендациям Скотта Майерса. Результат сборки моего последнего проекта поверг в уныние: будет ещё работы по вычистке.
  • cppcheck (в арчике есть в стандартных репах)
  • vera++ (есть в AUR)
  • rats (есть в AUR)
  • проверялки для чистого Си (как оказалось6) их значительно больше, нежели для C++)

Далее, Анализ утилит статического анализа C++ кода, автор рассматривает следующие анализаторы:

  • rats (выше писал)
  • cppcheck (аналогично)
  • Graudit (есть в AUR)

причём рассматривает проблемы, которые они не выявляют.

Список статических анализаторов можно поглядеть на страничке в википедии: http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis, причём не только для C/C++

Для интереса можно почитать перевод статьи Джона Кармака о статическом анализе: http://habrahabr.ru/post/135234/7), где кратко излагается, какими инструментами ему довелось воспользоваться, и какие впечатления остались после них.

И на последок серия из четырёх заметок камрада Andrey20088) «Как уменьшить вероятность ошибки на этапе написания кода»:

    1. Избегайте функции memset, memcpy, ZeroMemory и им аналогичные
    2. Внимательно следите, работаете вы со знаковым или беззнаковым типом
    3. Избегайте большого количества вычислений в одной строке
    4. Выравнивайте в коде всё, что возможно
    5. Не размножайте строку более, чем один раз
    6. Выставляйте высокий уровень предупреждений у компилятора и используйте статические анализаторы
    1. Не используйте тернарную операцию '?:' в составных выражениях
    2. Не стесняйтесь использовать скобки
  • Заметка №3 - на примерах ошибок в Qt4
    1. Обрабатывайте переменные в той же последовательности, как они объявлены
    2. Табличные методы — это хорошо
    3. Разное интересное (про разные и интересные ошибки в Qt4)
  • Заметка №4 - на примерах ошибок в Firefox
7)
Оригинал статьи: altdevblogaday.com/2011/12/24/static-code-analysis/
8)
Один из разработчиков PVS-Studio, поэтому малость пропускаем его отсылы к этому продукту