LINUX.ORG.RU

Сообщения Cupper

 

Generic comparator with templated accessor to elements

Форум — Development

Провет, я хотел бы наити стандартный способ (СТЛ) сортировки массива пар, с возвожностью специализации способа сравнениа елементов

Что то вроде вот такого

template <class P>
struct Pair2First {
    const typename P::first_type& operator() (const P &p) { return p.first; }
};

template <class P>
struct Pair2Second {
    const typename P::second_type& operator() (const P &p) { return p.second; }
};

template <class Type, typename Accessor>
struct Greater {
    typedef Type first_argument_type;
    typedef Type second_argument_type;
    typedef bool result_type;
    
    bool operator() (const Type& lhs, const Type& rhs) const {
        return accessor(lhs) > accessor(rhs);
    }
    
    Accessor accessor;
};

typedef pair<int, double> PairX;

int main()
{
    vector<PairX> vec = {
        make_pair(9, 6.5),
        make_pair(3, 6.3),
        make_pair(5, 6.9),
    };
    
    PairX p1 = make_pair(1, 2.0);
    PairX p2 = make_pair(2, 1.0);
    
    cout << Greater<PairX, Pair2First<PairX>>()(p1, p2) << endl;
    
    stable_sort(vec.begin(), vec.end(), Pair2First<PairX>>);
}

 ,

Cupper
()

Thunderbird - Quick action (aka Outlook)

Форум — General

Привет. Подскажите как можно сделать аналог «Quick Action» в Thunderbird.

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

Действие:

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

2. переместить тред в специальную папку.

SmartTemplate4 не умеет этого.

 

Cupper
()

CSS box model - перекрытие элементов и неожиданные отспуты

Форум — Web-development

Ознакомился с данной концепцией, вроде все понятно.

навоял пример, http://jsfiddle.net/fx5t4/ и понял, что видать упустил нехилый кусок понимания.

Из этого кода у меня возникают следующие вопросы:

1. Почему между границами двух span'ов есть пространство? Хотя указан margin: 0 на обоих.

2. Почему div не растянулся в сооветсвии с размерами вложеных span'ов? Ему ни padding ни border ни почем.

Можно даже не разжевывать, хотя бы линк на материал где объясняется именно это, а не то, что такое border/margin/padding. Часа 2 уже гуглю, так ничего и не выгуглил.

Спасибо.

Перемещено beastie из development

 ,

Cupper
()

не работает nav-collapse collapse

Форум — Development

Привет, и снова я.

Использую элемент nav-collapse collapse из bootstrap для шапки сайта. При уменьшении окна, все как надо сворачивается, кнопка появляется, но она не работает. Пробовал гуглить, нашел два несовсе понятных решения, заключавшиеся в переименовании некоторых элементов или удалении некоторого тега, но они только разваливают шапку и все равно не работают.

Собстно сам сайт тут http://rango.pythonanywhere.com

А вот так выглядит этот элемент

<div class="navbar navbar-inverse navbar-fixed-top">
          <div class="navbar-inner">
              <div class="container">
                  <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
                      <span class="icon-bar"></span>
                      <span class="icon-bar"></span>
                      <span class="icon-bar"></span>
                  </button>
                  <a class="brand" href="/rango/">Rango</a>

                  <div class="nav-collapse collapse">
                      <ul class="nav pull-right">
                          
                          <li><a href="/rango/profile/">Welcome, <strong>rango</strong>!</a></li>
                          <li><a href="/rango/logout/">Logout</a></li>
                          
                      </ul>
                      <ul class="nav">
                          
                          <li><a href="/rango/add_category/">Add Category</a></li>
                          
                          <li><a href="/rango/about/">About</a></li>
                      </ul>
                  </div>
                  <!--/.nav-collapse -->
              </div>
          </div>
      </div>

 ,

Cupper
()

JavaScript функция для элементов из списка <ol></ol>

Форум — Development

Привет, есть вот такой список в HTML

( читать дальше... )

генерируется шаблонизатором, элементов <li> в списке может быть сколько угодно. В каждой строке есть кнопка с id=«auto_add_page» (я могу сделать идентификатор уникальный для каждой кнопки если нужно) и некоторой доп. информацией.

На каждую кнопку вашается JS обработчик, который делает GET запрос с информацией которая вытаскивается из соотвествующего батона (типо AJAX).

