TechCave

Описание сайта

Основная информация

C++ — компилируемый строго типизированный язык программирования общего назначения. Поддерживает разные парадигмы программирования: процедурную, обобщённую, функциональную; наибольшее внимание уделено поддержке объектно-ориентированного программирования.

Рейтинг: 4
Создана 4 года назад
Владелец root

Стена группы

Загрузка...
2 года назад
#
Универсальный конструктор Auto

С приходом C++11 появилась возможность объявлять переменные с типом auto, а компилятор сам определил фактический тип переменной, на основе типа инициализируемого значения. Это удобно, когда мы хотим проинициализировать переменную тип которой слишком сложный, либо неизвестен, либо он нам не очень важен, либо просто для простоты.

Например:

auto f = [](){}; //указатель на функцию
auto r = foo(10); //тип возвращаемый функцией foo
for (auto i = 0; i < 10; i++){} 

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

int a = auto(10);

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

int a = 10;

Или в крайнем случае вызвать его конструктор:

int a(10);

А если это аргумент функции, например:

str::map<char, int> myMap;
myMap.insert(pair<char, int>('a', 10));

Подробнее
2 года назад
#
Умный указатель для начинающих с использованием счетчика

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

Вступление

А начнем мы с начала: в общем случае умный указатель — это некоторая надстройка над обыкновенным указателем, которая добавляет в него полезную или требуемую функциональность. Значит это все то, что он должен предоставлять все те же возможности по работе с указателем (разыменование, получение доступа к полям или функциям из-под указателя) и заниматься «грязной работой» — предотвращать утечки, избегать обращения к ранее освобожденному участку памяти. Хотелось бы сразу сказать, что мне случалось видеть создание объектов умного указателя только для адресов, под которыми лежат объекты классов, что верно, ведь зачистки памяти под указателями подошел бы и обычный MemoryGuard, которому бы хватило одного delete.

Ближе к делу

Итак, перейдем непосредственно к реализации Shared Pointer. Сперва вести учет ресурсов не будем. Требования к классу будут следующие:

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

Поскольку класс шаблонный, описание и реализацию можно выполнить в одному hpp-файле. Операторы -> и * могут быть определенные как члены класса, ведь слева от них будет всегда находится объект нашего умного указателя.

template<class T>
class shr_ptr
{
        T* resource;
public:
        shr_ptr(T* res=NULL):resource(res)
        {     
        } 
        ~shr_ptr()
        {
                delete resource;
        }
        T* operator ->() const 
        {
                return resource;
        }
        T& operator * () const 
        {
                return *resource;
        }
        T* get () const 
        {
                return resource;
        }
};

Подробнее
Den
2 года назад
#
Реализация блочного шифра «Кузнечик» с режимом CFB на С++

Сегодня речь пойдёт о новом алгоритме блочного шифрования «Кузнечик» из стандарта ГОСТ Р 34.12 2015. В последнее время выходит множество публикаций, посвященных этому стандарту. В них с теоретической точки зрения описываются приведённый алгоритм, изучаются особенности отельных преобразований, а так же предлагаются способы оптимизации, путём включения вставок кода на языке ассемблера.

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

Структура программы

Программа состоит из трех частей
  • набор вспомогательных функций и классов — mycrypto.cpp mycrypto.hpp

  • блочный шифр «Кузнечик» — Kuznyechik.cpp Kuznyechik.hpp

  • режим шифрования Cipher Feed Back — modes.hpp


Использованные обозначения

#define BLOCK_LENGTH 16

typedef unsigned char BYTE;
typedef unsigned short WORD;

Вспомогательные средства

Класс ByteBlock
class ByteBlock {
    BYTE * pBlocks;
    size_t amount_of_bytes;
public:
    // Construct block of bytes which contsists of
    // size_ blocks each of them with init_value in it
    ByteBlock(size_t size_ = 0, BYTE init_value = 0);

    // Construct block with size_ first bytes of pBlocks_
    // The value will be copied, source stays untouchable
    ByteBlock(BYTE * pBlocks_, size_t size_);

    // Move constructor
    // Copy constructor thus implicitly deleted
    // Object to move turn to null
    ByteBlock(ByteBlock && rhs);

    // Destructor, yeah
    ~ByteBlock();

