вторник, 10 февраля 2009 г.

Boost 1.38.0

Вот и вышла следующая версия Boost 1.38.0. После беглого взгляда добавили не очень то много, но зато поправили достаточно изрядно. Впрочем для меня интересным введением была библиотека Flyweight. Как раз сейчас пытаюсь применить ее как решение к некоторым задачам. Тесты на производительности и занимаемую память обнадеживают.

Так же интересным введением стала ScopeExit. Достаточно странный макрос на первый взгляд. Обычные смарт-поинтеры при высвобождении делают одну операцию - delete, но как отмечается в документации бывает накладно каждый раз писать класс, который принимает и как-то высвобождает ресурс. К примеру, хендл на файл (закрыть при исключении), хранилище объектов, которое возвращается в предыдущее состояние если какая-либо операция не удалась. Библиотека предлагает обойтись одним лишь макросом, которые встраивается прямо в функцию, которая испольняет какую либу операцию и нуждается в откате, если в ней произошло исключение. Выглядит это примерно так:
void Container::insert(Object const& obj) 
{
bool commit = false;
m_vector.push_back(obj);
BOOST_SCOPE_EXIT( (&commit)(&m_vector) )
{
if(!commit)
m_vector.pop_back();
} BOOST_SCOPE_EXIT_END
// ... other operations ...
commit = true;
}

Здесь макрос создает оббертку прямо внутри функции, которая будет вызвана при выходе из функции в любой случае - через исключение и "нормальным" путем. В эту оббертку он передает ссылки на commit и m_vector, которые можно будет посмотреть/модифицировать при завершении функции. В данном примере, если дело не дошло до commit = true, то внутри BOOST_SCOPE_EXIT совершится откат на один элемент (к примеру исключение было брошено копи-конструктором класса Object). Вот так все просто и незатейливо. Стало даже интересно покопаться и посмотреть как все это реализовано, возможно идиома может быть полезна и в других задачах.

Буду писать далее, по возможности, про новые фичи и чем они могут быть полезны.

четверг, 5 февраля 2009 г.

Superfast Hash function

Если вам необходимо часто хешировать данные/строки, то рекомендую интересную функцию разработанную by Paul Hsieh - SuperFastHash. Она не только быстрее всех стандартных дающих 4 байтовый код, но и имеет неплохое распределение. Я пока с явными коллизиями не сталкивался.

Boost.Assign

Может тема и известна обширно, но не могу не поделиться радостями использования библиотеки Boost.Assign.
Дело в том, что в стандарте С++ не предусмотрено (пока, ждем С++0x) удобное заполнение контейнеров объектами. Как массивы можно заполнять структуры (и то не все):
struct object
{
long value;
};

object data[] = { 10, 20, 30 };

Но если нужно заполнить динамический контейнер как std::vector<> то этот метод здесь не применим. Как раз тут идет на помощь Boost. С помощью нехитрой библиотеки Assign можно делать такое:
std::vector<long> data;
data += 10, 20, 30;

и даже
std::vector<long> v;
std::vector<long> data;
data += repeat(5, 10), repeat(5, 20), range(v.begin(),v.end());

или
std::map<std::string, int> months;  
insert(months)
( "january", 31 )( "february", 28 )
( "march", 31 )( "april", 30 )
( "may", 31 )( "june", 30 )
( "july", 31 )( "august", 31 )
( "september", 30 )( "october", 31 )
( "november", 30 )( "december", 31 );

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

В принципе методы использованые в библиотеки могут оказаться полезными и для других нужд. К примеру, существует ядро, которое возвращает объект, а объект в свою очередь имеет контейнер значений который мы хотим заполнить:
DB db;
Object obj = db.get("object");
obj.push_back(10);
obj.push_back(11);
obj.push_back(12);

а можно возвращать промежуточный объект, который в случае чего может быть приведен к объекту Object, и в котором будут переопределены операторы += и , добавляющие данные в объект:
DB db;
db.get("object") += 10, 11, 12;

Это как пример, иногда всеже предпочтительнее первый вариант.