сейчас js функция выглядит так

    $('#auto_add_page').click(function() {
    	var catid, title, url;
    	catid = $(this).attr("data-catid");
    	title = $(this).attr("data-title");
    	url = $(this).attr("data-url");
    	$.get('/rango/auto_add_page/', 
    		{catid: catid, title: title, url: url},
    		function(data){
    			$('#pages').html(data);
    		});
    });
Это работает только для первой кнопки. Как сделать так что бы этаже функция была забиндена и на все остальные кнопки. Напрщивается, что у них должны быть уникальные ID, но как тогда описа'ть JS функцию?

 , ,

Cupper
()

CSS адаптивная верстка

Форум — Web-development

Пытаюсь состряпать вот такой макет

http://jsfiddle.net/rRm7k/439/

но я хочу что бы элемент Footer был всегда прилеплен к низу экрана. А l_sidebar, main и r_sidebar были растянуты между Header и Footer.

При этом размер Header/Footer должен задаваться в px. А так же размер L/R Sidebar тоже в px. Хотя это уже и так сохранено, но я это к тому, что бы не делали жесткую верстку, она должна растягиваться для любой экран.

Спасибо.

Перемещено leave из development

 ,

Cupper
()

Удаленный рабочий стол без IP

Форум — Desktop

Подскажите пожалуйста софт для удаленного рабочего стола, но что бы адрес определялся внешними средствами а не прямо по IP. C Ubuntu 12.04 есть встроеная вича, но вот в 14.04 ее уже нету. Чем можно заменить?

Спасибо.

 

Cupper
()

Шаблонный класс из шаблонной функции

Форум — Development