    // Move assigment operator
    // Object to move turn to null
    void operator = (ByteBlock && rhs);

    // This cast may be convenient to use the ByteBlock
    // in functions which takes raw pointers as argument
    BYTE * byte_ptr();
    const BYTE * byte_ptr() const;

    // Indexing operator with evident functionality
    BYTE & operator [] (size_t index);
    BYTE operator [] (size_t index) const;

    bool operator == (const ByteBlock & lhs) const;
    bool operator != (const ByteBlock & lhs) const;

    // Replace body of the current block with pBlocks_
    // Old value will be zerod, and then, deleted
    // New value copied into the block,
    // source stays untouchable
    void reset(const BYTE * pBlocks_, size_t size_);

    // Return amount of bytes in block
    size_t size() const;

    // It'll return deep copy of the block, which
    // points to different place in memory
    ByteBlock deep_copy() const;

    // It'll return slice of current ByteBlock
    ByteBlock operator () (size_t begin, size_t length) const;

    // Changes values between two ByteBlock-s
    friend void swap(ByteBlock & lhs, ByteBlock & rhs);
};

Подробнее
2 года назад
#
PVS-Studio для Linux

PVS-studio

Свершилось! Сегодня мы выпустили публичную версию анализатора PVS-Studio для Linux. Теперь разработчики Linux приложений получат новое мощное оружие для борьбы с багами в коде. Призываем разнести эту новость по миру. Расскажите своим коллегам по работе, напишите в Twitter и Facebook! Да будут программы надёжней и стабильней!

Начиная с версии 6.10 анализатор PVS-Studio поддерживает не только Windows, но и Linux платформу.

PVS-Studio выполняет статический анализ кода и генерирует отчёт, помогающий программисту находить и устранять ошибки. PVS-Studio выполняет широкий спектр проверок кода, но наиболее силён в поисках опечаток и последствий неудачного Copy-Paste.

Подробнее
Den
2 года назад
#
Элементы функционального программирования в C++: частичное применение

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

Если кратко, то это механизм, позволяющий зафиксировать k аргументов функции от n аргументов, сделав из неё функцию от (n — k) аргументов.

// Пусть имеется функция f от четырёх аргументов:
int f (int a, int b, int c, int d)
{
    return a + b + c + d;
}

// Фиксируем первые два аргумента:
auto g = part(f, 1, 2); // 1 + 2 + ...

// Добрасываем оставшиеся два:
assert(g(3, 4) == 10); // ... + 3 + 4 = 10

Подробнее
Den
2 года назад
#
Задачка на std::multiset или поиск по полям структуры

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

Есть база пользователей 10 миллионов:

class User{
 int id; 
 time_t birthday; // дата рождения
 int gender;      // пол
 int city_id;     // место проживания
 time_t time_reg; // дата регистрации
};

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

  • город, пол;

  • пол, возраст.


Данные выдачи должны быть отсортированы по дате регистрации пользователей, и выдаваться постранично по 100 пользователей.

Подсказка 1: СУБД не даст нужной скорости.
Подсказка 2: Вспомнить сложность операций со множествами, сложность стандартных алгоритмов.
Подсказка 3: Проверить время поиска реализованного алгоритма, неплохой результат это порядка 0.005 сек.

Из готовых контейнеров для этой задачи можно использовать std::vector, отсортированный по нужному кретерию поиска, и std::lower_bound с реализацией:

template <class ForwardIterator, class T, class Compare>
  ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,
                               const T& val, Compare comp);

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

Подробнее
2 года назад
#
Умный указатель для Pimpl

Impl

Pimpl (pointer to implementation, указатель на имплементацию) — полезная идиома, распространенная в языке C++. У этой идиомы есть несколько положительных сторон, однако, в этой статье она рассматривается только как средство уменьшения зависимостей времени компиляции. Более подробно о самой идиоме можно посмотреть, например, здесь, здесь и здесь. Эта статья посвящена тому какой умный указатель использовать при работе с Pimpl и зачем он нужен.

Рассмотрим различные варианты реализации Pimpl:

Голый указатель

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

Пример использования:

