Комментарии 6
Странно, что такая отличная серия переводов так мало плюсуется. На хабре, по-моему, вообще ещё не было ни одного доведённого до конца перевода целой книги. А тут по всему видно, что дело будет до конца доведено, круто.
Рука не поднимается плюс ставить по причинам:
Разумеется минус я тоже не стал ставить.
- Макросы MEM_FN. Перевод для начинающих, ну и не надо начинающих программистов приучать к макросам. Это же C++.
- Форматирование исходных текстов ужасно. Я понимаю, что это нудно и неудобно… но код должен быть оформлен красиво.
- Ну и содержимое на столько простое и очевидное, что лично я не вижу смысла в этом переводе. Документация у boost не на столько хороша, как у Qt, но все же имеется.
Разумеется минус я тоже не стал ставить.
1) расскажите пожалуйста подробнее, что плохого в таких макросах:
Это же простые однострочники, при том безопасные, и даже контроль типов нигде не пропущен из-за простоты. Для реализации этого «по сиплюсплюсному» потребовался бы шаблон, который был бы гораздо толще и лишь помешал бы восприятию кода.
2) это тема вечного холивара, по мне так нормальное вполне, что конкретно Вам не понравилось? И да, прошу осознать, что это всё таки перевод.
3) no comment.
#define MEM_FN(x) boost::bind(&self_type::x, shared_from_this())
#define MEM_FN1(x,y) boost::bind(&self_type::x, shared_from_this(),y)
#define MEM_FN2(x,y,z) boost::bind(&self_type::x, shared_from_this(),y,z)
Это же простые однострочники, при том безопасные, и даже контроль типов нигде не пропущен из-за простоты. Для реализации этого «по сиплюсплюсному» потребовался бы шаблон, который был бы гораздо толще и лишь помешал бы восприятию кода.
2) это тема вечного холивара, по мне так нормальное вполне, что конкретно Вам не понравилось? И да, прошу осознать, что это всё таки перевод.
3) no comment.
1. Плох сам факт использования макросов. Это как если бы вместо for/while использовать метку и goto, вроде такого:
Казалось бы, ну что тут плохого? Код на C++, компилируется и работает без ошибок. Значит код правильный и использовать можно. Примерно такими же соображениями руководствовался программист, сделавший в где-то в WinAPI макрос с именем max и мне уже много лет приходится писать #ifdef max\n#undef max\n#endif. Чем именно плохи макросы, по моему, написано в любой книге по программированию на C++ и также дана рекомендация не использовать их. Но давайте я не буду учить вас программированию.
2. Тема для холивара — это какой стиль лучше. Тут же, откровенно говоря, стиля нет вообще. Код написан небрежно.
Вот например:
и тут уже ниже
Глядя на первый кусок уже и не кажется, что строка
Тут вообще аргумент функции на новой строке.
Вот зачем специально запутывать людей, создавая тип
должны быть объявлены вот так:
Ну и все остальное в том же духе. Конечно кому-то кажется, что человек может писать так, как ему хочется. Использовать макросы и goto, привидение типов в стиле C, free и delete вместо RAII… Надо проработать программистом не один год и в разных командах, чтобы осознать важность этих правил.
И да, я вижу, что это перевод. И даже потрудился заглянуть в оригинал и выяснить, что макросы и такой вот нехороший код идут от туда, а не от переводчика. Но вопрос был совсем не в том, хорош перевод или нет. Я отвечал на комментарий объяснив причину, по которой я стал ставить плюс.
int i = 0;
label:
// code
if (++i < 100)
goto label;
Казалось бы, ну что тут плохого? Код на C++, компилируется и работает без ошибок. Значит код правильный и использовать можно. Примерно такими же соображениями руководствовался программист, сделавший в где-то в WinAPI макрос с именем max и мне уже много лет приходится писать #ifdef max\n#undef max\n#endif. Чем именно плохи макросы, по моему, написано в любой книге по программированию на C++ и также дана рекомендация не использовать их. Но давайте я не буду учить вас программированию.
2. Тема для холивара — это какой стиль лучше. Тут же, откровенно говоря, стиля нет вообще. Код написан небрежно.
Вот например:
void on_read(const error_code & err, size_t bytes)
{
if ( err) stop();
if ( !started() ) return;
std::string msg(read_buffer_, bytes);
if ( msg.find("login ") == 0) on_login(msg);
else if ( msg.find("ping") == 0) on_ping();
else if ( msg.find("ask_clients") == 0) on_clients();
}
и тут уже ниже
void on_clients()
{
std::string msg;
for(array::const_iterator b =clients.begin(),e =clients.end(); b != e; ++b)
msg += (*b)->username() + " ";
do_write("clients " + msg + "\n");
}
Глядя на первый кусок уже и не кажется, что строка
msg += (*b)->username() + " ";
является телом цикла. Ведь даже отступа нет. void read_answer()
{
already_read_ = 0;
read(sock_, buffer(buff_),
boost::bind(&talk_to_svr::read_complete, this, _1, _2));
process_msg();
}
Тут вообще аргумент функции на новой строке.
typedef std::vector<client_ptr> array;
array clients;
Вот зачем специально запутывать людей, создавая тип
array
, который на самом деле vector
? Это ведь разные типы данных, один динамический массив, другой использует память на стеке. Кстати говоря, члены класса talk_to_client: char read_buffer_[max_msg];
char write_buffer_[max_msg];
должны быть объявлены вот так:
boost::array<char, max_msg> read_buffer_;
boost::array<char, max_msg> write_buffer_;
Ну и все остальное в том же духе. Конечно кому-то кажется, что человек может писать так, как ему хочется. Использовать макросы и goto, привидение типов в стиле C, free и delete вместо RAII… Надо проработать программистом не один год и в разных командах, чтобы осознать важность этих правил.
И да, я вижу, что это перевод. И даже потрудился заглянуть в оригинал и выяснить, что макросы и такой вот нехороший код идут от туда, а не от переводчика. Но вопрос был совсем не в том, хорош перевод или нет. Я отвечал на комментарий объяснив причину, по которой я стал ставить плюс.
1. На макросы будет много ругани при компиляции если макрос с таким именем уже присутствует.
Вообще то WinAPI, как и огромное количество другого системного кода, это C, а не C++, а стало быть наличие там данных макросов — нормальная ситуация. И да, в ОС используются гораздо более серьёзные макросы, в том числе и глобальные. К слову, в С++ до сих пор не реализован даже if этапа компиляции, и это огромная проблема, зато реализованы монструозные конструкции sfinae на которых и предлагается что то делать по «сиплюсплюсному» для реализации парадигмы «if этапа компиляции».
2.
void on_read(...) — нормальный код, хотя если бы его писал я, то написал бы со скобками под каждым условием,
а вообще
Пусть код со скобками для меня привычнее, но это нисколько не мешает воспринять условия в исходном примере кода с однострочными ифами — так очень многие пишут.
С void on_clients() скорее согласен, отступ там желателен, но почему бы не сообщить о таком допущении в личку?.. До кучи я бы, к примеру, использовал там сокращённую запись из C++11: for(const auto &b: clients), однако даже этот факт не мешает нормальному восприятию кода, к тому же это перевод, и судя по другим участкам кода — в оригинале код C++03.
c read_answer() проблем не наблюдаю, перенос длинных строк с параметрами — общепринятая практика, пусть там и не хватает отступа, и возможно этот перенос вообще не нужен, но это не мешает, и это ещё один недочёт сродни опечатки, о котором стоит сообщить в личку. Можно было даже в личку отправить предложение об использовании Astyle, но смысла обсуждать сие нет совсем никакого.
Ситуация с
У меня к Вам претензия: на дворе 2013 год, а Вы почему то предлагаете boost::array а не std::array на замену! :) Ладно шучу, просто это действительно не то из-за чего могут быть проблемы с восприятием примера кода! Это пример использования, и никто не заставляет данный код копипастить и сразу же использовать в промышленном применении, это просто пример :) К слову у Александреску, в примерах, вообще местами адский-ад.
Пожалуй соглашусь только с привидением типов в стиле C при использовании в C++, а вот всё остальное: макросы, goto, и сырые указатели использовать можно если это действительно необходимо. К слову C++ из-за отсутствия make_unique даже в C++11 не полностью гарантирует безопасность использования умных указателей, а С++03 толком вообще этих возможностей не имеет (умолчим тут про auto_ptr, с которым были проблемы, о которых надо было знать, и неоднозначность с которой вообще ничего поделать было нельзя, и который ныне, к счастью — deprecated). Безусловно в Boost умные указатели появились раньше С++11, но факт остаётся фактом.
p.s: руководствуясь написанным у Вас в пункте 3 вообще не понимаю зачем было писать что либо в данном топике, если данная тема Вам не интересна.
Примерно такими же соображениями руководствовался программист, сделавший в где-то в WinAPI макрос с именем max и мне уже много лет приходится писать #ifdef max\n#undef max\n#endif.
Вообще то WinAPI, как и огромное количество другого системного кода, это C, а не C++, а стало быть наличие там данных макросов — нормальная ситуация. И да, в ОС используются гораздо более серьёзные макросы, в том числе и глобальные. К слову, в С++ до сих пор не реализован даже if этапа компиляции, и это огромная проблема, зато реализованы монструозные конструкции sfinae на которых и предлагается что то делать по «сиплюсплюсному» для реализации парадигмы «if этапа компиляции».
2.
void on_read(...) — нормальный код, хотя если бы его писал я, то написал бы со скобками под каждым условием,
а вообще
как то так:
хотя конечно я немножко лукавлю, ибо написал бы с использованием memcmp что бы не создавать строку просто так:
, и гарантированно вынес бы проверки в две инлайн функции, после чего добавил бы пару макросов ]:-> для избежания ошибок при использовании, и для компактности при написании. Собственно и on_login я бы переписал, что бы там строки не было. Зачем всё это? — для высоконагруженных приложений, которые требуют быстрого, надёжного и легко читающегося кода. Но всё же пусть мой код и быстрее, но для данного примера он избыточен, и лишь запутает читателя.
void on_read(const error_code & err, size_t bytes)
{
if (err)
{
stop();
}
else if (started())
{
const std::string msg(read_buffer_, bytes);
static const char* login("login ");
static const char* ping("ping");
static const char* ask_clients("ask_clients");
if (msg.compare(0, _countof(login) - 1, login) == 0)
{
on_login(msg);
}
else if (msg.compare(0, _countof(ping) - 1, ping) == 0)
{
on_ping();
}
else if (msg.compare(0, _countof(ask_clients) - 1, ask_clients) == 0)
{
on_clients();
}
}
}
хотя конечно я немножко лукавлю, ибо написал бы с использованием memcmp что бы не создавать строку просто так:
static const char* login = "login ";
static const size_t login_size = _countof(login) - 1;
if (bytes > login_size && memcmp(read_buffer_, login, login_size) == 0)
...
else if (bytes == ping_size && memcmp(read_buffer_, ping, ping_size) == 0)
, и гарантированно вынес бы проверки в две инлайн функции, после чего добавил бы пару макросов ]:-> для избежания ошибок при использовании, и для компактности при написании. Собственно и on_login я бы переписал, что бы там строки не было. Зачем всё это? — для высоконагруженных приложений, которые требуют быстрого, надёжного и легко читающегося кода. Но всё же пусть мой код и быстрее, но для данного примера он избыточен, и лишь запутает читателя.
Пусть код со скобками для меня привычнее, но это нисколько не мешает воспринять условия в исходном примере кода с однострочными ифами — так очень многие пишут.
С void on_clients() скорее согласен, отступ там желателен, но почему бы не сообщить о таком допущении в личку?.. До кучи я бы, к примеру, использовал там сокращённую запись из C++11: for(const auto &b: clients), однако даже этот факт не мешает нормальному восприятию кода, к тому же это перевод, и судя по другим участкам кода — в оригинале код C++03.
c read_answer() проблем не наблюдаю, перенос длинных строк с параметрами — общепринятая практика, пусть там и не хватает отступа, и возможно этот перенос вообще не нужен, но это не мешает, и это ещё один недочёт сродни опечатки, о котором стоит сообщить в личку. Можно было даже в личку отправить предложение об использовании Astyle, но смысла обсуждать сие нет совсем никакого.
Ситуация с
это ещё один привет из C++03.typedef std::vector<client_ptr> array;
Кстати говоря, члены класса talk_to_client:
char read_buffer_[max_msg]; char write_buffer_[max_msg];
должны быть объявлены вот так:
boost::array<char, max_msg> read_buffer_; boost::array<char, max_msg> write_buffer_;
У меня к Вам претензия: на дворе 2013 год, а Вы почему то предлагаете boost::array а не std::array на замену! :) Ладно шучу, просто это действительно не то из-за чего могут быть проблемы с восприятием примера кода! Это пример использования, и никто не заставляет данный код копипастить и сразу же использовать в промышленном применении, это просто пример :) К слову у Александреску, в примерах, вообще местами адский-ад.
Ну и все остальное в том же духе. Конечно кому-то кажется, что человек может писать так, как ему хочется. Использовать макросы и goto, привидение типов в стиле C, free и delete вместо RAII… Надо проработать программистом не один год и в разных командах, чтобы осознать важность этих правил.
Пожалуй соглашусь только с привидением типов в стиле C при использовании в C++, а вот всё остальное: макросы, goto, и сырые указатели использовать можно если это действительно необходимо. К слову C++ из-за отсутствия make_unique даже в C++11 не полностью гарантирует безопасность использования умных указателей, а С++03 толком вообще этих возможностей не имеет (умолчим тут про auto_ptr, с которым были проблемы, о которых надо было знать, и неоднозначность с которой вообще ничего поделать было нельзя, и который ныне, к счастью — deprecated). Безусловно в Boost умные указатели появились раньше С++11, но факт остаётся фактом.
p.s: руководствуясь написанным у Вас в пункте 3 вообще не понимаю зачем было писать что либо в данном топике, если данная тема Вам не интересна.
Вообще то WinAPI, как и огромное количество другого системного кода, это C, а не C++, а стало быть наличие там данных макросов — нормальная ситуация.
Вот в том то и дело, что там код на C, поэтому макросы, хоть и вызывают неудобства, но без них не обойтись. А мы говорим о C++, и о коде, который макросов не требует вообще.
Пусть код со скобками для меня привычнее, но это нисколько не мешает воспринять условия в исходном примере кода с однострочными ифами — так очень многие пишут.
Я конечно опять нарываюсь на минусы, но все же нормальный код не должен так выглядеть. В книгах так часто пишут чтобы сократить объем. Но там и примечания ставят соответствующие. Но в статье на сайте нет смысла экономить строки.
С void on_clients() скорее согласен, отступ там желателен, но почему бы не сообщить о таком допущении в личку?
Следуя логике большинства — код компилируется? Да, значит он правильный. Так зачем что-то сообщать? Мои претензии к коду — исключительно мое личное дело, я никому не навязываю свой стиль. Тем более, что стилей очень много. Мне вот венгерская нотация не нравится, но не сообщать же теперь об этом в личку каждому автору, посмевшему ее использовать? :-)
Ситуация с
typedef std::vector<client_ptr> array;
это ещё один привет из C++03.
Я специально показал следующий пример с array из boost. Asio появился в boost начиная с версии 1.35, открываю первый попавшийся пример и вижу вот такие строки:
#include <boost/array.hpp>
...
boost::array<char, 1024> data_;
Пруф: www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/example/allocation/server.cpp
Сомнительно, что автор пишет о boost asio и не знает о контейнере array. А если знает, то зачем вводить потенциально конфликтный тип данных?
Пожалуй соглашусь только с привидением типов в стиле C при использовании в C++, а вот всё остальное: макросы, goto, и сырые указатели использовать можно если это действительно необходимо.
Я и не говорил, что это нельзя использовать. Разумеется можно, но только там, где это действительно необходимо. Но ведь не сокращать каждый вызов макросом.
p.s: руководствуясь написанным у Вас в пункте 3 вообще не понимаю зачем было писать что либо в данном топике, если данная тема Вам не интересна.
Тема как раз интересна, иначе бы я не стал открывать этот топик и тем более пролистывать до комментариев.
Ну и предлагаю завершить эту дискуссию :-)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
«Boost.Asio C++ Network Programming». Глава 4: Клиент и Сервер