Что то я не понимаю что я делаю не так :(

#include <iostream>

using namespace std;

template <class T>
class Task
{
public:
    Task(T t){}    
};

template <class T>
Task<T> make_task(T t)
{
    return Task(t);
}

int main()
{
   cout << "Hello World" << endl; 
   
   make_task(1);
   
   return 0;
}
main.cpp: In function ‘Task<T> make_task(T)’:
main.cpp:14:16: error: missing template arguments before ‘(’ token
     return Task(t);
                ^

Т.е. можно только вот так?

template <class T>
Task<T> make_task(T t)
{
    Task<T> tmp(t);
    return tmp;
}

Cupper
()

Произвольный порядок списка инициализации шаблона

Форум — Development

У меня есть два типа понтейнера которые принимают по 3 шаблонных параметра

template<class T, class Deferred, class Deadline>
struct prio_container;

template<class T, class Deferred, class Deadline>
struct queue_container;
Тип T - это элемент контейнера.

Deferred и Deadline это плагины, которые расширяют функционал. Все делается без палиморфизма, исключительно на этапе компиляции (статический полиморфизм).

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

template<class T, 
         class Plugin1 = disable_plugin,
         class Plugin2 = disable_plugin,
         class Plugin3 = disable_plugin>
struct container;

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

#include <iostream>
#include <string>

using namespace std;

#define static_type(name) \
    static const std::string& type() \
    { \
        static std::string type_(name); \
        return type_; \
    } \

struct prio_plugin;
struct dis_prio_plugin;

struct deferred_plugin
{ static_type("deferred"); };

struct deadline_plugin
{ static_type("deadline"); };

struct disable_plugin
{ static_type("disable"); };

template<class T, class Deferred, class Deadline>
struct prio_container
{
    static const std::string& type()
    {
        static std::string type_("prio_container<" + 
                                    Deferred::type() + ", " +
                                    Deadline::type() + ">");
        return type_;
    }
};

template<class T, class Deferred, class Deadline>
struct queue_container
{
    static const std::string& type()
    {
        static std::string type_("queue_container<" + 
                                    Deferred::type() + ", " +
                                    Deadline::type() + ">");
        return type_;
    }
};

template<class T, 
         class Plugin1 = disable_plugin,
         class Plugin2 = disable_plugin,
         class Plugin3 = disable_plugin>
struct container;

template<class T, 
         class Plugin1,
         class Plugin2>
struct container<T, prio_plugin, Plugin1, Plugin2>
{
    typedef prio_container<T, Plugin1, Plugin2> type;
};

template<class T, class DisableDeadline>
struct container<T, prio_plugin, deferred_plugin, DisableDeadline>
{
    typedef prio_container<T, deferred_plugin, DisableDeadline> type;
};

template<class T, class DisableDeferred>
struct container<T, prio_plugin, deadline_plugin, DisableDeferred>
{
    typedef prio_container<T, DisableDeferred, deadline_plugin> type;
};

template<class T>
struct container<T, prio_plugin, deadline_plugin, deferred_plugin>
{
    typedef prio_container<T, deferred_plugin, deadline_plugin> type;
};

template<class T>
struct container<T, prio_plugin, deferred_plugin, deadline_plugin>
{
    typedef prio_container<T, deferred_plugin, deadline_plugin> type;
};



int main()
{
   cout << "Hello World" << endl; 
   
   cout << container<int, prio_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deadline_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deferred_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deferred_plugin, deadline_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deadline_plugin, deferred_plugin>::type::type() << std::endl;
   
   return 0;
}
prio_container<disable, disable>
prio_container<disable, deadline>
prio_container<deferred, disable>
prio_container<deferred, deadline>
prio_container<deferred, deadline>

Cupper
()

condition_variable + timed_mutex

Форум — Development

Это возможно? Я не нашел ни одного упоминания как это сделать. Вариант написать свой timed_condition_variable не рассматривается.

 

Cupper
()

Размышление об архитектуре класса/классов

Форум — Development

Представьте, что вам нужен класс repository который содержит функцию make(ID& id) (При этом мы не знаем что такое ID, сейчас это шаблонный параметр). Данная функция должна возвращать некоторую сущность A, при этом если в текущий момент еще нет сущности ассоциированной с таким id, то он должен ее создать, а если есть то вернуть ранее созданную.

Очевидно что A это shared_ptr<A>. Задача состоит в том что бы уметь удалять из repository информацию об id и связанного с ним A когда будут удалены все A полученный через make.

В голову приходит идея хранить в repository map<ID, weak_ptr<A> >. Далее нам нужно как то научить A (в деструкторе), обращатся к repository и удалять себя из него.

Тип А, сам по себе, ни как не связан с ID, так и хотелось бы это оставить. Из за этого я не особо понимаю как можно связать A и repository, так как repository это шаблон, а A не знает тип которым инстанцируется этот шаблон (это про ID).

Пока в голову приходит только, хранить в A полсностью сконфигурированный функтор, который знает к кому обратиться и что удалить. Интересует как можно было обойтись без биндеров и функторов, но при это оставить слубую связность между A и repository<ID>.

 

Cupper
()

Утилита для тестирования DNS

Форум — Admin

Подскажите, как можно потетсить развернутый локально DNS сервер, который не является DNS сервером системы. Т.е. у меня есть просто сервер на определенном порту, который умеет резолвить имена и мне нужно чемто на подобие host стрельнуть в него что бы проверить что он работает.

В идеале что то вроде

host http://www.example.com -p 10053

Cupper
()

User hook на coredump

Форум — Development

Как то давно мне приходилось делать автоматическое создание репортов при возникновении coredump нашего приложение. Это делалось внешними средствами системы. Т.е. при возникновении coredump система сперва вызывала мой зарегистрированный скрипт с какими то параметрами, в котором я мог сделать репорт об ошибке.

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

Cupper
()

Перегрузка вирт функции в шаблоне

Форум — Development

Подскажите почему это не компилируется

#include <iostream>
using namespace std;

class Logger
{
public:

    int logger()
    { return 5; }

    virtual void logger(int)
    { ; }

    virtual ~Logger(){}
};

template <typename T>
class Base: public Logger
{
public:
    virtual void logger(int)
    { ; }

    virtual ~Base(){}
};

class Derived: public Base<int>
{
public:
    void f()
    {
        logger(logger());
    }
};

int main() {

    Derived d;
    d.f();
}
../src/overload_fin_template.cpp:40:23: ошибка: нет подходящей функции для вызова «Derived::logger()»
../src/overload_fin_template.cpp:40:23: замечание: candidate is:
../src/overload_fin_template.cpp:29:18: замечание: void Base<T>::logger(int) [with T = int]
../src/overload_fin_template.cpp:29:18: замечание:   candidate expects 1 argument, 0 provided
make: *** [src/overload_fin_template.o] Ошибка 1

Если в Base убрать перезрузку метода virtual void logger(int) то все как бы работает (собстно как и ожидалось).

Выжно, что

    int logger()
    { return 5; }

    virtual void logger(int)
    { ; }
имееют одинаковое имя, если сделать разные то компилируется.

Cupper
()

загрузка динамической библиотеки дважды

Форум — Development

Если я например сделаю дважды dl_open на одной и тойже библиотеке, она же от этого второй раз не загрузиться. Т.е. если у меня например есть глобальные, статические переменные в библиотеке, то все они будут в единственном числе, не важно сколько раз я бы не загружал библиотеку?

Cupper
()

boost::log channel vs attribute

Форум — Development

Ни как не могу понять в чем принципиальная разница между channel и attibute в boost log (1.54+). Вроде как и тот и другой просто ставит метку к записи, по которой потом можно фильтровать, причем фильтрация выглядит абсолютно одинакого.

По тестам производительности, source + channel на наносекунды обгоняет source + attribute, так что тут не принципиально logger(channel), разница в 50 миллисекунд на 500000 записей.

 ,

Cupper
()

Ubuntu 13.10 умирает

Форум — Desktop

Стоит у меня Ubuntu 13.10 со всеми апдейтами и она умирает. Разваливается на глазах, постоянно репроты с ошибками, skype на видио связи постоянно дохнет.

Так случилось, что вместе с 13.10 я себе SSD поставил, и теперь не понимаю то ли он так хреного работает толи 13.10 полный отстой.

 

Cupper
()

Thread safe queue и сбор статистики о времение

Форум — Development

Есть у меня код который обеспечивает асинхронное выполнение тасков.

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

Есть пару ухищрений, типа дедлайнов и cancel_hook в случае если таска просрочилась. Ну т.е. кладя задачу в очередь у нее либо вызовется метод execute() либо cancel().

Нужно мне добавить возможность сбора следующей статистики. 1. Сколько задача устанавливалась в очередь (при установки в очередь как минимум нужно схватить мютекс, как максимум есть capacity и ожидания в случае если они досиг лимита) 2. Сколько по времение задача провела в очедеи то тех поо пока ее от туда не вытащили. 3. сколько выполнялась 4. все это усредненное

Как сделано сейчас: статистика хранится в самом объекте который ставится в очередь и далее везде где нужно ее замерять, она устанавливается в сам объект. И в конце из объекта она куда то там сохраняется (т.е. объект нужно еще параметризировать тем куда ее сохранять).

схематично это выглядит так: push:

  • Засеч время при входе в метод
  • захватить мютекс
  • поставить задачу в очередь
  • засеч время выхода из метода
  • отпустить мютекс

pop:

  • Захватить мютекс
  • получить задачу из очереди
  • засем время начала выполнения
  • выполнение задачи
  • зачем время завершения
  • сохранить статистику в X

Мне не нравиться, что эту статистику приходится хранить в объектe. Поидее пользователю на нее вообще насрать. Хужее, что ее надо не просто получать, ее нужно хранить и аккамулировать, т.е. мы должны напрягать пользователя тем, что бы он подумал об этом. Мне кажется логичным что эта статистика должна накапливаться в самой очереди без участия пользователя. Но так как нужно знать когда объект был пушнут и когда был попнут, эту статистику как то нужно связать с самим объектом.

Хранить что то типо отдельного маппинга это вообще не решение. Притом сбор этоq статистики происходит на разных уровнях. Если немного подумать, то видно что информацию о пуше мы может собирать только под мютексом. А статистику о выполнении задачи нужно уже собирать на уровне выше. А еще cancel() выполняется опять на другом уровне. Единственно что объединяет все эти уровни это только объект (пользовательский тип).

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

Может кто делал такое? Посоветуйте?

Cupper
()

boost::multi_index_container<const int>

Форум — Development

Кто знает почему субж не умеет работать с константными типами?

#include <iostream>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/global_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>

int main()
{
	boost::multi_index_container<const int> t;

	t.insert(5);
	std::cout << *t.begin() << std::endl;
}
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from /usr/include/x86_64-linux-gnu/c++/4.7/./bits/c++allocator.h:34:0,
                 from /usr/include/c++/4.7/bits/allocator.h:48,
                 from /usr/include/c++/4.7/string:43,
                 from /usr/include/c++/4.7/bits/locale_classes.h:42,
                 from /usr/include/c++/4.7/bits/ios_base.h:43,
                 from /usr/include/c++/4.7/ios:43,
                 from /usr/include/c++/4.7/ostream:40,
                 from /usr/include/c++/4.7/iostream:40,
                 from ../main.cpp:13:
/usr/include/c++/4.7/ext/new_allocator.h: In instantiation of «class __gnu_cxx::new_allocator<const int>»:
/usr/include/c++/4.7/bits/allocator.h:89:11:   required from «class std::allocator<const int>»
/usr/include/boost/detail/allocator_utilities.hpp:149:31:   required from «struct boost::detail::allocator::rebinder<std::allocator<const int> >::result<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > >»
/usr/include/boost/detail/allocator_utilities.hpp:158:49:   required from «struct boost::detail::allocator::compliant_allocator_rebind_to<std::allocator<const int>, boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > >»
/usr/include/boost/mpl/eval_if.hpp:60:31:   required from «struct boost::mpl::eval_if_c<false, boost::detail::allocator::partial_std_allocator_rebind_to<std::allocator<const int>, boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > >, boost::detail::allocator::compliant_allocator_rebind_to<std::allocator<const int>, boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > > >»
/usr/include/boost/detail/allocator_utilities.hpp:164:8:   required from «struct boost::detail::allocator::rebind_to<std::allocator<const int>, boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > >»
/usr/include/boost/multi_index_container.hpp:70:7:   required from «class boost::multi_index::multi_index_container<const int>»
../main.cpp:22:42:   required from here
/usr/include/c++/4.7/ext/new_allocator.h:83:7: ошибка: «const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = const int; __gnu_cxx::new_allocator<_Tp>::const_pointer = const int*; __gnu_cxx::new_allocator<_Tp>::const_reference = const int&]» cannot be overloaded
/usr/include/c++/4.7/ext/new_allocator.h:79:7: ошибка: with «_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = const int; __gnu_cxx::new_allocator<_Tp>::pointer = const int*; __gnu_cxx::new_allocator<_Tp>::reference = const int&]»
In file included from /usr/include/boost/multi_index/detail/base_type.hpp:21:0,
                 from /usr/include/boost/multi_index_container.hpp:33,
                 from ../main.cpp:15:
