пятница, 23 апреля 2010 г.

[prog.c++] Слайды Solid C++ Code by Example с конференции ACCU 2010

Некоторые докладчики конференции ACCU 2010 уже выложили в сеть слайды своих докладов. Например, Olve Maudal опубликовал слайды своего выступления Solid C++ Code by Example.

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

В Интернете так же есть презентация того же автора на ту же тему, но от 2008 года: C++ Idioms by Example, lesson 1.

Но, поскольку я в C++ не новичок и многое из изложенного в презентациях я делаю уже на автопилоте, то ряд моментов вызвал у меня некоторое недоумение.

Начну с презентации от 2008 года.

Рекомендация первая: не делать using namespaces (стр.24). Спорная штука. Я сам стараюсь избегать using namespace, особенно в заголовочных файлах. Но иногда эта инструкция избавляет от изрядного геморроя и сильно повышает читабельность текста.

Рекомендация вторая: при определении тела свободной функции из какого-то пространства имен, не нужно открывать это пространство имен (ст.65). Т.е. вместо:

// bar.hpp
#if !defined( BAR_HPP )
#define BAR_HPP

namespace bar {
   void print();
}

// bar.cpp
#include <bar.hpp>

namespace bar {
   void print() {
      ...
   }
}

нужно поступать в файле bar.cpp вот так:

// bar.cpp
#include <bar.hpp>

void bar::print() {
   ...
}

Интересно, что он прикажет мне делать, когда у меня пространства имен носят названия вида: aag_3::utils::rdbms::odbc_multi::otl_connect_factory?

Но больше всего в презентации 2008-го года меня убила последняя рекомендация на стр.74: настоящие, мол, профессионалы делают отступ в 4 пробела. Она как! :)

Теперь к новой презентации от 2010-го. Здесь есть моменты, которые (как и в случае с 4-мя пробелами) являются не столько рекомендациями, сколько “доколупыванием”. Нужно было до чего-то доколупаться, вот и доколупались.

Вот здесь (стр.69):

const std::size_t data_offset(to.end() - to.begin());

автору не понравилось, что data_offset инициализируется в синтаксисе конструктора, а не присваиванием. Там же ниже по коду:

std::vector<uint8_t> buffer(prefix, prefix + sizeof(prefix));

он требует убрать скобки в выражении sizeof.

Интереснее на странице 63. Там приведен конструктор класса, в котором атрибуты domain_ и workstation_ не перечислены в списке инициализаторов. Т.е. конструктор имеет вид:

pal::type3_message::type3_message(
   const std::vector<uint8_t> & lm_response,
   const std::vector<uint8_t> & nt_response,
   const std::string & user,
   uint32_t ssp_flags)
   :
   lm_response_(lm_response),
   nt_response_(nt_response),
   user_(user),
   ssp_flags_(ssp_flags)
   session_key_(session_key_size)
{...}

А автору хочется, чтобы он имел вид:

pal::type3_message::type3_message(
   const std::vector<uint8_t> & lm_response,
   const std::vector<uint8_t> & nt_response,
   const std::string & user,
   uint32_t ssp_flags)
   :
   lm_response_(lm_response),
   nt_response_(nt_response),
   domain_(),
   user_(user),
   workstation_(),
   session_key_(session_key_size)
   ssp_flags_(ssp_flags)
{...}

Атрибуты domain_ и workstation_ имеют тип std::string. У этого типа есть нормальный конструктор по умолчанию. Зачем демонстрировать факт этого в списке инициализаторов я не понимаю. А автор не объясняет.

Еще на странице 74 автор доколупался до метода debug_print. Метод этот писал значения атрибутов класса в указанный std::ostream. С багами, но писал. На странице 87 приведен модифицированный вариант этого метода, устраивающий автора. Новый debug_print не пишет в std::ostream. Он использует внутри себя std::stringstream и возвращает std::string.

Я не понял, зачем потребовалось заменять печать в ostream на возврат строки. Но зато автор выступления сам попался в собственные сети – почему у debug_print-а осталось старое название? Смысл-то поменялся. Нужно было дать название, например, to_debug_string или make_debug_string :/

Резюмирую. В обоих презентациях есть изрядное число полезных советов. Но нет ни одного объяснения, почему нужно поступать именно так. Человек с опытом понимает почему, а вот новичку остается только верить на слово. При этом следовать некоторым советом Olve Maudal я бы не рекомендовал.

PS. Это тот самы Olve Maudal, который написал главу в книгу 97 Things Every Programmer Should Know, о которой я уже писал. Глава называется Hard Work Does Not Pay Off и содержит, на мой взгляд, набор банальностей о том, как плохо много работать.

2 комментария:

Miroslav комментирует...

//in cpp file
namespace otl_fac=aag_3::utils::rdbms::odbc_multi::otl_connect_factory;
ы ?

юзинги в хидерах вне пространства имен - это айяйяй :)

eao197 комментирует...

>otl_fac=aag_3::utils::rdbms::odbc_multi::otl_connect_factory;


Ну и какой смысл затем писать вот так:

void otl_fac::init_odbc_mssql_factory() { ... }
void otl_fac::init_odbc_firebird_factory() { ... }
void otl_fac::init_odbc_oracle_factory() { ... }
void otl_fac::init_factories() {
otl_fac::init_odbc_mssql_factory();
otl_fac::init_odbc_firebird_factory();
otl_fac::init_odbc_oracle_factory();
}

Если все тоже самое внутри открытого пространства имен можно написать без префиксов?

>юзинги в хидерах вне пространства имен - это айяйяй :)

А с этим я и сам согласен и сам за такие вещи по рукам бью. Но речь шла даже о using-ах в cpp-файлах.