Новый триал IBProvider-а [сборка 15302]. Ревизия кода

Привет всем.

Новый рабочий год начинается тяжко начал с ревизии и доработки существующего кода :). А конкретнее:
— Натравил на код анализаторы.
— Немного оптимизировал работу с низкоуровневыми конструкциями, на которых базируется вся инфраструктура.

Анализ кода.

1. Сначала я прогнал исходный код через компилятор (VS2012) с включенным 4-м уровнем предупреждений. Первоначальное число ошибок было в районе трех сотен. Сократил до 50-штук. Наиболее положительный эффект (в виде уменьшения размера бинарника) дало уничтожение недостижимого кода. Это были return-ы после выкидывания исключений.

Кроме того, были обнаружены и устранены потенциально опасные ситуации с неинициализированными переменными.

2. Потом я снова натравил на код статический анализатор кода 2012 студии. Изничтожил еще несколько предупреждений. В частности, анализатор выявил некритичную ошибку в использовании sprintf. Я вообще-то стараюсь не использовать эти муторные функции (то есть, практически совсем их не использую). И надо бы окончательно исключить их из кода.

3. Прогнал код через триал PVS Studio. Он нашел еще пару ошибок (к счастью, неопасных) созданных по китайской технологии copy&paste. И, в целом, также способствовал улучшению качества кода.

Моя первая реакция на результаты работы этого анализатора — «вот сукины дети!» 🙂

Оптимизация низкоуровневых примитивов.
В основе большинства конструкций провайдера лежат объекты со счетчиками ссылок. Управляются они смарт-указателями, которые автоматизируют инкременты (AddRef) и декременты (Release) этих счетчиков. Этот подход к конструированию применяется мною где-то с 2000 года, и время от времени появляются мысли по поводу оптимизации работы этих смарт-указателей.

В предпоследний раз оптимизация была связана с внедрением rvalue-reference, которая сократила число вызовов AddRef/Release при перемещении (move) смарт-указателей:

template<class T,class traits_data>
inline
 t_smart_object_ptr<T,traits_data>::t_smart_object_ptr(self_type&& ptr)
  :m_ptr(__STL_MOVE_VALUE(ptr.m_ptr))
{
 ptr.m_ptr=NULL;
}//t_smart_object_ptr - move constructor

А в этот раз я допер, что в коде вида:

t_smart_object_ptr<t_my_object> spObj(new t_my_object());

можно подсказать конструктору смарт-указателя, что передаваемый аргумент не равен NULL. Например так:

t_smart_object_ptr<t_my_object> spObj(not_null_ptr(new t_my_object()));

В результате будет вызываться не универсальный конструктор

template<class T,class traits_data>
inline
t_smart_object_ptr<T,traits_data>::t_smart_object_ptr(pointer const ptr)
 :m_ptr(ptr)
{
 if(m_ptr)
  traits_data::increment_cntRef(m_ptr);//->add_ref();
}

а специализированный, в котором отсутствует «if»:

template<class T,class traits_data>
template<class U>
inline
t_smart_object_ptr<T,traits_data>::t_smart_object_ptr(const t_not_null_ptr<U>& nn_ptr)
 :m_ptr(nn_ptr)
{
 assert(m_ptr);
 traits_data::increment_cntRef(m_ptr);//->add_ref();
}

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

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

Конечно, эта оптимизация даст 0% к производительности кода в реальных условиях. Я это точно знаю. Но все равно — приятно, что «пока еще могу» 🙂

Leave a Comment