// widget.h
class Widget {
public:
    Widget();
    ~Widget();
//...
private:
    struct Impl;
    Impl* d_;
};
// widget.cpp
struct Widget::Impl { /*...*/ };
Widget::Widget(): d_(new Impl) {}
Widget::~Widget() { delete d_; }

Подробнее
Den
2 года назад
#
SObjectizer: проблема перегрузки агентов и средства борьбы с ней

В предыдущих статьях мы несколько раз упоминали о такой проблеме, как перегрузка агентов. Что это такое? Чем это грозит? Как с этим бороться? Обо всем этом мы и поговорим сегодня.

Проблема перегрузки агентов возникает, когда какому-то агенту отсылается больше сообщений, чем он успевает обрабатывать. В результате очереди сообщений постоянно увеличиваются в размерах. Растущие очереди расходуют память. Расход памяти ведет к замедлению работы приложения. Из-за замедления проблемный агент начинает обрабатывать сообщения дольше, что увеличивает скорость роста очередей сообщений. Что способствует более быстрому расходу памяти. Что ведет к еще большему замедлению приложения. Что ведет к еще более медленной работе проблемного агента… Как итог, приложение медленно и печально деградирует до полной неработоспособности.

Проблема усугубляется еще и тем, что взаимодействие посредством асинхронных сообщений и использование подхода fire-and-forget прямо таки провоцирует возникновение перегрузок (fire-and-forget – это когда агент A получает входящее сообщение M1, выполняет его обработку и отсылает исходящее сообщение M2 агенту B не заботясь о последствиях).

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

Подробнее
2 года назад
#
Пример использования policy-based design в С++ вместо копипасты и создания ООП-шых иерархий

Язык C++ очень часто обвиняют в неоправданной сложности. Конечно же, язык C++ сложен. И с каждым новым стандартом становится все сложнее. Парадокс, однако, состоит в том, что постоянно усложняясь, C++ последовательно и поступательно упрощает жизнь разработчикам. В том числе и обычным программистам, которые пишут код попроще, чем разработчики Boost-а или Folly. Чтобы не быть голословным, попробую показать это на небольшом примере «из недавнего»: как в результате адаптации к различным условиям тривиальный класс превратился в легкий хардкор с использованием policy-based design.

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

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

Подробнее
2 года назад
#
Из опыта использования SObjectizer: акторы в виде конечных автоматов – это плохо или хорошо?

Познакомив читателей с фреймворком SObjectizer, его возможностями и особенностями, можно перейти к рассказу о некоторых уроках, которые нам довелось усвоить за более чем четырнадцать лет использования SObjectizer-а в разработке C++ного софта. Сегодня поговорим о том, когда агенты в виде конечных автоматов не являются хорошим выбором, а когда являются. О том, что возможность создания большого количества агентов – это не столько решение, сколько сама по себе проблема. И о том, как первое соотносится со вторым…

Итак, в трех предыдущих статьях (раз, два и три) мы наблюдали за тем, как агент email_analyzer развивался от очень простого до более-менее сложного класса. Думаю, что у многих, кто посмотрел на финальный вариант email_analyzer-а, возник вопрос: «Но ведь это же очень сложно, неужели нельзя было проще?»

Получилось так сложно потому, что агенты представляются в виде конечных автоматов. Для того чтобы обработать входящее сообщение, должен быть описан отдельный метод – обработчик события. Для того чтобы у агента мог запуститься новый обработчик события, текущий обработчик должен завершиться. Поэтому, чтобы отослать запрос и получить ответ агент должен завершить свой текущий обработчик, чтобы дать диспетчеру возможность вызвать соответствующий обработчик при поступлении ответа. Т.е. вместо:

Подробнее
2 года назад
#
SObjectizer: от простого к сложному. Часть III

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

В предыдущей статье мы остановились на том, что у нас появился агент email_analyzer, который можно считать более-менее надежно решающим свою задачу. Однако, он сам, последовательно, выполняет три стадии проверки email-а: сперва проверяет заголовки, затем содержимое, затем аттачи.

