Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Стремительней чем std::function

Anna | 24.06.2014 | нет комментариев

С момента выхода эталона С 11 прошло теснее огромнее 2-х лет. И множество С разработчиков теснее знакомы с основными его нововведениями и костылями. Одним из новшеств было добавление в стандартную библиотеку класса std::function.

Классы std::function и boost::function являются высокоуровневыми обертками над функциями и функциональными объектами. Объекты таких классов разрешают беречь и вызывать функции и функторы с заданной сигнатурой, что бывает комфортно, скажем, при создании callback вызовов (скажем, мы можем регистрировать несколько обработчиков, и это могут быть как обыкновенные функции, так и объекты с определенным оператором =)

©

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

  1. При создании объекта std::function вызывается оператор new, как следствие того, что std::functionразрешает сберегать в себя функтор произвольного размера.
  2. std::function имеет семантику копирования, которая, в тезисе, редко когда бывает нужна в при действиях с функторами (в связи с возникновением move-семантики), но стоит определенных источников CPU.

Как от этого избавиться?

Для этого, безусловно же, необходимо написать свой std::function без этих неизбежных недостатков =) К счастью, новые вероятности С 11 разрешают нам это сделать без лишних телодвижений и обращений к специфичным вероятностям компиляторов.

Что хочется?

  • Избавиться от вызовов new при создании объекта функтора.
  • Убрать семантику копирования, Дабы избежать потенциального копирования объектов функторов.
  • Синтаксиса близкого к std::function.
  • Внятного кода.
  • Побаловаться с С 11.

Ну и как же это сделать?

Для начала разглядим легкой метод реализовать делегат на С , тот, что я подчерпнул из статей Fastest Possible C Delegates и Lightweight Generic C Callbacks.

class function_t {
public:
    template <typename U>
    function_t (U &&object)
    {
        typedef typename std::remove_reference<U>::type unref_type;

        m_object_ptr = new unref_type(object);
        m_method_ptr = &method_stub<unref_type>;
    }

    void operator()() const
    {
        if (m_method_ptr) {
            (*m_method_ptr)(m_object_ptr);
        }
    }

private:
    void *m_object_ptr;

    typedef void (*method_type)(void *);
    method_type m_method_ptr;

    template <class T>
    static void method_stub(void *object_ptr)
    {
        static_cast<T *>(object_ptr)->operator()();
    }
};

Пока что закроем глаза на неимение вызова delete, Дабы не загружать код излишней информацией.
А дальше, будем добавлять все нужные на фичи.

Убираем выделение динамической памяти

Для этого будем конструировать объект делегата в теснее присутствующем на момент создания нашегоfunction буфере. Добавим в наш класс следующее поле:

class function_t {
    enum {STORAGE_SIZE = 32};
public:
    // ...
private:
    typename std::aligned_storage<STORAGE_SIZE, STORAGE_SIZE>::type m_storage;    
    // ...
};

И будем конструировать объект делегата в нём.

    template <typename U>
    fixed_function_t(U &&object)
    {
        typedef typename std::remove_reference<U>::type unref_type;

        m_object_ptr = new (&m_storage) unref_type(std::forward<U>(object));
        m_method_ptr = &method_stub<unref_type>;
    }

Убираем вероятность копирования

struct noncopyable_t {
    noncopyable_t & operator=(const noncopyable_t&) = delete;
    noncopyable_t(const noncopyable_t&) = delete;
    noncopyable_t() = default;
};

class fixed_function_t: private noncopyable_t  {
    //...

При этом нужно не позабыть реализовать верно move семантику! В move конструкторе придется делать memcpyдля m_storage, и изменить указатель на способ.

Добавляем синтаксис ближний к std::function

template <typename R, typename... ARGS>
class fixed_function_t : private noncopyable_t {
    enum {STORAGE_SIZE = 32};
public:

    //...

    R operator()(ARGS... args) const
    {
        if (m_method_ptr) {
            return (*m_method_ptr)(m_object_ptr, args...);
        }
        return R();
    }

private:

    //...

    template <class T>
    static R method_stub(void *object_ptr, ARGS... args)
    {
        return static_cast<T *>(object_ptr)->operator()(args...);
    }
};

Готово!

Взамен завершения

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

Спасибо за внимание.

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB