24 марта 2007

Declarative programming

В продолжение темы предыдущего поста про философию программирования. Всем, кто "застрял" в императивном программировании, предлагаю расширить кругозор программированием декларативным.

В частности, можно почитать книгу по Хаскелю и посмотреть видео-лекции по Лиспу.

22 марта 2007

Языковой барьер

Очень правильная заметка - Языковой барьер.

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

Больше внимания нужно уделять именно "духу" языка. Не стоит писать на C++ как на "расширенном C". Следует проникнуться RAII, шаблонами, умными указателями и патернами.

Всем, кто не читал, рекомендую книги Александреску, Саттера и Мэйерса. Особенно Современное проектирование на С++.

06 марта 2007

clone()

Иногда есть "тяжеловесные" классы, для которых нежелательно допустить неявное копирование. Обычно это делается так:
class Foo
{
private:
Foo(const Foo&);
Foo& operator=(const Foo&);
};
Однако, возникает вопрос: как все-таки явно скопировать объекты такого типа?

Хорошее решение этого вопроса: использование функции clone(), как это сделано в Boost Pointer Container Library:
ptr_vector<T> v1, v2(v1.clone());
v2 = v1.clone();
Clone() создает свой клон на куче (да хоть через тот же приватный конструктор копирования) и возвращает auto_ptr на него, а соотвутствующий конструктор и оператор присваивания делают свое дело через swap():
class Foo
{
public:
void swap(Foo&);
auto_ptr<Foo> clone() const;

Foo(auto_ptr<Foo> clone)
{
swap(*clone);
}

Foo& operator=(auto_ptr<Foo> clone)
{
swap(*clone);
return *this;
}
};

04 марта 2007

Bicycles and Weak pointers

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

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

А вот теперь представим ситуацию: один объект удалился, затем создался другой. Причем operator new() может спокойно выдать адрес, равный адресу старого объекта. И если предварительно мы запомнили адрес первого (удаленного) объекта, то менеджер (упомянутый ранее) скажет нам что указатель наш валиден, хотя на самом деле объект, на который мы ссылались - уничтожен.

А все могло бы быть и без этой головной боли. Если бы в качестве указателя на объект мы запомнили не простой указатель, а велосипед под названием weak pointer, и при обращении к объекту просто лочили его.