Скорее всего, каждая из этих операций не будет исключительно CPU-bound. Намного вероятнее, что вычленив какие-то значения из проверяемого фрагмента (например, из заголовков письма), потребуется сделать куда-то запрос для проверки допустимости этого значения. Например, запрос в БД дабы проверить, нет ли имени хоста-отправителя в черном списке. Пока будет выполняться данный запрос можно было бы выполнить еще какую-то операцию, например, разобрать содержимое текста письма на отдельные ключевые фразы, дабы их можно было проверить по какому-то словарю спам-маркеров. Или проверить, есть ли в аттачах архивы, и инициировать их проверку антивирусом. В общем, имеет смысл распараллелить операции анализа email-а.

Давайте попробуем задействовать отдельных агентов на каждую операцию. Т.е. можно написать агентов вида:

Подробнее
2 года назад
#
SObjectizer: от простого к сложному. Часть II

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

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

Во-первых, нам потребуется набор сообщений, которыми между собой будут обмениваться IO-агент и email_analyzer:

Подробнее
2 года назад
#
SObjectizer: от простого к сложному. Часть I

В первой статье мы рассказали о том, что такое SObjectizer и почему он получился именно таким. Во второй – попробуем показать, как может выглядеть более-менее реальный код на SObjectizer. С демонстрацией того, в какую сторону этот код обычно эволюционирует. Ибо первоначально, когда у разработчика появляется возможность работать с Actor Model, он начинает этой возможностью злоупотреблять, создавая проблемы и себе, и тем, кто будет эксплуатировать программный продукт, написанный в стиле «актор на каждый чих». Только спустя некоторое время и некоторое количество набитых шишек приходит понимание того, что прелесть модели акторов вовсе не в возможности создавать их десятками тысяч или даже просто тысячами. Но давайте пойдем последовательно, не опережая события.

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

Естественно, таких имен с файлами email-ов у нас будет не одно и не два. Будет некий поток этих имен, с которым нужно разбираться. Желательно, используя возможности современного многоядерного железа, т. е. запуская обработку нескольких email-ов в параллель.

Схематично покажем, как эта задача может быть решена на SObjectizer-е «в лоб». После чего укажем проблемы выбранного подхода, сделаем следующую итерацию и т.д. Дабы в итоге на примерах подвести читателя к тому пониманию «удобного использования модели акторов на C++» которое у нас сложилось за десять лет работы с SObjectizer-ом в реальных проектах.

Для начала определимся с тем, как выдаются запросы на проверку файлов с email-ами и как возвращаются результаты проверок. Используем для этих целей простые сообщения:

// Избавляемся от необходимости указывать префиксы so_5 и std.
// В последующих примерах эти using-и дублировать не будем,
// подразумевая, что они уже выполнены.
using namespace so_5;
using namespace std;
using namespace chrono_literals;

// Сообщение для проверки одного файла с email-ом.
struct check_request {
  // Имя проверяемого файла.
  string email_file_;
  // Кому нужно отослать результат проверки.
  mbox_t reply_to_;
};

// Статус проверки, который будет возвращен в ответном сообщении.
enum class check_status {
  safe,
  suspicious,
  dangerous,
  check_failure,
  check_timedout
};

// Сообщение с результатом проверки одного файла с email.
// Содержит не только статус проверки, но и имя проверяемого файла.
// Это имя нужно лишь для того, чтобы облегчить сопоставление
// получаемых результатов проверки.
struct check_result {
  string email_file_;
  check_status status_;
};

Подробнее
2 года назад
#
Почему C++ atomics именно такие — Егор Деревенец

В C++11 появились новые типы данных atomic T, позволяющие выполнять гарантированно атомарные операции с памятью. Для операций с данными новых типов можно указать порядок, в котором они, а также операции до и после них, достигнут глобальной памяти, то есть станут видны другим тредам.
По умолчанию используется порядок sequential consistency: все атомарные операции становятся видны всем тредам в одной и той же последовательности. Они не меняются местами с предшествующими или последующими операциями с памятью в треде, который их выполняет. C++ предоставляет возможность запросить и более слабые гарантии: release, acquire, consume, relaxed memory order.
Я попытаюсь объяснить, почему в C++ действительно нужны пять (а на самом деле шесть) видов гарантий. Я расскажу, откуда они появились, что означают и как код, использующий эти гарантии, компилируется на x86 и Power.

2 года назад
#
Генерация правил сборки в CMake — Иван Сидоров

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

10 11 13 14

Авторизация

Войти с помощью

Пользователи

GeekBrains

КАРКАМ

Нетология