Блог о программистских вкусностях, которые чаще всего касаются языка C++. Не исключено появление других фишек - это будет зависит от моих сезонных интересов.
Быть в курсе последних статей просто, достаточно подписаться на RSS-ленту.
Обновлено 4.01.2010. Нынче тематика сменилась в сторону Javascript'a
суббота, 31 мая 2008 г.
О чем этот блог?
пятница, 30 мая 2008 г.
Интервью с Владимиром Жилинским
Давно в айтишном секторе русской блогосферы не встречались интересные интервью. Я решил поправить эту ситуацию, и, в связи с этим, хочу представить вашему вниманию интервью со своим коллегой по ремеслу - компетентным веб-разработчиком и вполне известным блоггером Владимиром Жилинским.
› Привет. Рад, что ты согласился дать мне интервью :) Для начала, расскажи немного о себе.
Привет, Сергей. Рад, что моя персона тебя заинтересовала в таком аспекте :-) О себе... Я айтишник, во всех смыслах и стереотипах этого слова. Был сисадмином, программистом, тимлидером, SEO, IT-журналистом. Сейчас занимаюсь этим всем сразу и всегда ломаю голову над тем, что просить писать в трудовой.
› Погуглив немного, выяснилось, что ты женат. В народе ходит много жизненных анекдотов про отношения программиста со своей женой. У тебя бывали анекдотичные ситуации?
Долго мучал гугль, не нашёл такой информации. Выдохнул :-)
Нет, я не женат. Одни сплошные анекдотичные ситуации.
(Мое примечание: А я так надеялся :) Сделал поспешные выводы, прочитав твои интересные факты )
› Ты живешь в замечательном по красоте городе - Питере. Что тебя больше всего привлекает в нем?
Я много городов объехал, но остаться решил в Петербурге. Тут красиво, но в то же время есть огромные возможности и нет такой суматохи как в Москве.
› Один из городов, где тебе пришлось побывать, был Витебск. Я сам из Беларуси. Мне интересно, какие впечатления о моей стране остались у тебя?
Я лет семь в Витебске жил (учёба там прошла), и до сих пор туда иногда приезжаю - отдохнуть. Буквально пару недель назад ездил. Витебск кажется более зелёным, чистым, спокойным. Общее впечатление, конечно, позитивное - замечательные люди, хорошие друзья. А ситуацию в стране оставлю без комментариев - когда я начинаю это комментировать, меня сразу банят за мат, оскорбления и разжигание вражды :-)
› Любой программист в свое время занимался фрилансом. Как у тебя складывались успехи в этой стези?
Да, было дело. Писал статьи в IT-журналы, сайты делал. Мне почему-то сложно заставить себя работать дома, мне нужен офис. Поэтому в итоге я отказался от такой формы работы. Ну и вторая причина - заказчики услуг фрилансеров принципиально отличаются от заказчиков аналогичных услуг в специализированных компаниях. Среди них очень много обычных жмотов, которые хотят всё, вчера и бесплатно, а это самые неприятные клиенты.
› Сейчас ты работаешь в офисе. Преследуют ли тебя антикорпоративные мысли?
Я не против компаний, я против плохих компаний. Если руководство меня не устраивает, если мне не интересно, даже если мне просто не нравится атмосфера в команде - я встаю и ухожу, всё равно продуктивной работы не будет, а сидеть и тупеть мне некогда. А если всё нормально, то для меня это отличный вариант. Не люблю работать с сейлами и бухгалтерами, с ними намного сложнее находить общий язык, чем, например, с программистами.
› Ты можешь поделиться действенным способом отвлечения от работы?
Лучше всего куда-нибудь уехать на несколько дней, не взяв с собой ни телефонов, ни устройств с возможностью выхода в интернет. Это мой дзен-метод восстановления равновесия. А ещё иногда катаюсь на картах и бегаю с маркером.
› Ты поддерживаешь несколько удачных проектов. Начнем с твоего блога. Ему немного больше года, но он стоит наряду с авторитетными блогами по качеству излагаемого материала. Расскажи, как ты добивался такого результата?
Сначала я писал на разные околокомпьютерные темы, прощупывая интересы читателей, анализируя реакции. Потом тематика постепенно сузилась и получилось то, что есть.
Теперь я прилагаю усилия, чтобы не сузить тему окончательно, но сохранить полезность и интересность постов.
Когда писать было не о чем, я шёл на тематические форумы и искал вопросы, которые люди задают с некоторой периодичностью, и давал в блоге развёрнутые ответы.
Главный принцип - всегда писать о том, что может быть полезно. Каждый пост должен решать какую-то проблему. Ну а чтобы придать блогу индивидуальность и оттенки собственной личности, я иногда разбавляю контент постами со своими мыслями, новостями и тем, что интересно мне самому.
Немаловажная часть успешного блогерства - отношения с коллегами-блогерами, тут у меня есть выработанный годами подход. Я всегда отвечаю на вопросы, всегда иду навстречу, всегда помогаю "своим". Исключение - неадекватные люди, с которыми я обычно не церемонюсь и посылаю сразу (на хабре много примеров).
› Блог - это визитная карточка блоггера, особенно айтишника. В связи с этим, каких успехов ты сумел достичь при его помощи?
Сейчас это фактически моё резюме. Когда я писал скандальные статьи про разборки питерских нечистых на руку SEO-компаний, меня настойчиво приглашали на работу и те, о ком я писал, и их конкуренты.
Сейчас моё руководство гордится моими успехами и грамотно использует мои возможности.
› Более 1000 подписчиков с посещаемостью в 400+ человек - это не шутки. Как ты считаешь, это предел?
Нет, абсолютно. Они накапливались постепенно и как серьёзные цифры мной не воспринимаются. С учётом быстрого роста числа пользователей в сети, развиваться есть куда. В моём случае рост, конечно, ограничен узкой тематикой, которая интересна только вебмастерам, но запас ещё огромный.
› В этом году ты запустил проект "Коллеги" и уже прошло достаточно времени, чтобы сделать некоторые выводы. Ты можешь ими поделиться?
"Коллеги" был экспериментальным проектом, который должен был показать возможную активность пользователей. Поэтому они появились в сети в таком жутко недоделанном варианте, на мой взгляд. Их посетили чуть больше 3000 человек, что как раз и говорит о том, что 1000 читателей - не предел, хорошие IT-блоги найдут свою аудиторию. А по статистике кликов в матрице "Коллег" видно то, что и ожидалось - люди просматривают, начиная с верхнего левого угла :-)
› По-моему этот проект вполне самодостаточен и может жить отдельно от блога. Какими ты видишь перспективы его развития?
На самом деле на эту идею можно навешать ещё очень много - придать ему социальности, обмена данными и идеями, сделать полноценную регистрацию, трансляцию RSS, статистику по RSS-лентам блогов (почти готова), ввести теги для поиска, и прочее и прочее... Но катастрофически не хватает времени с учётом более "взрослых" проектов.
› Есть ли у тебя другие проекты? Планируешь ли новые?
Я сейчас все силы трачу на новый сверхамбициозный проект "Moskva.ru", который неофициально должен стать преемником "Одноклассников" и "ВКонтакте", избавив пользователей от их недостатков, которые уже пора исправить. Проект будет запущен первого июля, а инвайт-тестирование начнётся через 2-3 недели. Новости можно отслеживать на созданном сегодня блоге, которым я занимаюсь.
› Каково быть одним из разработчиков наверняка популярной в будущем социальной сети?
Если одним словом - круто.
И наконец-то не скучно :-)
› Ты номинируешься на лучший блог об Информационных Технологиях. Сама номинация - это подтверждение твоего нелегкого труда по взращиванию сильных проектов. Как ты оцениваешь свои шансы на победу?
Это просто любительский рейтинг одного из коллег-блогеров. Мне приятно, что среди моей аудитории есть много лояльных читателей - это главное, а не премия.
› Хочу выразить тебе благодарность, что нашел время и ответил на мои вопросы. Спасибо!
Не за что, коллега :-)
От себя хочу добавить, что это мое первое интервью и, видимо, не последнее. Думаю, вам понравилось! Если не хотите пропустить, подписывайтесь на RSS :) Спасибо за внимание
среда, 28 мая 2008 г.
Полезные ссылки для разработчика
- Free C / C++ Libraries, Source Code and Frameworks - хорошая и достаточно объемная подборка всевозможных библиотек, выложенных в свободный доступ.
- Free C++ (and C) Programming Tools - кроме ссылок на свободно распространяемые инструменты разработки, приводятся наиболее употребительные библиотеки разработки (лайт-версия предыдущей ссылки).
- Object Orientation Tips - краткие заметки по объектно-ориентированным технологиям. Каждая из них снабжена тематическими ссылками на источники информации.
- Open Source Software testing tools, news and discussion - интересный ресурс, на котором сосредоточены ссылки на различные приложения для тестирования собственных проектов. Они разбиты по категориям языка: C/C++, PHP, Ruby и много других.
- More C++ Idioms - викиучебник по идиомам языка. Must read!
воскресенье, 25 мая 2008 г.
Как Gecko формирует веб-страницы? Смотрим видео
Наткнулся на интересный пост, в котором приведено 3 ролика. На них показан процесс, как движок Gecko производит расчет геометрии слоев и их форматирование на веб-странице. Вобщем, смотрите сами ;)
Форматирование страницы wikipedia:
Форматирование страницы mozilla.org:
Форматирование страницы google.co.jp:
Понравилось? Подпишись на RSS! Не пропусти большего :)
Грабли C++. Наследование
Как и обещал, публикую продолжение темы граблей. Предыдущая статья - "Грабли C++. Конструкторы".
Пример:
class Employee
{
public:
Employee(string name, string dept);
virtual void print() const;
string dept() const;
private:
string _name;
string _dept;
};
class Manager : public Employee
{
public:
Manager(string name, string dept);
virtual void print() const;
private:
// ...
};
void Employee::print() const
{
cout << _name << endl;
}
void Manager::print() const
{
// вызовы функций базового класса
cout << dept() << endl;
print();
} Грабли: void Manager::print() const
{
// вызовы функций базового класса
cout << dept() << endl;
print();
}
Функция dept() принадлежит классу Employee и ее вызов происходит в "штатном режиме" в то время, как виртуальная функция print() переопределена в производном классе Manager. Поэтому ее ожидаемого вызова не происходит. В довесок, в этом примере происходит бесконечная рекурсия. Мораль: чтобы избежать такой ситуации, необходимо указывать пространтсво имен, из которой необходимо вызвать виртуальную функцию: void Manager::print() const
{
cout << dept() << endl;
Employee::print();
}
Пример: class Employee;
void Manager::print() const
{
cout << dept() << endl;
Employee:print();
}
Грабли: Employee:print();Понятно, что должно быть так:
Employee::print();Но почему этот пример удачно компилируется? Потому что Employee явлется меткой. Мораль: стоит внимательно смотреть за оператором расширения пространства имен ::. Пример:
class Employee
{
public:
void raise_salary(double by_percent);
// ...
};
class Manager : public Employee
{
public:
// ...
};
void make_them_happy(Employee* e, int ne)
{
for (int i = 0; i < ne; i++)
e[i].raise_salary(0.10);
}
int main()
{
Employee e[20];
Manager m[5];
m[0] = Manager("Иван Иванов", "Продажи");
// ...
make_them_happy(e, 20);
make_them_happy(m + 1, 4); // пропустим Иванова
return 0;
}Слабо определить, где грабли? Грабли: void make_them_happy(Employee* e, int ne); Manager m[5]; make_them_happy(m + 1, 4);Что происходит в этом коде?
m + 1 - это тип Manager*. Через наследование, указатель на Manager становится указателем на Employee. "И что тут странного?" - спросите вы.
Все дело в том, что при выполнении операции e[i] происходит смещение внутри массива на значение, равное i*sizeof(Employee).
Мораль: не стоит злоупотреблять использованием указателей. Есть две трактовки записи Employee* e:
1. е указывает либо на объект класса Manager, либо на объект одно из его производных классов, например Employee;
2. e указывает либо на объект класса Manager, либо на их набор (массив).
Эти две трактовки несовместимы между собой. Путаница в них приводит к ошибкам времени выполнения. (В результате выполнения этого кода, происходит "затирание" полезных участков памяти.)
Данную тему можно продолжать бесконечно. Оригинальную статью по описанным выше граблям можно найти здесь. В ней вы найдете еще больше примеров.
среда, 21 мая 2008 г.
Насколько интересна тема создания ботов для покера?
How I Built a Working Online Poker Bot, Part 2: Interlude.
Блоггер не побрезговал и выложил статистику взрывной посещаемости его блога, которая говорит о большом интересе к затронутой теме. По-крайней мере, интерес к вопросу, где раскрываются аспекты заработка на хлеб с маслом, всегда будет популярным.
Изложение статьи очень интересное и доступное. Рекомендую прочитать хотя бы из любопытства :)
А чтобы не пропустить выход моих интересных постов, достаточно подписаться на RSS. Оставайтесь на связи!
вторник, 20 мая 2008 г.
Грабли C++. Конструкторы
Что такое грабли?
Код C++, который:
- компилируется,
- линкуется,
- запускается,
- но делает совсем не то, что ожидается.
Маленький пример:
if (-0.5 <= x <= 0.5) return 0;Грабли:
if (-0.5 <= x <= 0.5) return 0;Это выражение не проверяет математическое выражение вида:
-2.4 <= x <= 2.6
Вместо этого сначала вычисляется выражение -2.4 <= x, которое может принимать значение 0 либо 1 (в зависимости от x), а затем полученный результат сравнивается с числом 2.6.
Мораль: хоть C++ имеет встроенный тип bool, булевские переменные все еще спокойно конвертируются в тип int.
До тех пор, пока такое возможно, компилятор не сможет определить обоснованность записанного выражения. Единственное, на что он способен — это предупредить о небезопасном использовании типа bool.
Грабли, связанные с конструктором
Пример:
int main()
{
string a("Hello");
string b();
string c = string("World");
// ...
return 0;
}Грабли:
string b();
Это выражение не создает объект b типа string. В всего лишь определяет прототип функции b без аргументов и с возвращаемым типом string.
Мораль: помните, что необходимо опускать скобки при вызове конструктора по-умолчанию.
Объявление функции в стиле С в локальном пространстве имен не несет полезной нагрузки. Лучше всего помещать его в файл заголовков, чтобы вышеописанная ловушка не сработала.
Пример:
template<typename T>
class Array
{
public:
Array(int size);
T& operator[](int);
Array<T>& operator=(const Array<T>&);
//....
};
int main()
{
Array<double> a(10);
a[0] = 0; a[1] = 1; a[2] = 4;
a[3] = 9; a[4] = 16;
a[5] = 25; a = 36; a[7] = 49;
a[8] = 64; a[9] = 81;
// ...
return 0;
} Грабли:
a = 36;К удивлению, но, в общем-то, выполняется следующий код:
a = Array<double>(36);где, объект a заменяется новым массиов в 36 элементов.
Мораль: Конструкторы с одним аргументом выполняют побочную работу — приведение типов.
Избегайте конструкторы с одним аргументом (особенно с типом int). Либо используйте ключевое слово explicit, чтобы избежать такую ситуацию.
Пример:
template<typename T>
class Array
{
public:
explicit Array(int size);
// ...
private:
T* _data;
int _size;
};
template<typename T>
Array<T>::Array(int size)
: _size(size),
_data(new T(size))
{
}
int main()
{
Array<double> a(10);
a[1] = 64; // нарушение целостности памяти
// ...
} Грабли:
template<typename T>
Array<T>::Array(int size)
: _size(size),
_data(new T(size)) // должно быть new T[size]
{
}
В чем проблема?
new T(size)возвращает указатель T* на единичный объект T, инициализированный значением size.
new T[size]возвращает указатель T* на массив объектов типа T размером size, созданный конструктором по-умолчанию.
Мораль:
Массив и указатель имеют одинаковую природу, и поэтому несут в себе опасность.
Пример:
template<typename T>
class Array
{
public:
explicit Array(int size);
// ...
private:
T* _data;
int _capacity;
int _size;
};
template<typename T>
Array<T>::Array(int size)
: _size(size),
_capacity(_size + 10),
_data(new T[_capacity])
{}
int main()
{
Array<int> a(100);
//....
} Грабли:
Array<T>::Array(int size)
: _size(size),
_capacity(size + 10),
_data(new T[_capacity]) // <---
{} Инициализация членов выполняется в порядке объявления в классе, а не по порядку появления в строке инициализации конструктора.
Совет: не используйте члены-данные в выражениях инициализации.
Array<T>::Array(int size)
: _data(new T[size + 10])
_capacity(size + 10),
_size(size)Пример:
class Point
{
public:
Point(double x = 0, double y = 0);
// ...
private:
double _x, _y;
};
int main()
{
double a, r, x, y;
// ...
Point p = (x + r * cos(a), y + r * sin(a));
// ...
return 0;
}Грабли:
Point p = (x + r * cos(a), y + r * sin(a));Корректным будет выполнить следующий код
Point p(x + r * cos(a), y + r * sin(a))либо
Point p = Point(x + r * cos(a), y + r * sin(a));Выражение
(x + r * cos(a), y + r * sin(a))имеет искаженное понимание. Оператор запятая не учитывает x + r * cos(a) и выполняет y + r * sin(a). В данном случае вызывается конструктор со следующими параметрами:
Point(y + r * sin(a), 0)Мораль: аргументы по-умолчанию могут привести к непреднамеренным вызовам. В нашем случае, конструктор Point(double) некорректен, зато Point() - вполне приемлимо. Использовать аргументы по-умолчанию необходимо лишь в том случае, когда все способы вызова такого конструктора осмысленны.
Грабли, связанные с деструктором
Пример:
class Employee
{
public:
Employee(string name);
virtual void print() const;
private:
string _name;
};
class Manager : public Employee
{
public:
Manager(string name, string dept);
virtual void print() const;
private:
string _dept;
};
int main()
{
Employee* staff[10];
staff[0] = new Employee("Harry Hacker");
staff[1] = new Manager("Joe Smith", "Sales");
// ...
for (int i = 0; i < 10; i++)
staff[i]->print();
for (int i = 0; i < 10; i++)
delete staff[i];
return 0;
}Где здесь утечка памяти?
Грабли:
delete staff[i];удаляет все объекты деструктором ~Employee(). Строка _dept объекта Manager никогда не удалится.
Мораль: Наследуемый класс должен иметь виртуальный деструктор.
Пример:
class Employee
{
public:
Employee(string name);
virtual void print() const;
virtual ~Employee();
private:
string _name;
};
class Manager:public Employee
{
public:
Manager(string name, string sname);
~Manager();
private:
Employee* _secretary;
}
Manager::Manager(string name, string sname)
: Employee(name),
_secretary(new Employee(sname))
{}
Manager::~Manager() { delete _secretary; }Где затаилась проблема?
Грабли:
int main()
{
Manager m1 = Manager("Sally Smith","Joe Barnes");
Manager m2 = m1;
// ...
}Деструкторы обоих объектов m1 и m2 удалят один и тот же объект класс Employee.
Мораль: необходимо позаботиться о копирующем конструкторе
Manager::Manager(const Manager&)и об операторе присваивания
Manager& Manager::operator=(const Manager&)в случае, если класс содержит сложные типы данных (в том числе указатели)
Продолжение следует... Чтобы не упустить продолжение, достаточно подписаться на RSS.
вторник, 13 мая 2008 г.
У вас отображается форма для комментирования?
Меня насторожила ситуация, что к последним постам не было ни одного комментария, учитывая немалый к ним интерес (судя по статсам). Я подозреваю, что это произошло после добавления фичи Disqus. Мои опасения подтвердились: в 2 из 4 подопытных браузерах форма не отображалась (Firefox и IE). Скорее всего, это из-за специфических настроек. В моей любимой Опере все отображается очень даже классно (в сравнении с формой от blogger.com).
Вот я решил спросить, действительно ли ситуация у вас такова? Если да, то мне придется отказаться от нее и перейти на стандартный блогспотовский. Свои комментарии оставляйте там в случае, если здесь форма не отображается.
Даже если у вас все в порядке, оставьте свой комментарий, подтверждающий это. Я хочу в этом удостовериться. Спасибо ;)
ЗЫ. Проблема уже решена
понедельник, 12 мая 2008 г.
Как я создал бот для покера
Наверное многие, кто имел дело с онлайн играми (особенно картежными), желали иметь под рукой программу, которая помогала бы выполнять статистические расчеты, а может и вообще совершала бы все необходимые манипуляции. Может даже некоторые пользовалась такими программами. И это не удивительно. Потому как создать свой бот - вполне возможно! Достаточно иметь programming skills.
По-крайней мере, одному человеку это удалось наверняка. Подтверждающий пост с заголовком How I Built a Working Poker Bot и вышел в блоге Coding The Wheel.
Как принято говорить в русской блогосфере, блоггер James Devlin спалил тему. Хотя, на самом деле, скачать рабочий бот у вас врятли получиться, а вот понять принцип работы - запросто. Для этого особых знаний не надо, если уж читаете этот блог :) От вас требуется всего ничего:
- Windowing GDI
- Windows Hooks
- Kernel objects
- DLL Injection (in general: the injecting of code into other processes)
- API Instrumentation (via Detours or similar libraries)
- Inter-process Communication (IPC)
- Multithreading & synchronization
- Simulating user input
- Regular expressions (probably through Boost)
- Spy++
На данный момент по ссылке можно почитать лишь вводный пост. Он уже успел вызвать резонанс интереса к этой теме.
Чтобы оставаться в курсе событий, достаточно подписаться на RSS. Все самое интересное впереди!
суббота, 10 мая 2008 г.
Cоздание веб-сайтов на C++? Легко!
Меня трудно удивить, но данная возможность повергла меня в шок!
Я верю в то, что талантливый программист талантлив во всем, и освоить новый язык с целью разработки веб-приложений не составит для него особого труда. Тем более, разработчик на C++ без труда может изучить тот же PHP5, который по синтаксису и логике очень схож с ним.
Но! Каким надо быть энтузиастом, чтобы разработать библиотеку, с помощью которой можно без проблем писать и поддерживать собственные веб-приложения на любимом языке, так же просто, как написать любое другое консольное приложение! Чтобы начать, надо всего лишь изучить библиотеку Wt. Она позволяет использовать C++ в качестве server-side языка (не CGI).
В общем, ознакомьтесь с Витти лично. Она стоит того! И, кстати, она распространяется по лицензии GPL. Не прослеживаете аналогий с Qt?
На затравку — простейший пример.
вторник, 6 мая 2008 г.
Coding Style. Part 2
»Стиль программирования. Часть 2«
Читать другие материалы серии статей "Стиль программирования":
Вступление, Часть 1
Пробельные символы
Правило 9
Вступительный комментарий, защита заголовков, блок #include, блок using и определения функций разделяются двумя пустыми строками. Это позволяет визуально выделить логические блоки кода.
Правило 10
В конце файла необходимо поставить символ новой строки. Это требование стандарта C++, игнорируемое многими компиляторами.
Комментарии
Правило 11
Все файлы с исходным кодом должны быть откомментированы при помощи вступительного комментария, который предоставляет информацию об имени файла, его версии и содержимом.
Правило 12
Все файлы должны включать информацию о копирайте.
Правило 13
Все комментарии пишутся на английском языке (естественно, данного правила не придерживаются, как и многих других - прим. перев.).
Правило 14
Пишите комментарии для каждого класса, каждой его функции и определенных типов данных (enum/typedef/struct). Стандартное комментирование позволяет автоматически генерировать справочную документацию по исходному коду. Это может быть использовано для поддержки документации в актуальном состоянии.
Правило 15
Используйте "//" для комментариев.
Комментарий должен быть компактным и быть на видном месте. Используя тщательно подобранные имена переменных, функций и классов, и правильно разбив код на логические блоки, нет особой необходимости в излишнем комментировании.
Заметьте, что комментарии в заголовочном файле предназначены для тех, кто будет использовать классы, в то время, как комментарии в файле реализации предназначены для тех, кто сопровождает эти классы.
Комментарии делятся на две категории - стратегические и тактические. Стратегические комментарии описывают, что будет функция или часть кода выполнять, и располагаются перед этим кодом. Тактические - описывают, что выполняет однострочный код, и располагаются в конце строки. К сожалению, большое число тактических комментариев делают код плохочитаемым. По этой причине, рекомендуется использовать в основном стратегические комментарии, за исключением случаев, когда необходимо пояснить слишком сложный код.
Если символы // используются в основном для написания непосредственно комментариев, то комбинация /* */ может пригодиться в случае, когда необходимо исключить цельную часть кода из процесса разработки или отладки. C++ не поддерживает вложенные комментарии вида /* */, поэтому лучше всего воспользоваться условными директивами препроцессора (#ifdef 0 ... #endif) для разграничения большого куска кода.
Продолжение следует...
Чтобы быть в курсе последних статей, подпишись на RSS. Это просто!



