Обновить
256K+

C++ *

Типизированный язык программирования

467,39
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

Можем ли мы доверять используемым библиотекам?

Время на прочтение9 мин
Охват и читатели24K
Can We Trust the Libraries We Use?
Сейчас любое крупное приложение состоит из множества сторонних библиотек. Хочется поднять такую тему, как доверие к этим библиотекам. В книгах и статьях можно встретить очень много рассуждений о качестве кода, методах тестирования, методологиях разработки и так далее. Но я не помню, чтобы кто-то рассуждал о качестве кирпичей, из которых строятся приложения. Давайте немного поговорим об этом. Например, есть Medicine Insight Segmentation and Registration Toolkit (ITK). Мне кажется, он написан весьма качественно. По крайней мере, я заметил в коде весьма мало ошибок. Но я не могу сказать, что код используемых библиотек столь же качественен. Тогда вопрос. Насколько мы можем доверять таким системам? Есть повод для размышлений.
Читать дальше →

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

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

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

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

Читать дальше →

Проверка PVS-Studio с помощью Clang

Время на прочтение11 мин
Охват и читатели27K
Checking PVS-Studio with Clang
Да, да. Вы не ослышались. В этот раз статья «наоборот». Не мы проверяем какой-то проект, а проверили наш анализатор с помощью другого инструмента. На самом деле, подобное делали мы и раньше. Например, проверяли PVS-Studio с помощью Cppcheck, с помощью анализатора, встроенного в Visual Studio, смотрели на предупреждения Intel C++. Но раньше не было повода написать статью. Ничего интересного не находилось. А вот Clang смог заинтересовать своими диагностическими сообщениями.
Читать дальше →

Как я стенд для сборки с windows на wine мигрировал

Время на прочтение9 мин
Охват и читатели13K
image

Преамбула


Есть у меня несколько старых проектов, писанных на С++, которые все еще развиваю по мере сил. Казалось бы — в чем же дело? Увы, это пачка очередных плагинов под мой любимый Adobe InDesign.

И каждый раз, когда выходит новый Creative Suite, приходится портировать это дело. Что интересно, основные усилия уходят на то, чтобы собрать новую версию по новым правилам, и подогнуть инсталлятор. Потому как уж если дошел до стадии «оно компилируется», то как правило — работает. Хотя конечно есть нюансы — например в один прекрасный момент PlaceGun перестал раскладывать несколько выбранных изображений, только первое. Но об этом — в следующий раз.

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

Итак, для сборки, нам нужны одновременно

  • MS VS 2005
  • MS VS 2005 sp1
  • MS VS 2008
  • MS VS 2010
  • MS VS 2012


Читать дальше →

Пишем простой интерпретатор на C++ с помощью TDD, часть 3

Время на прочтение19 мин
Охват и читатели14K
В первой части был написан лексер, а во второй части — парсер. Далее будет рассмотрена разработка вычислителя и фасада для всего интерпретатора, а также рефакторинг кода для устранения дублирования.

Вычислитель


Приступим к самому интересному. Вычисление выражения в постфиксной записи можно осуществить двумя способами: через рекурсию, неявно используя стек процесса, или используя явный стек. Реализуем второй вариант. Алгоритм с использованием явного стека такой:

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

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

  • Если на входе пустой список, возвращаем 0.
  • Если на входе список с одним числом, возвращаем это число.
  • Если на входе [1 2 +], возвращаем 3.

Создадим новый тестовый класс и добавим первый тест.

TEST_CLASS(EvaluatorTests) {
public:
    TEST_METHOD(Should_return_zero_when_evaluate_empty_list) {
        double result = Evaluator::Evaluate({});
        Assert::AreEqual(0.0, result);
    }
};

Читать дальше →

Пишем простой интерпретатор на C++ с помощью TDD, часть 2

Время на прочтение16 мин
Охват и читатели14K
В первой части был написан лексер. Далее будет рассмотрена разработка парсера.