/usr/include/boost/multi_index/detail/index_base.hpp: In instantiation of «boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::node_type* boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::insert_(boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type, boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::node_type*) [with Value = const int; IndexSpecifierList = boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>; Allocator = std::allocator<const int>; boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::node_type = boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >; boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type = const int]»:
/usr/include/boost/multi_index/ordered_index.hpp:633:63:   required from «boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::node_type* boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::insert_(boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::value_param_type, boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::node_type*) [with KeyFromValue = boost::multi_index::identity<const int>; Compare = std::less<const int>; SuperMeta = boost::multi_index::detail::nth_layer<1, const int, boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<const int> >; TagList = boost::mpl::vector0<mpl_::na>; Category = boost::multi_index::detail::ordered_unique_tag; boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::node_type = boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > >; typename SuperMeta::type::node_type = boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >; boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::value_param_type = const int]»
/usr/include/boost/multi_index_container.hpp:488:40:   required from «std::pair<typename boost::multi_index::detail::multi_index_base_type<Value, IndexSpecifierList, Allocator>::type::node_type*, bool> boost::multi_index::multi_index_container<Value, IndexSpecifierList, Allocator>::insert_(const Value&) [with Value = const int; IndexSpecifierList = boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>; Allocator = std::allocator<const int>; typename boost::multi_index::detail::multi_index_base_type<Value, IndexSpecifierList, Allocator>::type::node_type = boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > >]»
/usr/include/boost/multi_index/detail/index_base.hpp:150:30:   required from «std::pair<typename boost::multi_index::detail::multi_index_node_type<Value, IndexSpecifierList, Allocator>::type*, bool> boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::final_insert_(boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type) [with Value = const int; IndexSpecifierList = boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>; Allocator = std::allocator<const int>; typename boost::multi_index::detail::multi_index_node_type<Value, IndexSpecifierList, Allocator>::type = boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > >; boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type = const int]»
/usr/include/boost/multi_index/ordered_index.hpp:275:61:   required from «std::pair<boost::multi_index::detail::bidir_node_iterator<boost::multi_index::detail::ordered_index_node<typename SuperMeta::type::node_type> >, bool> boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::insert(boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::value_param_type) [with KeyFromValue = boost::multi_index::identity<const int>; Compare = std::less<const int>; SuperMeta = boost::multi_index::detail::nth_layer<1, const int, boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<const int> >; TagList = boost::mpl::vector0<mpl_::na>; Category = boost::multi_index::detail::ordered_unique_tag; typename SuperMeta::type::node_type = boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >; boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::value_param_type = const int]»
../main.cpp:24:12:   required from here
/usr/include/boost/multi_index/detail/index_base.hpp:88:5: ошибка: нет соответствующей функции для вызова «construct(boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >::value_type*, boost::multi_index::detail::index_base<const int, boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<const int> >::value_param_type&)»
/usr/include/boost/multi_index/detail/index_base.hpp:88:5: замечание: candidate is:
In file included from /usr/include/boost/multi_index_container.hpp:20:0,
                 from ../main.cpp:15:
