27 декабря 2010 г.

Нововведения в C++0x, которые не могут не радовать (меня)

Просмотрел повнимательнее список новшеств в будущем стандарте C++0x и обнаружил, что многие грабли, которые приходилось раньше реализовывать самостоятельно или городить воркэраунды, теперь будут поддерживаться конструкциями языка или добавлены в стандартную библиотеку. Это не может не радовать, потому что это сильно облегчает жизнь.

  1. Первым пунктом у меня идут потоки и объекты синхронизации (§30 [thread]): thread, mutex, lock, condition_variable, future, ... Наконец-то! Надеюсь, теперь можно будет выкинуть весь самописный код, который реализовывал классы с подобной функциональностью для использования на различных платформах. Конечно, было бы неплохо расширить список поддерживаемых Стандартом объектов синхронизации, но и существующий список вполне хорош.
  2. static_assert — проверка условий на этапе компиляции, которой так не хватало в предыдущих версиях Стандарта. Очень полезна для проверки размеров типов данных и кратности этих типов каким-то заданным значениям. (§7 [dcl.dcl])
  3. Списки инициализации и универсальная инициализация — новая синтаксическая конструкция (§8.5.4 [dcl.init.list]), которая позволяет инициализировать массивы, структуры данных и контейнеры следующим образом:
    double ad[] = { 1, 2.0 };
    S2 s22 { 1.0, 2, 3 };
    std::map<std::string, int> anim =
      { {"bear",4}, {"cassowary",2}, {"tiger",7} };

  4. shared_ptr — умные указатели (§20.9.11 [util.smartptr]). Объект, хранимый умным указателем, уничтожается только после того, как счетчик ссылок на объект будет равен нулю.
  5. Лямбда-выражения (§5.1.2 [expr.prim.lambda]). К самим по себе лямбда-выражениям я отношусь достаточно спокойно. Даже, пожалуй, скептически, потому что мне кажется, что фанатичное использование лямбда-выражений приведёт к хаосу (особенно выражений, которые изменяют состояние классов). Но у лямбда-выражений есть свойство, которого мне раньше не хватало — их можно передавать в классы и алгоритмы стандартной библиотеки (и в пользовательские шаблоны) в качестве предикатов. Раньше надо было городить кучу кода, определяя дополнительные функции и классы, причем передавать в шаблон локальный класс запрещено. А с новым стандартом можно сделать так:
    std::sort(x, x + N,
              [](float a, float b)
              { return std::abs(a) < std::abs(b); });

  6. Автоматический тип данных auto — тип объявляемой переменной определяется самостоятельно из типа инициализатора. Особенно удобно использовать при работе с итераторами контейнеров и другими типами, от которых зависит шаблон, чтобы не париться с горой typedef'ов. (§7.1.6.4 [dcl.spec.auto])
  7. Возможность вызова конструкторов класса из других конструкторов этого же класса (§12.6.2 [class.base.init]). Очень сильно облегчает написание конструкторов классов, помогает избежать дублирования кода инициализации.
  8. Цикл for по коллекциям (§6.5.4 [stmt.ranged]). Не очень актуально, учитывая появление auto и лямбда-выражений, но объём кода уменьшает.
    int array[5] = { 1, 2, 3, 4, 5 };
    for (int& x : array)
      x *= 2;

  9. Из маленьких приятных мелочей можно упомянуть поддержку генераторов случайных чисел (§26.5 [rand]), атомарных операций (§29 [atomics]), регулярных выражений (§28 [re]) и новых алгоритмов. Например, алгоритм iota (§27.6.5 [numeric.iota]), который заполняет заданный интервал инкрементирующимися значениями, начиная с заданного (подобный функционал я реализовывал с помощью алгоритма generate и самописного класса UniqueNumberGenerator).

15 декабря 2010 г.

Подключение сетевого диска через SSH в Ubuntu

Описание подключения сетевого диска обычным способом см. "Подключение сетевого диска в Ubuntu".

Если доступ на удалённый сервер открыт по протоколу SSH, то в Ubuntu используя модуль sshfs можно подключить любую доступную директорию этого сервера как локальную. Для подключения/отключения директории с помощью sshfs права суперпользователя не нужны.

Установка sshfs:

sudo apt-get install sshfs


Подключение директории удалённого сервера. Например, директорию /some_dir/common с сервера 192.168.1.25. Также предположим, что текущее имя пользователя на локальном компьютере совпадает с именем пользователя удалённого сервера (при подключении будет запрошен пароль доступа через SSH). Следующая команда монтирует директорию /some_dir/common с сервера 192.168.1.25 в локальную директорию ./remote_dir:

mkdir ./remote_dir
sshfs 192.168.1.25:/some_dir/common ./remote_dir


Если имя пользователя на удаленном сервере отличается от локального, то нужно указать это имя при подключении. Например, имя пользователя на удалённом сервере user0001 (при подключении будет запрошен пароль доступа через SSH для пользователя user0001):

sshfs user0001@192.168.1.25:/some_dir/common ./remote_dir


Отключение директории:

fusermount -u ./remote_dir

Команда sshfs также принимает различные опции для управления правами доступа, идентификаторами пользователя и т. д.

Об автоматизации подключения можно почитать здесь.

10 декабря 2010 г.

Цитата: Грэм

Баян, конечно, но странно, что баян не теряет актуальность.

Если вы поедете в Кремниевую Долину, то вы увидите лишь здания. Но Долина состоит не из зданий, а из людей. (...)

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

Наши клоуны начали со зданий.

9 декабря 2010 г.

Саттер рапортует

Херб Саттер рассказал о том, что наконец-то разум восторжествовал комитет C++ решил избавиться от уродливых конструкций атрибутов с двойными квадратными скобками и заменил их на ключевые слова. Лично мне новый вариант нравится намного больше.

Было:
class [[base_check]] Derived : public Base {
public:
  virtual void f [[override]] ();
  virtual double g [[final]] ( int );
  virtual void h [[hiding]] ();
};

Стало:
class Derived explicit : public Base {
public:
  virtual void f () override;
  virtual double g( int ) final;
  virtual void h() new;
};

STL: есть ли жизнь без исключений

Известно, что при компиляции кода можно отключить обработку исключений компилятором (например, опцией -fno-exceptions в GCC, или /EHs- в Visual Studio). Однако, отключение обработки исключений вовсе не означает, что программа не будет генерировать исключения. Это всего лишь означает, что компилятор не будет создавать код для обработки исключений и уничтожения автоматических объектов. А исключения будут продолжать генерироваться — операторами new при нехватке памяти, методом at() класса std::vector при выходе за пределы массива, просто операторами throw расставленными программистом по своему коду и т. д. Различие лишь в том, что так как в программе не будет вообще никакого кода, перехватывающего исключения, то любое сгенерированное в программе исключение приведет к вызову terminate().

Классы стандартной библиотеки сообщают об ошибках только с помощью исключений и никак иначе. Проблема использования STL в том, что когда мы отключаем поддержку исключений в проекте, то лишаемся механизма обработки ошибок. И если проблему с оператором new можно решить его заменой на new (nothrow), то исключение, генерируемое в аллокаторе при вызове vector::resize(), вроде как ничем не заменишь.

6 декабря 2010 г.

Clang API: обход AST (clang-2.8)

В прошлом посте про Clang мы получали абстрактное синтаксическое дерево в виде XML. Теперь попробуем выполнить обход AST вручную. Вручную — это значит создать и инициализировать в программе экземпляры классов, необходимых для анализа исходного файла, построить дерево и получить в коде программы доступ к каждому узлу по очереди, чтобы сотворить с узлами какое-нибудь действо.

29 ноября 2010 г.

Цитата: Резерфорд

Однажды вечером нобелевский лауреат и гениальный физик Резерфорд зашел в лабораторию. Хотя время было позднее, в лаборатории склонился над приборами один из его учеников.
— Что вы делаете так поздно? — спросил Резерфорд.
— Работаю, — последовал ответ.
— А что вы делаете днем?
— Работаю, разумеется, — отвечал ученик.
— И рано утром тоже работаете?
— Да, профессор, и утром работаю, — подтвердил ученик, рассчитывая на похвалу.
Резерфорд помрачнел и раздраженно спросил: — Послушайте, а когда же вы думаете?
Из юмористических баек
о жизни известных физиков

26 ноября 2010 г.

Clang API: получение AST в виде XML


Задача: с помощью Clang API получить XML-файл, описывающий абстрактное синтаксическое дерево (AST) исходного кода. Это можно сделать и простым запуском команды clang с параметром -ast-print-xml в командной строке, но через API — интереснее :)

24 ноября 2010 г.

Исключения C++ и производительность (2)

Предыдущее: Исключения C++ и производительность (1.1)

Итак, я знаю, что в общем случае при обработке сгенерированного исключения происходят дополнительные затраты процессорного времени. Какие они и чем мне это грозит?

23 ноября 2010 г.

Исключения C++ и производительность (1.1)

Предыдущее: Исключения C++ и производительность (1)

Наверное, нужно упомянуть предстоящие изменения в стандарте C++. Херб Саттер, который уже лет десять пытается бороться со спецификаторами throw(), все-таки добился того, чтобы в новом стандарте спецификаторы throw(A, B, ...) считались устаревшими, а спецификаторы throw() были заменены на новый спецификатор noexcept именно с той целью, чтобы компиляторы могли выполнять оптимизацию, если возможно.

Лично я считаю, что как спецификатор не назови (throw или noexcept), то компилятору всё равно. Для программиста — да, noexcept куда более читабельно, но смысл при этом не меняется.

Что касается спецификаторов throw(A, B, ...), то если их все-таки упразднят в окончательной версии стандарта — то и бог с ними, если нет — тоже не страшно. Но мне интересно почему спецификаторы throw(A, B, ...) не использовались для углубленного статического анализа кода компиляторами, это ведь было возможно?.. Вместо того, чтобы их ругать, их можно было превратить в оружие. Ну да ладно, до принятия нового стандарта еще дожить надо :)

Продолжение: Исключения C++ и производительность (2)

22 ноября 2010 г.

Проблемы линковки библиотек clang и llvm

При линковке приложения с библиотеками clang и llvm может возникнуть такая проблема, что нужно передавать линковщику список библиотек в строгом порядке, иначе может возникнуть ошибка "undefined reference" даже если нужная библиотека указана в параметрах линковки. (Как здесь, например. Правда, там у человека еще и строка линковки некорректна.)

Пример:

$ g++ -o ./a.out main.o `llvm-config --ldflags` -lclangFrontend -lclangBasic -lclangDriver -lclangSerialization -lclangCodeGen -lclangSema -lclangChecker -lclangAnalysis -lclangIndex -lclangRewrite -lclangAST -lclangParse -lclangLex `llvm-config --libs`

libclangParse.a(Parser.o): In function `clang::Parser::ExpectAndConsume(clang::tok::TokenKind, unsigned int, char const*, clang::tok::TokenKind)':
Parser.cpp:151: undefined reference to `clang::tok::getTokenSimpleSpelling(clang::tok::TokenKind)'
libclangLex.a(Preprocessor.o): In function `clang::Preprocessor::DumpToken(clang::Token const&, bool) const':
Preprocessor.cpp:155: undefined reference to `clang::tok::getTokenName(clang::tok::TokenKind)'
collect2: ld returned 1 exit status



Все нужные библиотеки указаны, но не в том порядке, в каком хотелось бы линковщику. Проблема в том, что линковщик ищет в каждой библиотеке по одному разу и именно в том порядке, в каком они указаны в командной строке. Например, символ clang::tok::getTokenName находится в библиотеке libclangBasic.a, которая в списке линковки указана раньше.

Можно попытаться поискать правильный порядок (долгая и неблагодарная работа), а можно воспользоваться возможностью группировки библиотек:

$ g++ -o ./a.out ../build/obj/testclang.o `llvm-config --ldflags` -lgtest -lgtest_main -Wl,--start-group -lclangFrontend -lclangBasic -lclangDriver -lclangSerialization -lclangCodeGen -lclangSema -lclangChecker -lclangAnalysis -lclangIndex -lclangRewrite -lclangAST -lclangParse -lclangLex `llvm-config --libs` -Wl,--end-group

Линковщик будет перебирать библиотеки, указанные между ключами --start-group и --end-group снова и снова, пока не отыщет все требуемые символы.

Теперь всё ОК.

18 ноября 2010 г.

Цитата: Бек

У программиста во время работы появляется соблазн думать только о компьютере. Однако во время программирования стоит подумать и о других людях.

Кент Бек, "Шаблоны реализации
корпоративных приложений"

16 ноября 2010 г.

Исключения C++ и производительность (1)

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

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

9 ноября 2010 г.

g++ 4.5 и clang

В Ubuntu 10.10 уже входит gcc 4.5, и я вчера решил собрать clang из репозитория. Всё было хорошо, пока процесс линковки не сожрал полтора гигабайта памяти. После этого он был торжественно убит системой, потому что у меня для виртуалки выделено всего полтора гигабайта. Попробовал собрать с gcc 4.4 — собрался без проблем.

Жаль, но gcc 4.5 всё-таки еще сыроват.

UPD: Смог добиться того, чтобы gcc 4.4 тоже сожрал больше 1,5 Гб. Для этого нужно включить дебаг-режим, включить ассерты и expensive checks, и выключить оптимизатор. Но это, конечно, извращение.

Еще жаль, что clang нельзя собрать без сборки llvm. Или я чего-то не знаю?

25 октября 2010 г.

Битхаки

Хороший сборник хаков по работе с битами — Bit Twiddling Hacks. Мне особенно понравился макрос инициализации таблицы для разворачивания битов.

28 июля 2010 г.

Цитата: Кларк

Единственный способ обнаружения пределов возможного состоит в том, чтобы отважиться сделать шаг в невозможное.

Артур Кларк, Второй закон Кларка

23 июля 2010 г.

fuse_operations::flush и реальность

В библиотеке FUSE (Filesystem in userspace) есть обработчики flush и release. Судя по описанию, обработчик flush вызывается, когда происходит системный вызов close() для файлового дескриптора. То есть сколько раз вызывался open() для файла, столько же раз будет вызван close() и, соответственно, flush. А release вызывается всего один раз, когда в системе не осталось больше ни одного открытого дескриптора этого файла.

В описании fuse_operations::flush есть небольшое примечание:
NOTE:The flush() method may be called more than once for each open(). (...) It is not possible to determine if a flush is final, so each flush should be treated equally. Multiple write-flush sequences are relatively rare, so this shouldn't be a problem.

На деле оказывается, что первый же вызов команды echo с выводом результата в файл (например, "echo blablabla >./1.txt") приводит к следующей последовательности вызовов обработчиков: create - flush - write - flush - release. То есть flush вызывается два раза, причем один раз до записи данных в файл, а второй раз — после. Получается, что корректно закрыть файловый дескриптор в обработчике flush невозможно.

Как с этим бороться — непонятно. Можно, конечно, отказаться от поддержки команд, которые приводят к "multiple write-flush sequences", но так поступать не очень хочется. Поэтому пока реализовал извращение в обработчике release, чтобы хоть как-то обойти проблему двойного вызова flush, а обработчик flush остаётся пустой, потому что при таком раскладе он совершенно бесполезен.

24 февраля 2010 г.

Поиск в Яндекс.Блогах

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

Например, сейчас на странице Яндекс.Блогов вот такая картинка:






Как видно, за последние три дня о трех главных темах блоггеры написали 478 постов. Однако, судя по рейтингам, которые сам же Яндекс и предоставляет, на пост пользователя abstract2001 "Дочка главы избиркома не должна уйти от ответственности" за сутки уже поставлено 430 ссылок (а с момента написания - 534, то есть за 36 часов). Об этом можно узнать, например, у Лебедева или на whoyougle. Вон она в Яндексе на четвертом месте -- "Новые подробности ДТП в Иркутске".

Странно, что за 36 часов блоггеры умудрились поставить ссылок на сообщение об Анне Шавенковой больше, чем по главным темам за три дня, а тема почему-то стоит на четвертом месте. Но фиг с ними. Скорее всего, ссылки с форумов тоже дают результат.

Поиск. Жму на "Новые подробности ДТП в Иркутске". На первой странице вижу, что найдено примерно 570 записей.


Ок. А можно всех посмотреть? Оказывается, нет. На второй странице вижу, что записей уже примерно не 570, а только 300.


А на третьей меня вообще обламывают, сообщая, что записей вообще-то всего 22, и умещаются они всего на трех страницах.


Это как понимать?


Update 24.02.2010  9:30

Тема дня "ДТП в Иркутске" уже на первом месте в Яндекс.Блогах. Видимо, обновляется раз в сутки или что-то типа того. Но поиск все равно лажает.

21 января 2010 г.

Юзабилити мобильных телефонов

Интересно, почему еще никто не додумался сделать в мобильных телефонах поиск контактов по номерам телефонов? У меня в телефоне не так много контактов, около двухсот. У многих моих знакомых список контактов раза в два больше. Но сколько бы их не было — всех не запомнишь.

Вот маленький пример. Есть у Мегафона такая услуга "Всегда на связи". Если ты был недоступен, то при появлении твоего телефона в сети придет СМСка с информацией когда и с какого номера тебе звонили. Сам по себе номер мне ничего не говорит. Вот если б там были написаны имя и фамилия... Или, например, был бы в телефоне пункт меню "Найти контакт по номеру"...

Производители телефонов, добавьте такой функционал! Пожалуйста. Хотя, может, уже есть у кого, просто я не в курсе?

20 января 2010 г.

Thunderbird 3 и Касперский

Обновил свой Thunderbird до версии 3 и получил картинку, похожую на эту:



Исчезла вся почта, папки... Осталась информация о почтовых аккаунтах, контакты и события в календаре. Тааак, думаю, проапгрейдился, блин. Посмотрел в папке Local Settings/Thunderbird. Нет, всё нормально — вся почта на месте, лежит там, разложенная по папкам.

Вспомнил, что Thunderbird не дружит с Касперским. Отключил Касперского, запустил Thunderbird — то же самое. Попробовал переустановить Thunderbird при отключенном Касперском — не помогло.

Порылся в инете. Оказалось, что модуль Kaspersky Anti-Spam Extension 9.0 не совместим с новой версией Thunderbird, но при этом является источником проблемы.

Решение (http://forums.mozillazine.org/viewtopic.php?f=39&t=1637865):

1. Деинсталлировать Thunderbird.
2. Зайти в папку C:\Program Files\Mozilla Thunderbird и удалить из нее оставшееся (а именно — папку components с компонентом Anti-Spam).
3. Установить Thunderbird 3. Всё должно работать корректно.