Парсер


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

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

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

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

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

  • При получении пустого списка, возвращается пустой список.
  • При получении списка с одним числом, возвращается список с этим числом.
  • При получении [1 + 2], возвращается [1 2 +].
  • При получении [1 + 2 + 3], возвращается [1 2 + 3 +], так как оператор + является лево ассоциативным.
  • При получении [1 * 2 + 3], возвращается [1 2 * 3 +].
  • При получении [1 + 2 * 3], возвращается [1 2 3 * +], так как оператор * имеет больший приоритет.

Со скобками и ошибками разберёмся позднее. Итак, напишем первый тест из списка.

TEST_CLASS(ParserTests) {
public:
    TEST_METHOD(Should_return_empty_list_when_put_empty_list) {
        Tokens tokens = Parser::Parse({});
        Assert::IsTrue(tokens.empty());
    }
};

Читать дальше →

Создание аудиоплагинов, часть 16

Время на прочтение8 мин
Охват и читатели9.3K
Все посты серии:
Часть 1. Введение и настройка
Часть 2. Изучение кода
Часть 3. VST и AU
Часть 4. Цифровой дисторшн
Часть 5. Пресеты и GUI
Часть 6. Синтез сигналов
Часть 7. Получение MIDI сообщений
Часть 8. Виртуальная клавиатура
Часть 9. Огибающие
Часть 10. Доработка GUI
Часть 11. Фильтр
Часть 12. Низкочастотный осциллятор
Часть 13. Редизайн
Часть 14. Полифония 1
Часть 15. Полифония 2
Часть 16. Антиалиасинг



Чтобы наш SpaceBass звучал еще лучше, нужно создать осциллятор, в котором было бы меньше алиасинга. Это опциональное улучшение. Без него синтезатор будет работать как и раньше, но с ним звук на верхних октавах будет значительно лучше.
Читать дальше →

Пишем простой интерпретатор на C++ с помощью TDD, часть 1

Время на прочтение17 мин
Охват и читатели51K

Введение



Многие C++ программисты слышали про разработку через тестирование. Но почти все материалы по данной теме касаются более высокоуровневых языков и сосредоточены больше на общей теории, чем на практике. Итак, в данной статье я попробую привести пример пошаговой разработки через тестирование небольшого проекта на C++. А именно, как можно предположить из названия, простого интерпретатора математических выражений. Такой проект также является неплохой code kata, так как на его выполнение затрачивается не более часа (если не писать параллельно статью об этом).

Архитектура


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

Существует множество библиотек и инструментов, которые могут облегчить разработку интерпретаторов и компиляторов. Начиная от Boost.Spirit и заканчивая ANTLR и Bison. Можно даже запустить канал интерпретатора командной строки через popen и вычислить выражение через него. Целью данной статье является пошаговая разработка достаточно сложной системы с помощью TDD, поэтому будет использоваться только стандартная библиотека C++ и встроенный в IDE тестовый фреймворк.
Читать дальше →

Анимации на лямбдах в C++11

Время на прочтение3 мин
Охват и читатели20K


Компании-разработчики, как правило, не особо спешат переходить на новый Си++. Главным образом из-за поддержки его компиляторами, а точнее ее полного или частичного отсутствия. Недавно я решил узнать, что же есть новенького в плане поддержки C++11 компилятором GCC, и понял, что пора начинать. Благо, у нас в Ivideon лояльно относятся к новым технологиям и дают пробовать что-то новое.
Начал, конечно же, с самого вкусного — с лямбда-выражений! И с потоков.
Читать дальше →

Создание аудиоплагинов, часть 14

Время на прочтение11 мин
Охват и читатели149
Все посты серии:
Часть 1. Введение и настройка
Часть 2. Изучение кода
Часть 3. VST и AU
Часть 4. Цифровой дисторшн
Часть 5. Пресеты и GUI
Часть 6. Синтез сигналов
Часть 7. Получение MIDI сообщений
Часть 8. Виртуальная клавиатура
Часть 9. Огибающие
Часть 10. Доработка GUI
Часть 11. Фильтр
Часть 12. Низкочастотный осциллятор
Часть 13. Редизайн
Часть 14. Полифония 1
Часть 15. Полифония 2
Часть 16. Антиалиасинг



Приступим к созданию полифонического синтезатора из тех компонентов, которые у нас имеются!

В прошлый раз мы работали над параметрами и пользовательским интерфейсом, сегодня мы начнем работу над лежащей в основе плагина полифонической обработкой аудио. В нашем случае мы сможем играть до 64-х нот одновременно. Это требует основательных изменений в структуре плагина, но мы сможем использовать уже написанные нами классы Oscillator, EnvelopeGenerator, MIDIReceiver и Filter.

В этом посте мы напишем класс Voice (голос), представляющий одну звучащую ноту. Затем создадим класс VoiceManager, следящий за тем, чтобы все ноты звучали и заглушались вовремя.
В следующем посте мы почистим код от ненужных устаревших частей, добавим модуляцию тона и приведем элементы управления интерфейса в рабочее состояние. На первый взгляд, работы полно. Но во-первых, у нас уже есть практически все нужные компоненты, а во-вторых, в конце у нас будет настоящий-полифонический-субстрактивный-блин-синтезатор!

Читать дальше →

Проверка Bitcoin

Время на прочтение4 мин
Охват и читатели31K
Bitcoin, PVS-Studio
Ничего эпического в этой статье не будет. Мы проверили с помощью PVS-Studio исходный код Bitcoin. Нашли всего пару подозрительных мест. Это не удивительно. Думаю, эти исходные коды не проверял только ленивый. Но раз проверили, то решил написать маленькую заметку. Так сказать, «для галочки».
Читать дальше →

Пишем на языке С/C++ в Windows под KolibriOS

Время на прочтение7 мин
Охват и читатели23K
image
KolibriOS – миниатюрная операционная система, ядро и большинство программ которой написано на языке ассемблер. Это, конечно же, не означает, что другим языкам программирования путь в KolibriOS закрыт. К примеру, за время эволюции этой операционной системы было несколько попыток разработать инструментарий или адаптировать библиотеки для создания приложений на языке C/C++. В репозитории KolibriOS до сих пор есть работающие примеры, использующие ранние наработки адаптации C/C++ кода, например (root)/programs/games/kosilka или (root)/programs/system/shell, использующие разные подходы и обертки C/Asm.

На текущее время самой перспективной из существующих библиотек, на мой взгляд, является newlib. Она состоит из адаптированной libc, C-оберкой над основными coreAPI функциями и toolchain’а для сборки.

К сожалению, в KolibriOS нативного компилятора C/C++ еще не существует, текущий toolchain предполагает сборку приложений в ОС Windows или Linux.

Данная статья является инструкцией по настройке newlib для ОС Windows.

Читать дальше →

Атрибут deprecated в С++14