/usr/include/boost/detail/allocator_utilities.hpp:176:6: замечание: template<class Type> void boost::detail::allocator::construct(void*, const Type&)
/usr/include/boost/detail/allocator_utilities.hpp:176:6: замечание:   template argument deduction/substitution failed:
In file included from /usr/include/boost/multi_index/detail/base_type.hpp:21:0,
                 from /usr/include/boost/multi_index_container.hpp:33,
                 from ../main.cpp:15:
/usr/include/boost/multi_index/detail/index_base.hpp:88:5: замечание:   cannot convert «& x->boost::multi_index::detail::index_node_base<Value, Allocator>::value<const int, std::allocator<const int> >()» (type «boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >::value_type* {aka const int*}») to type «void*»
make: *** [main.o] Ошибка 1

Такое чувство, что я единственнй кто это пробовал, ибо в гугле ничего похожего ненашел.

Cupper
()

Thread safe Queue + delete object's with O(1)

Форум — Development

Нужно реализовать вот такую незамысловатую штуку. Обычная thread safe очередь но с возможность удаления поставленных в нее объектов.

При этом хотелось бы что бы «опцию» удаления объектов из очереди можно было бы отключить безболезненно если она не нужна.

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

Если пораскинуть мозгами, то появляются вот такие требования к реализации:

  • Сторона которая делает push получает хендел через который можно удалить объект
  • Если кто то сделал pop этого объекта, то удалить его через хендл полученных из push уже нельзя
  • Если объект был удален, то pop возвращает пустой хендл, поэтому перед использованием объекта полученного из pop нужно его проверить (хотя эту проверку можно делать сразу в pop)