Время на прочтение3 мин
Охват и читатели24K
Нормальным развитием любого кода является устаревание отдельных его частей (функций, классов и т.д.) и планомерное удаление их из проекта для снижения сложности и повышения безопасности кода. Просто убрать что-то обычно является плохой идеей — это может резко сломать какой-нибудь компонент, использующий удаляемую сущность. Хорошей практикой является пометка устаревшего кода каким-либо способом, который даст возможность использующим его программистам узнать о том, что он запланирован к удалению. (Прим. переводчика — Microsoft для этого изобрела свой велосипед, а ещё люди иногда пользовались #pragma message).

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

[[deprecated]]
void foo() {}

int main() {
	foo(); // в этом месте компилятор выведет предупреждение
}

Читать дальше →

Ближайшие события

Variadic Templates, Low Coupling и немного размышлений

Время на прочтение16 мин
Охват и читатели13K
Каждый программист, наверняка, сталкивался с ситуацией, когда в приложении имеется набор классов (возможно, сервисных), которые используются во многих участках программы. И вроде бы всё ничего, но как только появлялась необходимость менять эти классы, это могло негативно влиять и на вызывающий код. Да, как и указано в заголовке, речь в статье пойдет о том самом паттерне «Low Coupling».



Проблема не нова и давно известна. Путей ее решения может быть несколько, все зависит от предметной области. Я предлагаю читателю возможное решение, которое я нашел, занимаясь прикладной задачей. Как идеалиста, найденное решение меня устроило не полностью. Так же, оно было спроектировано в бОльшей степени от желания воспользоваться новыми возможностями стандарта C++11. Естественно, все написанное подлежит обсуждению, а возможно, кто-то предложит более стройный вариант.
Читать дальше

Генерация больших карт в ремейке игры «Caesar III(с)»

Время на прочтение3 мин
Охват и читатели30K
Если вы любитель игры «Caesar III», то наверняка замечали то, с каким старанием и вниманием к мелочам сделаны карты кампании, да и свободного режима тоже. Природные пейзажи, на которых игрок возводит «новый Рим», выглядят вполне реалистично (в рамках игры): ручейки впадают в реки и озера, реки текут через всю карту, а в лесах бродят «бессмертные» овцы, иногда забредая на луга и мешая строить фермы, чайки кружат над местами скопления рыбы, а иногда по реке проплывает неудачливый моряк на останках корабля. Скальные массивы окружены деревьями, а земля покрыта ковром сочной зеленой травы. У всей этой чудной картинки есть недостаток, размер карты не превышает 160х160 тайлов, в статье я расскажу как сделал генерацию карт больших размеров.


Все дороги ведут в Рим

Шаблонная фабрика объектов (ещё раз, и в пятнадцать строк)

Время на прочтение7 мин
Охват и читатели24K
image

Привет!

Я очень новичок в C++, программирую в общем исключительно ради своего удовольствия (причём иногда для несколько экзотичных платформ), не читал теоретических книжек, в процессе написания активно использую гугл, Stack Overflow и интуицию, а ещё придерживаюсь мнения, что C++ знать невозможно.

Надеюсь, это снимет некоторые вопросы и предотвратит удивлённые взгляды. :)
Читать дальше →

Запись данных в формате JSON

Время на прочтение6 мин
Охват и читатели247K

Запись данных в формате JSON


В одной из моих программ понадобилась запись данных в формате JSON. Вкратце — XML-подобный формат, вполне подходит на замену Windows INI-файлам или тому же XML. Удобен тем, что поддерживает массивы и вложенность собственных структур, но при этом не замусоривает файл данных своими тегами до полной нечитабельности человеком. Вот пример файла данных:
{
  "Comment":"My comment",
  "Count":10,
  "DiskParam":
  {
    "DB":10.000000,
    "DBAngle":1.234000
  },
  "Range":true,
  "Blades":
  [
    {
      "Caption":"A",
      "Value":65
    },
    {
      "Caption":"B",
      "Value":66
    },
    {
      "Caption":"C",
      "Value":67
    }
  ],
  "Slots":
  [
    0,1,2
  ]
}

Формат довольно простой, вполне можно работать с ним без всяких библиотек. Поэтому первоначально за запись отвечал примерно такой участок кода:
    fprintf(pOut, "{\n");
      fprintf(pOut, "  \"Comment\":\"%s\"", Header->Comment);
      fprintf(pOut, ",\n  \"NumSt\":%d", Header->NumSt);
      //Пропущено немного кода
      fprintf(pOut, ",\n  \"DBMax\":%lf", Header->DBMax);
      fprintf(pOut, ",\n  \"Range\":%s", Header->Range?"true":"false");
      
      fprintf(pOut, ",\n  \"Blades\":\n  [");
      for(int i=0; i<Header->Count; i++)
      {
        TElement &e=Element[i];
        fprintf(pOut, i?",\n    {":"\n    {");
          fprintf(pOut, "\"Caption\":\"%s\"", e.Caption);
          fprintf(pOut, ",\"Value\":%lf", e.BaseChar);
        fprintf(pOut, "}");
      }
      fprintf(pOut, "\n  ]");
      //Пропущено много кода
    fprintf(pOut, "\n}");

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