У меня получилась вот такая реализация:

template<class T, class H = ::Holder<T> >
class Queue
{
	typedef typename H::Ptr Ptr;

public:
	typedef H Holder;

	object():stop_(false){}

	Holder push(T* t)
	{
		std::unique_lock<std::mutex> lock(mtx_);
		Holder holder(t);
		q_.push_back(holder.ptr());
		cond_.notify_one();
		return holder;
	}
	Holder pop()
	{
		std::unique_lock<std::mutex> lock(mtx_);
		while(q_.empty() && !stop_) cond_.wait(lock);
		if(stop_ && q_.empty())
			throw std::runtime_error("stopped");
		Ptr ptr = q_.front();
		q_.pop_front();
		return Holder(ptr);
	}

	void stop()
	{
		std::unique_lock<std::mutex> lock(mtx_);
		stop_ = true;
		cond_.notify_one();
	}
private:
	std::deque<Ptr> q_;
	bool stop_;
	std::mutex mtx_;
	std::condition_variable cond_;
};
Сразу бросается в глаза, что очередь может работать только с указателями. Но, в противном случае, как бы мы могли удалить объект в очереди (ниже будет понятнее).

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

template<class T>
class Holder
{
public:
	typedef T* Ptr;

public:
	Holder(T* t): t_(t){}

	void reset() {  }

	operator bool(){ return static_cast<bool>(t_); }
	T* operator->() {return t_;}
	Ptr ptr() { return t_; }

private:
	T* t_;
};

Второй тип хендлера, подразумевает что настоящим владельцем (хранителем объекта) будет сам pusher

template<class T>
class RemovableHolder
{
public:
	typedef std::weak_ptr<T> Ptr;

public:
	RemovableHolder(T* t):t_(t){}
	RemovableHolder(const Ptr& ptr):t_(ptr.lock()){}

	void reset() { t_.reset(); }

	operator bool(){ return static_cast<bool>(t_); }
	T* operator->() {return t_.get();}
	Ptr ptr() { return std::weak_ptr<T>(t_); }

private:
	std::shared_ptr<T> t_;
};
Проще говоря в самой очереди мы храним лишь weak_ptr, первый shared_ptr мы отдаем push'ру и он собственно может в любой момент удалить реальный объект. После операции pop у нас появляется еще один шаред, и тем самым мы добиваемся требуемого. Но тут есть одна неприятность. Pusher должен хранить все объекты. Это не очень удобно, вернее это вообще не удобно.

Третий холдер, решает эту проблему

template<class T>
class ExRemovableHolder
{
	struct Impl
	{
	public:
		Impl(T* t):t_(t), is_popped_(false){}
		void destroy(bool from_popper)
		{
			std::unique_lock<std::mutex> lock(mtx_);
			if(is_popped_ && !from_popper)
			{
				return;
			}
			if(t_)
			{
				delete t_;
				t_ = 0;
			}
		}
		~Impl()
		{
			delete t_;
		}

	public:
		std::mutex mtx_;
		T* t_;
		bool is_popped_;
	};

public:
	typedef std::shared_ptr<Impl> Ptr;

public:
	ExRemovableHolder(T* t):impl_(new Impl(t)), popper_(false){}
	ExRemovableHolder(Ptr& ptr):popper_(true)
	{
		std::unique_lock<std::mutex> lock(ptr->mtx_);
		if(ptr->t_)
		{
			impl_ = ptr;
			impl_->is_popped_ = true;
		}
	}

	void reset() { impl_->destroy(popper_); }

	operator bool(){ return static_cast<bool>(impl_); }
	T* operator->() {return impl_->t_;}
	Ptr ptr() { return impl_; }

private:
	std::shared_ptr<Impl> impl_;
	bool popper_;
};
Теперь у нас pusher,popper и в самой очереди хранится shared_ptr. Pusher может его в ручном порядке удалить. Притом только если этот объект еще не был pop'нут. Так же нам в принципе нет необходимости вообще хранить объекты из pushra. Так же объект может быть удален в ручную из pop'ra. И так же объект будет удален автоматически если его вообще никто не удалял.

Вот пример как это используется

typedef Queue<Person, ExRemovableHolder<Person> > TSQueue;
typedef simple_object<TSQueue::Holder> DestroyQueue;

void popper(TSQueue& q)
{
	try
	{
		while(true)
		{
			TSQueue::Holder tmp = q.pop();
			if(tmp)
			{
				tmp->name();
				tmp.reset();
			}
		}
	}
	catch(...)
	{
		std::cout << "popper finished\n";
	}
}
void destroyer(DestroyQueue& q)
{
	try
	{
		while(true)
		{
			TSQueue::Holder tmp = q.pop();
			tmp.reset();
		}
	}
	catch(...)
	{
		std::cout << "destroyer finished\n";
	}
}

int main()
{
	TSQueue q;
	std::thread th(popper, std::ref(q));

	DestroyQueue d;
	std::thread thd(destroyer, std::ref(d));

	const int repeat = 9999999;
	for(int i=1; i<=repeat; i++)
	{
		TSQueue::Holder h = q.push(new Person("Vasya"));
		d.push(h);
	}

	q.stop();
	d.stop();
	th.join();
	thd.join();
}

Зачем вся эта котовасия понадобилась. Это вроде как ActiveObject где активные объекты должны исполнятся в пуле тредов. Т.е. очередь это интерфейс для асинхронного выполнения задач. Притом логично, что после постановки задачи в очередь, может произойти так, что эта задача станет уже не актуальной до момента, когда до нее дойдет очередь выполнения (например клиент отключился), и тогда ее выполнения будет бессмысленным.

Если система слобосвязана, то это по сути единственнй способ отменить выполнения таски.

А теперь я хотел бы выслушать вашу критику. И в плане идеи и в плане реализации.

 

Cupper
()

RSS подписка на новые темы