Решил я этот техпроцесс слегка механизировать и создать микробиблиотеку для работы с JSON.
Читать дальше →

Неопределённое поведение и теорема Ферма

Время на прочтение4 мин
Охват и читатели57K
В соответствии со стандартами C и C++, если выполнение программы приводит к переполнению знаковой целой переменной, или к любому из сотен других «неопределённых действий» (undefined behaviour, UB), то результат выполнения программы может быть любым: она может запостить на Твиттер непристойности, может отформатировать вам диск…
Увы, в действительности «пасхальные яйца», которые бы заставляли программу в случае UB делать что-то из ряда вон выходящее, не встречались со времён GCC 1.17 — та запускала nethack, когда встречала в коде программы неизвестные #pragma. Обычно же результат UB намного скучнее: компилятор просто оптимизирует код для тех случаев, когда UB не происходит, не придавая ни малейшего значения тому, что этот код будет делать в случае UB — ведь стандарт разрешает сделать в этом случае что угодно!
В качестве иллюстрации того, как изобилие UB в стандарте позволяет компилятору выполнять неочевидные оптимизации, Реймонд Чен приводит такой пример кода:

int table[4];
bool exists_in_table(int v)
{
    for (int i = 0; i <= 4; i++) {
        if (table[i] == v) return true;
    }
    return false;
}

В условии цикла мы ошиблись на единицу, поставив <= вместо <. В итоге exists_in_table() либо должна вернуть true на одной из первых четырёх итераций, либо она прочтёт table[4], что является UB, и в этом случае exists_in_table() может сделать всё что угодно — в том числе, вернуть true! В полном соответствии со стандартом, компилятор может соптимизировать код exists_in_table() до
int table[4];
bool exists_in_table(int v)
{
    return true;
}

Такие оптимизации иногда застают программистов врасплох.
Читать дальше →

О бедном C++ API замолвите словцо!

Время на прочтение15 мин
Охват и читатели44K
Желание написать об C++ API у меня возникло давно, и вот наконец выдался спокойный вечер. По роду деятельности я и мои ребята пишем код на C++ для программистов на C++ и Python, общее ядро функционала, который используется во всех продуктах нашей компании. Разумеется это подразумевает, что код должен иметь интуитивно понятный API, с общей логикой как для низкоуровневого C++, так и для высокоуровневого Python, вне зависимости от разночтения в языках некоторых базовых конструкций. Об объединении C++ и Python я много писал ранее в статьях про Boost.Python, сейчас я очень благодарен архитектуре и логике языка Python, я многое понял и перенял в С++ именно благодаря опыту построения общего API для этих двух таких разных языков, но сейчас речь пойдёт только и исключительно о C++, про API и про то, что такой зверский гибкий язык позволяет сделать с интерфейсом вашей замечательной библиотеки, если не учитывать ряд важных особенностей языка C++.
Читать дальше →

Как заставить работать бинарный классификатор чуточку лучше

Время на прочтение6 мин
Охват и читатели51K
Disclaimer: пост написан по мотивам данного. Я подозреваю, что большинство читателей прекрасно знает, как работает Наивный Байесовский классификатор, поэтому предлагаю лишь мельком хотя бы глянуть на то, о чём там говорится, перед тем как переходить под кат.

Решение задач с помощью алгоритмов машинного обучения давно и прочно вошло в нашу жизнь. Это произошло по всем понятным и объективным причинам: дешевле, проще, быстрее, чем явно кодить алгоритм решения каждой отдельной задачи. До нас, обычно, доходят «черные ящики» классификаторов (вряд ли тот же ВК предложит вам свой корпус размеченных имен), что не позволяет ими управлять в полной мере.
Здесь я бы хотел рассказать о том, как попробовать добиться «лучших» результатов работы бинарного классификатора, о том какие характеристики бинарный классификатор имеет, как их измерять, и как определить, что результат работы стал «лучше».
Читать дальше →