![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
[ Предупреждение: для непрограммистов неинтересно ]
Пусть у нас есть два класса - базовый Base и отнаследованный от него Derived. В Derived есть конструктор, похожий на конструктор копии с параметром типа Base.
Допустим, в программе это используется вот так:
И оно не работает.
Тщательное расследование показало эпическое западло...
В какой-то момент я внес часть кода в функцию:
И вдруг оно начало работать! Счастливый, я все так и оставил, предполагая разобраться как-нибудь потом. Сегодня это как-нибудь наступило.
Западло состоит в том, что в строке Derived d2(d1) не всегда вызывается второй конструктор и не будут выполняться "важные манипуляции". Вместо этого будет вызван "невидимый" автоматически сгенерированный конструктор-копии, и все поля будут тупо скопированы из d1 в d2.
Это происходит в том случае, если d1 имеет тип Derived. Если Base - то все хорошо. Вот почему та функция исправляла проблему. Так тоже будет работать:
Лечится это легко:
Но ведь и вляпаться тоже легко...
Пусть у нас есть два класса - базовый Base и отнаследованный от него Derived. В Derived есть конструктор, похожий на конструктор копии с параметром типа Base.
class Base { ... }; class Derived: public Base { public: Derived() {...} Derived(const Base &b) { /* важные манипуляции */ } };
Допустим, в программе это используется вот так:
Derived d1; Derived d2(d1);
И оно не работает.
Тщательное расследование показало эпическое западло...
В какой-то момент я внес часть кода в функцию:
void foo(Base &d1) { Derived d2(d1); ... } ... Derived d1; foo(d1);
И вдруг оно начало работать! Счастливый, я все так и оставил, предполагая разобраться как-нибудь потом. Сегодня это как-нибудь наступило.
Западло состоит в том, что в строке Derived d2(d1) не всегда вызывается второй конструктор и не будут выполняться "важные манипуляции". Вместо этого будет вызван "невидимый" автоматически сгенерированный конструктор-копии, и все поля будут тупо скопированы из d1 в d2.
Это происходит в том случае, если d1 имеет тип Derived. Если Base - то все хорошо. Вот почему та функция исправляла проблему. Так тоже будет работать:
Derived d2((Base&)d1);
Лечится это легко:
class Base { ... }; class Derived: public Base { public: Derived() {...} Derived(const Base &b) { /* важные манипуляции */ } Derived(const Derived &b) { /* важные манипуляции */ } };
Но ведь и вляпаться тоже легко...
no subject
Date: 2009-07-15 12:46 pm (UTC)Вот это как раз - "достойный" пример бездумного следования религиозной заповеди: "типизация - это хорошо" - всегда, независимо ни от чего. А теперь просвети меня, как и почему в данном конкретном случае типизация - это хорошо? Не в параметрах функций, а вот конкретно для констант. Слабо обосновать? Ну и для закрепления пройденного, подумай: что, у констант типов нет? Суффиксы L, U, F не для эстетов? :)
----------------
Сарказм неуместен. Ты не с ламером разговариваешь.
Итак, что напишет программа в такой реализации:
#include
const CH = '0';
int main(int argc, char* argv[])
{
std::cout << CH << std::endl;
return 0;
}
?
Без компиляции и запуска ответишь?
И что измениться при проведении замены на
const char CH = '0';
?
------------------------
[ за что им в данной шкале +10 ]
А вот это - уже религиозно-идеологическое воззрение. Для холиваров - прекрасно, для серьезного рассмотрения - негодно. Может, сразу +1000^1000? :) Ну чиста патаму шта эта крута!? :)
------------------------
Потому что решение проблемы потенцильной ошибки, на вылавливание которой можно потрать куеву хучу времени намного важнее (в данном случае на порядок) четырех-пяти символов.
Ход мысли ответа понятен?
------------------------
[ Потому что define не может быть членом класса. ]
Следи за руками:
#define ClassName__MAX_CHANNEL = 2;
:)
------------------------
Это уже грязный хак. Манипуляторы отрывать надо за такое.
no subject
Date: 2009-07-15 12:48 pm (UTC)no subject
Date: 2009-07-15 01:10 pm (UTC)гы гы гы - сраказм ему мой не понравился видите ли :) за собой то не замечаем, да? :)
[ Без компиляции и запуска ответишь? ]
Отвечу - либо компилятор напишет ошибку (если компилятор не допускает тип int по-умолчанию), либо 48 (ASCII-код символа нуля). А зачем ты такую муру написал? Это не техника #define и некорректная техника для const. Ты пытаешься мне показать, что мура - это мура? Так я соглашусь: мура. :)
[ И что измениться при проведении замены на '0' ]
'0' будет.
А теперь берем технику с #define:
#define CH '0'
Константа типа char, напечатает, опять же, '0'. Ну и где оно - счастье? :)
[ Потому что решение проблемы потенцильной ошибки, на вылавливание которой можно потрать куеву хучу времени намного важнее (в данном случае на порядок) четырех-пяти символов. ]
Это ты какой случай рассматриваешь? Константа-член-класса? Тогда не четырех-пяти, а придется переключаться на файл-исходник и там эту переменную еще и определять. А, если файла-исходника нет, то создавать его, вносить в CVS, в проект. У тебя получается, что куча времени на отлов потенциальной ошибки существует, а куча времени на набивание - не существует? И повторю еще раз: в любом случае enum лучше. В упомянутом же "мучебнике" для ламеров прием с enum рассматривается как нечто устаревшее и отжившее. Гы.
[ Это уже грязный хак. Манипуляторы отрывать надо за такое. ]
Это уже опять пошла религия. Думаешь, сказал слово "хак" и на белого коня влез? :) Это не хак, а классическое определение константы со специальным префиксом, который играет ту же роль, что и namespace. Именно так и надо писать глобальные #define-ы, тогда и не придется тратить "куеву хучу времени" на отлов ошибок из-за повторения констант. Потому, что никаких повторений просто не будет.
no subject
Date: 2009-07-16 08:00 pm (UTC)Сейчас не удалось воспроизвести ситуацию с ошибкой из-за отсутствия типизациии у макросов, с которой бодался я пару лет назад. В любом случае она снимается конструкцией вида
#define CH ((char)'0')
но об этом мало кто помнит.
>И повторю еще раз: в любом случае enum лучше.
Я не говорил о том, что enum хуже. Использование enum для определения констант рекомендуется ведущими
собаководамиспециалистами наравне с const, но никак не с макросами.>У тебя получается, что куча времени на отлов потенциальной ошибки существует, а куча времени на набивание - не существует?
Если есть возможность отловить/пресечь потенциальную ошибку компилятором, то эту возможность нужно использовать. Это одно из фундаментальных правил. Если так нравится натыкаться на грабли - флаг в руки.
У меня константы в классе описываются крайне редко. Потому что константа на то и константа, что она одинакова для всех instance и может быть оформлена в качестве константы пространства имен или геттера.
>Это уже опять пошла религия. Думаешь, сказал слово "хак" и на белого коня влез?
Покажи
справкустандарт языка, где такой префикс обязателен для всех компиляторов. Жду.Слово "хак" означает вполне конкретное действие, которое направлено на использование особенностей текущей системы или поведения программы для достижения локальной цели, но при этом не соответствует нормам и ведет к большой жопе в долгосрочной перспективе.
Если программист для ожидания ввода пишет
std:cin >> "";
то это грязный хак.
Если у него программа при int x[100] не работает по каким-то непонятным причинам, а при исправлении на int x[1000] все вдруг работает, и при этом нет никакого анализа причин - то это также грязный хак.
В нормальных фирмах за грязные хаки увольняют без разговоров. Потому что никому не нужны 10% программистов делающих 90% ошибок в проектах.
Я понятно объяснил, что такое "хак"?
>Именно так и надо писать глобальные #define-ы, тогда и не придется тратить "куеву хучу времени" на отлов ошибок из-за повторения констант.
Способов написания "уникальных" define'ов много, и я их тут не затрагиваю.
no subject
Date: 2009-07-16 10:13 pm (UTC)[ Сейчас не удалось воспроизвести ситуацию с ошибкой из-за отсутствия типизациии у макросов ]
При желании все можно придумать - просто это редкие ситуации. При желании можно и
const int string= "";
написать, а потом удивляться, что за фигня получается, когда путается с std::string.
[ Использование enum для определения констант рекомендуется ведущими собаководами специалистами наравне с const, но никак не с макросами. ]
Ну вот потому мне тот собаковод и не понравился, что уперся в const :)
[ Если есть возможность отловить/пресечь потенциальную ошибку компилятором, то эту возможность нужно использовать ]
Так и с #define-ом есть возможность пресечь - используй достаточно уникальные имена, а не "CH" и не "WIDTH1". :)
[ Покажи справку стандарт языка, где такой префикс обязателен для всех компиляторов. ]
При чем тут компиляторы? Это просто традиция - облегчать себе жизнь префиксами. Скажем, в виндах пишем не TIMER, а WM_TIMER, где префикс WM_ - есть аббревиатура от Window Message. Та или иная схема префиксов должна быть.
[ Слово "хак" означает вполне конкретное действие, которое направлено на использование особенностей текущей системы или поведения программы для достижения локальной цели, но при этом не соответствует нормам и ведет к большой жопе в долгосрочной перспективе. ]
Ну так слезай с белой лошадки, Всякие WM_ или Class__ под это определение не подходят и, следовательно, хаками не являются. :)
no subject
Date: 2009-07-16 10:26 pm (UTC)Я кажется уже написал, что попадал в такую 'редкую' ситуацию.
>Ну вот потому мне тот собаковод и не понравился, что уперся в const :)
Всякому овобщу свое время.
>Так и с #define-ом есть возможность пресечь - используй достаточно уникальные имена, а не "CH" и не "WIDTH1". :)
См. примеры 3.3, 3.4. Ошибки компилятором не выявлены.
Опять же, уникальность ещё можно обеспечить какими либо средствами, но вот контроль компилятора - нет.
>При чем тут компиляторы? Это просто традиция - облегчать себе жизнь префиксами. Скажем, в виндах пишем не TIMER, а WM_TIMER, где префикс WM_ - есть аббревиатура от Window Message. Та или иная схема префиксов должна быть.
Это просто префикс, который не делает так, что константа попадает в пространство имен?
namespace используется не только для уникальности. например это удобная вещь при рефакторинге. Если есть класс A::B::C, и его нужно перенести в E::F::D, то копируется он сам как таковой без каких либо правок, просто включается в другое пространство имен, при этом другой код может его использовать точно также, как использовал ранее. И не нужно бегать по всему проекту и по всем пользователям, использующим код для произведения правок.
>Ну так слезай с белой лошадки, Всякие WM_ или Class__ под это определение не подходят и, следовательно, хаками не являются. :)
На вопрос ответь сначала (;
no subject
Date: 2009-07-16 10:42 pm (UTC)Ну и на здоровье :))))
[ Всякому овобщу свое время. ]
Нет, там явно говорится, что enum - устаревшая, экзотическая техника. Практически "хак по Бсивко" ;))))
[ См. примеры 3.3, 3.4. Ошибки компилятором не выявлены. ]
3.4 - вообще не константа, не собираюсь защищать define-ы в качестве альтернативы inline-функций. 3.3 - #define с операциями и без внешних скобок пишут только индийские программисты. :)
[ Это просто префикс, который не делает так, что константа попадает в пространство имен? ]
Ну он просто дает аналогичный эффект - гарантирует, что не будет одноименных констант. Хотя компилятор обычно и так ругается на повторный #define, но так лучше (думаю, понятно, почему).
[ На вопрос ответь сначала (; ]
На который??
no subject
Date: 2009-07-17 02:07 pm (UTC)Ну и на здоровье :))))
---------
Это говорит о том, что ситуация не такая уж и редкая.
---------
Ну он просто дает аналогичный эффект - гарантирует, что не будет одноименных констант. Хотя компилятор обычно и так ругается на повторный #define, но так лучше (думаю, понятно, почему).
[ На вопрос ответь сначала (; ]
На который??
---------
Уже ответил.
И я тебе уже тоже ответил. Namespace это не только
30 кг легко усваиваемого мясаспособ создания уникальных имен, но и например удобный элемент при рефакторинге.---------
[ Всякому овобщу свое время. ]
Нет, там явно говорится, что enum - устаревшая, экзотическая техника. Практически "хак по Бсивко" ;))))
---------
>Т.е. это описывается как "трюк", который надо знать для каких-то изъебских случаев - в то время, как это не трюк, а метод, который лучше того метода, который перед этим рекламируется.
Enum не предназначен для описания констант. Поэтому это именно трюк, но не метод в рамках языка.
Т.о. Майерс его не рекомендует, Страуструп и Саттер рекомендуют. Программистам же остается включать мозги и делать выбор. У тебя с этим проблемы нервного плана? Раньше за тобой такого не замечал.
Но то, что хотел сказать, не в этом. А в том, что по твоим словам (2009-07-14 05:42 pm)
Использование const вместо #define соответсвует чисто идеологическому переходу с парадигмы C на C++. Соответственно везде, где пропагандируется идеология C++, пропагандирутся и const вместо #define. Проблема в том, что это чисто идеологическая, пропагандистская фишка. Ее назначение - разного рода холивары и пособия типа "C++ за два дня для ламеров".
Для ламера надо вызубрить некое правило, как можно более простое и бездумное. Например, "препроцессор - плохо, const - хорошо". Без всяких оговорок типа, когда, где и при каких условиях. Если же подходить с практических позиций, то лучше далеко не всегда и не везде. Но это надо чуть-чуть мозги включать и вникать.
-- конец цитаты --
в книге - набор тупых правил для чайников. А на самом деле в книге подробно расписывается, что как и почему. В частности, для enum (там же):
"Этот прием стоит знать по нескольким причинам. Во-первых, поведение "трюка с перечислением" в некоторых отношениях более похоже на #define, чем на константу, а иногда это как раз то, что нужно. Если вы хотите запретить получать адрес или ссылку на какую-нибудь целую константу, то применение enum - хороший способ наложить такое ограничение."
(есс-но define-аналогии в сторону, важны сами факты различных способов)
т.е. конкретно расписаны плюсы и минусы (и это только часть, в книге ещё есть), и при этом рекомендуется использовать константу, т.к. это дает больше возможностей программисту и оптимизации компилятору.
Ламеры будут использовать константу - обойдут потенциальные грабли и получат большую функциональность. Те, кто понимают что делают, будут использовать enum там, где это оправдано. Так что все корректно и к месту.
>И нехуй мне тут пиздить, что я хуем по заголовкам читаю.
Так что пиздить мне тут хуй (;
Все ещё настаиваешь на обвинении Майерса в пособии необоснованных правил для чайников?
no subject
Date: 2009-07-16 08:00 pm (UTC)Что ты не затронул ещё кучу особенностей макросов. И почему-то для тебя главное кол-во букв в коде, нежели другие показатели качества кода и его сопровождения.
1. Макросы могут быть раскрыты неожиданно, раскрываясь в непредсказуемые конструкции. С этим хорошо знакомы программисты, которые хоть раз использовали 2-3 уровня макросов.
Типичный простой пример:
#define WIDTH1 20
#define WIDTH2 25
#define TOTAL_WIDTH WIDTH1 + WIDTH2
#define HEIGHT 10
#define PER TOTAL_WIDTH*2 + HEIGHT*2
#define AREA TOTAL_WIDTH * HEIGHT
Второй пример:
#define ABORT(msg)\
std::cerr << msg << std::endl; exit(1);
Они конечно лечаться, но приличным трудом программистов, в основном методом расставляния скобок различного типа во все дыры без каких либо внятных средств отладки.
2. Макросы трудно отлаживать. Потому что синтаксический анализатор и прочие средства добираются только после того, как макросы прошлись табуном по коду, в результате мест ошибки будет совсем не там, где на неё показывает компилятор.
Пример (действующий для большинства компиляторов):
#define HUNDRED (10 ** 2)
int main() {
for(int i = 0; i < 10; ++i) {
std::cout << i << ":" << (HUNDRED*i) << "\n";
}
return 0;
}
Ошибка в одной строке, компилятор указывает на другую, при чем появляется она не на всех компиляторах.
3. Особенности макросов нужно знать и постоянно за ними следить и держать в голове. Потому что потом придется исправлять все долго и мучительно. Скобки уже были показаны ранее. Немного остальных особенностей:
3.1
#define INT_PTR int *
int main() {
INT_PTR one, two;
one = two;
return 0;
}
3.2
#define DOUBLE (value) ((value) + (value))
int main() {
for(int i = 0; i < 10; ++i) {
std::cout << DOUBLE(i) << std::endl;
}
return 0;
}
3.3
#define TOP 3.0; // Высота окна.
#define BORDER 0.7; // Ширина кромки.
#define REAL TOP- BORDER
int main() {
float real = REAL;
std::cout << real << std::endl;
}
3.4
#define SQR(x) ((x)*(x))
int main() {
int i = 0;
while( i < 10 ) {
std::cout << i << ":" << SQR(++i) << std::endl;
}
return 0;
}
3.5
Сколько аргументов у такого
#define MACR( one
Что ты не затронул ещё кучу особенностей макросов. И почему-то для тебя главное кол-во букв в коде, нежели другие показатели качества кода и его сопровождения.
1. Макросы могут быть раскрыты неожиданно, раскрываясь в непредсказуемые конструкции. С этим хорошо знакомы программисты, которые хоть раз использовали 2-3 уровня макросов.
Типичный простой пример:
#define WIDTH1 20
#define WIDTH2 25
#define TOTAL_WIDTH WIDTH1 + WIDTH2
#define HEIGHT 10
#define PER TOTAL_WIDTH*2 + HEIGHT*2
#define AREA TOTAL_WIDTH * HEIGHT
Второй пример:
#define ABORT(msg)\
std::cerr << msg << std::endl; exit(1);
Они конечно лечаться, но приличным трудом программистов, в основном методом расставляния скобок различного типа во все дыры без каких либо внятных средств отладки.
2. Макросы трудно отлаживать. Потому что синтаксический анализатор и прочие средства добираются только после того, как макросы прошлись табуном по коду, в результате мест ошибки будет совсем не там, где на неё показывает компилятор.
Пример (действующий для большинства компиляторов):
#define HUNDRED (10 ** 2)
int main() {
for(int i = 0; i < 10; ++i) {
std::cout << i << ":" << (HUNDRED*i) << "\n";
}
return 0;
}
Ошибка в одной строке, компилятор указывает на другую, при чем появляется она не на всех компиляторах.
3. Особенности макросов нужно знать и постоянно за ними следить и держать в голове. Потому что потом придется исправлять все долго и мучительно. Скобки уже были показаны ранее. Немного остальных особенностей:
3.1
#define INT_PTR int *
int main() {
INT_PTR one, two;
one = two;
return 0;
}
3.2
#define DOUBLE (value) ((value) + (value))
int main() {
for(int i = 0; i < 10; ++i) {
std::cout << DOUBLE(i) << std::endl;
}
return 0;
}
3.3
#define TOP 3.0; // Высота окна.
#define BORDER 0.7; // Ширина кромки.
#define REAL TOP- BORDER
int main() {
float real = REAL;
std::cout << real << std::endl;
}
3.4
#define SQR(x) ((x)*(x))
int main() {
int i = 0;
while( i < 10 ) {
std::cout << i << ":" << SQR(++i) << std::endl;
}
return 0;
}
3.5
Сколько аргументов у такого
#define MACR( one<int, float> )
макроса?
И самое страшное не то, что могут быть ошибки. А то, что если ошибка есть, а программа скомпилируется во что-то квази-работающее.
---------------------------
При всем этом макросы являются единственным решением для таких задач, как защита от повторной компиляции, условная компиляция блоков кода.
Макрос это инструмент. И как показывает практика, он хорошо работает только в исключительных случаях. Рекомендуется использовать const и enum для определения явных констант, inline для исключения накладных расходов вызова функций, template для определения множества однотипных функций, namespace для избежания коллизий по именам. Все. Для макросов места практически не остается.
А ты про свою религию брось. Если там общаешься постоянно с сумашедшим домом, то это не говорит о том, что все такие.
no subject
Date: 2009-07-16 10:22 pm (UTC)А потому, что я не люблю бездумные "глобальные" правила для ламеров. В тех ситуациях, когда макросы хуже, зачем же я их буду защищать? :) Скажем, для мелких функций inline или template+inline лучше, чем #define со скобками. Там, где макросы хуже, глупо их хвалить. А там, где макросы не хуже, нет смысла их ругать. Глобальные обобщения - это для чайников :)
no subject
Date: 2009-07-16 10:54 pm (UTC)Не пленился - открыл и просмотрел Майерса. Он у меня есть в домашней библиотеке, но читал его пару лет назад. Да и библиотека далеко сейчас находитсяю
Так вот. Похоже что ты прочитал только названия глав. Вершки схватил, принял их буквально как руководство для чайников.
Если же читать нормально, то там аккуратно все расписывается что почему и когда используется. Включая enum.
Так что незачет тебе. За поверхностное ознакомление. И необоснованный наезд.
>Да что вы. Это развлекает.
Хорошо смеется тот, кто смеется без последствий.
no subject
Date: 2009-07-16 11:36 pm (UTC)Накося, выкуси.
Date: 2009-07-16 11:47 pm (UTC)Т.е. это описывается как "трюк", который надо знать для каких-то изъебских случаев - в то время, как это не трюк, а метод, который лучше того метода, который перед этим рекламируется.
И нехуй мне тут пиздить, что я хуем по заголовкам читаю.
Re: Накося, выкуси.
Date: 2009-07-17 02:08 pm (UTC)Ну и на здоровье :))))
---------
Это говорит о том, что ситуация не такая уж и редкая.
---------
Ну он просто дает аналогичный эффект - гарантирует, что не будет одноименных констант. Хотя компилятор обычно и так ругается на повторный #define, но так лучше (думаю, понятно, почему).
[ На вопрос ответь сначала (; ]
На который??
---------
Уже ответил.
И я тебе уже тоже ответил. Namespace это не только
30 кг легко усваиваемого мясаспособ создания уникальных имен, но и например удобный элемент при рефакторинге.---------
[ Всякому овобщу свое время. ]
Нет, там явно говорится, что enum - устаревшая, экзотическая техника. Практически "хак по Бсивко" ;))))
---------
>Т.е. это описывается как "трюк", который надо знать для каких-то изъебских случаев - в то время, как это не трюк, а метод, который лучше того метода, который перед этим рекламируется.
Enum не предназначен для описания констант. Поэтому это именно трюк, но не метод в рамках языка.
Т.о. Майерс его не рекомендует, Страуструп и Саттер рекомендуют. Программистам же остается включать мозги и делать выбор. У тебя с этим проблемы нервного плана? Раньше за тобой такого не замечал.
Но то, что хотел сказать, не в этом. А в том, что по твоим словам (2009-07-14 05:42 pm)
Использование const вместо #define соответсвует чисто идеологическому переходу с парадигмы C на C++. Соответственно везде, где пропагандируется идеология C++, пропагандирутся и const вместо #define. Проблема в том, что это чисто идеологическая, пропагандистская фишка. Ее назначение - разного рода холивары и пособия типа "C++ за два дня для ламеров".
Для ламера надо вызубрить некое правило, как можно более простое и бездумное. Например, "препроцессор - плохо, const - хорошо". Без всяких оговорок типа, когда, где и при каких условиях. Если же подходить с практических позиций, то лучше далеко не всегда и не везде. Но это надо чуть-чуть мозги включать и вникать.
-- конец цитаты --
в книге - набор тупых правил для чайников. А на самом деле в книге подробно расписывается, что как и почему. В частности, для enum (там же):
"Этот прием стоит знать по нескольким причинам. Во-первых, поведение "трюка с перечислением" в некоторых отношениях более похоже на #define, чем на константу, а иногда это как раз то, что нужно. Если вы хотите запретить получать адрес или ссылку на какую-нибудь целую константу, то применение enum - хороший способ наложить такое ограничение."
(есс-но define-аналогии в сторону, важны сами факты различных способов)
т.е. конкретно расписаны плюсы и минусы (и это только часть, в книге ещё есть), и при этом рекомендуется использовать константу, т.к. это дает больше возможностей программисту и оптимизации компилятору.
Ламеры будут использовать константу - обойдут потенциальные грабли и получат большую функциональность. Те, кто понимают что делают, будут использовать enum там, где это оправдано. Так что все корректно и к месту.
>И нехуй мне тут пиздить, что я хуем по заголовкам читаю.
Так что пиздить мне тут хуй (;
Все ещё настаиваешь на обвинении Майерса в пособии необоснованных правил для чайников?
Re: Накося, выкуси.
Date: 2009-07-17 03:26 pm (UTC)О, да, если с тобой случилось, то это регулярно и у многих :) Правда ты толком даже не помнишь, что там было, только тГавма осталась. :))
[ Namespace это не только 30 кг легко усваиваемого мяса способ создания уникальных имен, но и например удобный элемент при рефакторинге ]
Чего и зачем там рефакторить с namespace??
[ Т.о. Майерс его не рекомендует, Страуструп и Саттер рекомендуют. ]
Так что минус очко Майерсу.
[ в книге - набор тупых правил для чайников ]
Не везде, но при чтении только одной произвольно взятой главы такое мне встретилось трижды. Отсюда я сделал предположение об остальном тексте.
[ т.е. конкретно расписаны плюсы и минусы ]
Ага, - причем, неправильно расписаны. Но это мелочь :)) Зато идеологичненько.
Re: Накося, выкуси.
Date: 2009-07-17 05:24 pm (UTC)То это как минимум случилось. Или типа если один раз наступил на грабли, то это случайность, да?
Я помню толком, что преобразование типа не проводилось. При чем грабли тянулись ещё с особенностей С, для которого char это целое число.
>Чего и зачем там рефакторить с namespace??
A::B::C поищи поиском в комментах.
Кроме того, у namespace есть свои плюсы - как раз таки уменьшение кол-ва букв при включении кода в namespace (не нужно перед каждым идентификатором писать 'уникальное') и локальный using (за глобальный давать по голове (; ) для уменьшения числа букв.
>Так что минус очко Майерсу.
Цитата из резюме конца главы:
"Что следует помнить: * Для простых констант директиве #define следует предпочесть константные объекты и перечисления enum"
Где тут полный отказ от enum?
Ты все ещё играешь в очко? (; Да ещё и по авторитетам?
>Не везде, но при чтении только одной произвольно взятой главы такое мне встретилось трижды. Отсюда я сделал предположение об остальном тексте.
Мне же при чтении этой же главы встретилось 11 практических обоснований, на которые обратил внимание (список могу приложить).
Я нашел конкретные обоснования, ты нашел абстрактные правила. Так дело все таки в консерватории?
>Ага, - причем, неправильно расписаны.
Что именно в цитате неправильно расписано?
>Но это мелочь :)) Зато идеологичненько.
Тебя политработники в последнее время прессуют? Откуда это г.но взялось?
У С++ есть свои
плюсыпреимущества, которые нужно по возможности и необходимости использовать. Не нравится на что он заточен - иди в другой язык. Если тебе пофигу на строгую типизацию, нравится чтобы было меньше букв - то руби/питон/перл/.. в зубы и вперед. Там все тебе к чему-нить работающему по типам приведут и не надо будет писать много букв для констант, методов, классов и пр..no subject
Date: 2009-07-17 07:06 pm (UTC)Понимаешь, лучше соблюдать некий разумный баланс осторожности, чтобы осторожность не правратилась в паранойю, но и не выродилась в безалаберность. Если какая-то неприятность может случиться, это не значит, что надо тратить непомерно много ресурсов на то, чтобы ее предотвратить. Надо смотреть, что это за неприятность, чем она грозит, что можно сделать для предотвращения и сколько это будет стоить. Можно угробить столько времени на предотвращение неприятностей, что окажется выгоднее просто позволить этим неприятностям произойти, а потом исправить их. По времени выгоднее.
В данном случае ты уже не помнишь, что за проблема была, а делаешь какие-то кардинальные выводы. А, может, там фигня какая-нибудь была?
[ A::B::C поищи поиском в комментах. ]
Я видел, но не понял, какого рода рефакторинг ты имел в виду.
[ Где тут полный отказ от enum? ]
Зачем полный? Просто неправильно расставлены приоритеты. Наихудший метод преподносится как основной. Наилучший метод преподжносится как "трюк". Средний метод преподносится как наихудший.
Причем, наихудший метод оказался наилучшим почему? А потому, что афтар последовательно придерживается определенной идеологизированной схемы. Пропагандонствует.
[ Не нравится на что он заточен - иди в другой язык. ]
Это была попытка послать? Нежнее, сударь, нежнее. Сами пройдите на хуй, посмотрите, как там дела, а потом уж рекомендуйте.
[ Если тебе пофигу на строгую типизацию ]
Что за ебучая хуйня мне тут приписана? Где я говорил, что мне пофигу на строгую типизацию? Из какой пизды на лыжах приехало сие обвинение?
#define и const для чисел в смысле типизации приблизительно одинаковы. Можно типизировать константы в #define - всякие там 1UL или 0.5f дадут соответственно unsigned long и float. В const тип приходится писать в самом начале. В #define можно ничего не писать - будет int или double. В const можно бездумно написать int, эффект будет тот же. Если выйдешь за границы допустимых значений, компилятор тебя обругает - в обоих случаях. И в обоих случаях все эти твои типы со свистом и незаметно для тебя преобразуются в другие типы автоматом. Даже если ты объявишь const unsigned HUJ = 30; или #define HUJ 30U - это тебе совершенно не помешает тебе послать сей huj в параметр типа int или double или даже в short, если компилятор достаточно умный, чтобы не писать глупых предупреждений. Так при чем тут строгая или нестрогая типизация? Откуда это г.но взялось?
no subject
Date: 2009-07-17 07:57 pm (UTC)Хорошо если эта неприятность проявится на этапе отладки. Тут ещё можно посчитать на пальцах. А вот если как это у меня пару раз было - звонок в 5-6 утра от службы поддержки со срочным вызовом, потому что система, работающая в режиме 24х7 дала сбой.
И я не говорю уже о системах, связанных со здоровьем и жизнью людей.
Конечно, если верстать какие-нить веб-сайты, в которых в худшем случае access denied и восстановление из back-up'a, то тогда да, можно и повыкаблучиваться. А в серьезных системах это недопустимо. Выявлена ситуация - исправлена - выработано правило, чтобы её избежать - правило применено для всех ответственных лиц. Все.
>В данном случае ты уже не помнишь, что за проблема была, а делаешь какие-то кардинальные выводы. А, может, там фигня какая-нибудь была?
Принципиально проблема в том, что тип отличался от ожидаемого, а результате конвертация привела к другому значению. Ошибка отлавливалась только при рантаймовом запуске, что само по себе критично.
В данный момент для меня такой х-ки достаточно. Ты же делай свои выводы.
>Я видел, но не понял, какого рода рефакторинг ты имел в виду.
namespace project {
namespace sub_project1 {
class name_t {
};
}
namespace sub_project2 {
}
}
Перенос из sub_project1 в sub_project2 - "копи-паст".
Для хитровыебнутых нотаций для идентификаторов:
class project_sub_project_1_name_1 {
...
};
Перенос - дополнительный rename всего, что есть в классе.
Это
>Кроме того, у namespace есть свои плюсы - как раз таки уменьшение кол-ва букв при включении кода в namespace (не нужно перед каждым идентификатором писать 'уникальное') и локальный using (за глобальный давать по голове (; ) для уменьшения числа букв.
объяснять надо?
>Просто неправильно расставлены приоритеты. Наихудший метод преподносится как основной. Наилучший метод преподжносится как "трюк". Средний метод преподносится как наихудший.
Неправильно с твоей точки зрения. Автор имеет право на свою точку зрения?
>Причем, наихудший метод оказался наилучшим почему? А потому, что афтар последовательно придерживается определенной идеологизированной схемы. Пропагандонствует.
Автор внятно объяснил преимущества своего подхода. Ему важнее скорость работы, меньший расход памяти, более расширенная функциональность. Он все это получает за счет одной дополнительной строчки в файле реализации.
Ты же пропагандируешь идеологию
лени и минимальных движенийболее компактного способа создания кода. Тебе все равно что скрыто под капотом компилятора (что видно из твоего первого очкового анализа), главное чтобы букф было поменьше.>Это была попытка послать? Нежнее, сударь, нежнее. Сами пройдите на хуй, посмотрите, как там дела, а потом уж рекомендуйте.
Это была попытка сказать, что любой язык имеет свои плюсы и минусы, и его использование оправдано для определенных и конкретных задач. Если у тебя задача формализуется в минимизации букф исходного кода и тебе все равно, как это выполняется в бою и с каким качеством - то пройди по адресу. Хватит чистить зубы молотком и забивать леворезьбовые гвозди зубной щеткой.
>Что за ебучая хуйня мне тут приписана? Где я говорил, что мне пофигу на строгую типизацию? Из какой пизды на лыжах приехало сие обвинение?
Ты слово "если" видишь? Или для тебя "если" - это утверждение?
>#define и const для чисел в смысле типизации приблизительно одинаковы. Можно типизировать константы в #define - всякие там 1UL или 0.5f дадут соответственно unsigned long и float.
Да, и я об этом уже говорил.
У меня вопрос главный то в этом:
Все ещё настаиваешь на обвинении Майерса в пособии необоснованных правил для чайников?
no subject
Date: 2009-07-17 08:19 pm (UTC)У меня кстати есть опыт программинга на руби и перле, в т.ч. работающих проектах, потому я там был и могу много чего рассказать. И не только - а сам использую данные инструменты при необходиомости.
Привет. (;
no subject
Date: 2009-07-17 08:48 pm (UTC)Ну допустим, ты делаешь такую систему. Время разработки в любом случае ограничено. Лучше потратить его на исключение тех неприятностей, которые потенциально более опасны, чем другие. Я призываю фокусироваться на предотвращении тех потенциальных неприятностей, которые реально опасны, а не в воображении. Если ты пишешь систему "с риском для жизни", то тем более лучше тратить время не на "рюшечки" типа писать везде const, а не enum потому, что атэц Майерс сказал, что enum - это "трюк". И если не связано с риском для жизни, все равно выкаблучиваться не надо: время - деньги.
[ Перенос из sub_project1 в sub_project2 - "копи-паст". ]
А везде заменять sub_project1::name_t на sub_project2::name_t будет батька Махно?
[ Неправильно с твоей точки зрения. Автор имеет право на свою точку зрения? ]
Право то он имеет. Но важно, как он обосновывает свою точку зрения. Приведенное обоснование мне кажется недостаточно практичным и слишком идеологичным. Хотя определенного типа пипл именно такие обоснования "хавает" с большим удовольствием.
[ Автор внятно объяснил преимущества своего подхода. Ему важнее скорость работы, меньший расход памяти, более расширенная функциональность. ]
Остапа понесло. Какая разница по скорости работы и расходу памяти между const, enum и define в конкретном случае с определением числовых констант? Ну-ка, просвети меня, как "дополнительная строчка в файле реализации" ускоряет исполнение программы?
[ Ты же пропагандируешь идеологию лени и минимальных движений более компактного способа создания кода. ]
Лень - это святое.
[ Тебе все равно что скрыто под капотом компилятора (что видно из твоего первого очкового анализа), главное чтобы букф было поменьше. ]
Опять тебя несет без пургена. Может, лучше пойдешь выпьешь валерьянки, чем сочинять про собеседника хуйню?
[ Ты слово "если" видишь? Или для тебя "если" - это утверждение? ]
Если - это наезд. Например, "если ты, Бсивко, мудак, то ты, Бсивко, мудак". Утверждение логически безупречно (тавтология из A следует A) и не содержит, формально говоря, утверждения, что Бсивко - мудак. Но я сомневаюсь, что оно тебе было бы приятно.
[ У меня вопрос главный то в этом ]
Да, конечно настаиваю. На самом деле одна конкретная фишка с константами - мелочь, которую можно списать на некоторое "эстетство" автара. Если бы она была одна. Это просто тебе захотелось очень подробно обсуждать эту мелочь. Но я сразу, взяв только одну главу и начав ее читать, наткнулся еще на пару вещей, посмотрел на общий "йазыг" и стиль - и мне не понравилось. Считаю, что книжка вредная для обучающихся. На свое мнение я тоже имею право, так как вожусь с этим языком по времени, наверное, не меньше, чем сей афтар.
no subject
Date: 2009-07-17 11:16 pm (UTC)Реально опасны это те, которые уже дали по голове? Так от без избавления от таких никто в бой систему не пустит. Не то что говорить уже о качестве и кол-ве ошибок при сопровождении. Тем более, что описанные ошибки трудновылавливаются, всякие стектрейсы, логи и проч. очень слабо помогают. Одну ошибку такого рода можно вылавливать и ждать месяцами.
Чем раньше предотвращается ошибка - тем лучше. Это также одно из фундаментальных правил.
>время - деньги
качество/время = результат ~= деньги
>А везде заменять sub_project1::name_t на sub_project2::name_t будет батька Махно?
Я не говорю о внешнем вызове, а о внутреннем использовании.
>Право то он имеет. Но важно, как он обосновывает свою точку зрения. Приведенное обоснование мне кажется недостаточно практичным и слишком идеологичным. Хотя определенного типа пипл именно такие обоснования "хавает" с большим удовольствием.
Свою точку зрения он обосновывает. Именно поэтому это не книжка набора правил для ламеров, а совокупность опыта и теории, которые каждый может получить и использовать у себя на вооружении.
>Остапа понесло. Какая разница по скорости работы и расходу памяти между const, enum и define в конкретном случае с определением числовых констант? Ну-ка, просвети меня, как "дополнительная строчка в файле реализации" ускоряет исполнение программы?
Там жеж в книжке написано. Ты же сам говорил что её не х.ем по заголовкам читал, а как следует, с толком и расстановкой.
Цитирую (это к вопросу о памяти):
"К тому же в случае использования константы с плавающей точкой (как в этом примере) генерируется более компактный код, чем при использовании #define. Дело в том что препроцессор, слепо подставляя вместо макроса ASPECT_RATIO величину 1.653, создает множество копий 1.653 в объектном коде, в то время как использование константы никогда не породит более одной копии этого значения."
>Опять тебя несет без пургена. Может, лучше пойдешь выпьешь валерьянки, чем сочинять про собеседника хуйню?
Почему хуйню? Смотрим пост http://psilogic.livejournal.com/326131.html?thread=6217203#t6217203 - где отмечены особенности (или самые важные (если о других было лень писать), или тебе известные (на то время) ).
Были затронуты вопросы:
1 - кол-во букф, область видимости.
2 - удобство отладки в IDE, область видимости.
3 - кол-во букф, необходимость переключаться между файлами (хотя я называю это сущестованием сущности в двух местах, что имеет среднюю степень критичности).
Тут не вижу ни расхода памяти, ни времени выполнения (ничего, что касается производительности и того, что "под капотом"), ни профилактики багов.
Итаг, что в моем обосновании является хуйней? Ткни пальчиком, плз.
>Если - это наезд. Например, "если ты, Бсивко, мудак, то ты, Бсивко, мудак". Утверждение логически безупречно (тавтология из A следует A) и не содержит, формально говоря, утверждения, что Бсивко - мудак. Но я сомневаюсь, что оно тебе было бы приятно.
Ну извини.
Теперь обоснование конкретно в моем контексте.
Мне бывает пофигу на строгую типизацию. Например, мою табличку ICQ Rating генерит простой скрипт на перле, написанный за два часа и занимает он пару страниц кода. Скрипт маленький, ошибки сделать трудно, а если есть - то отладить лехко, в реальные системы код не пойдет - домашнее использование. Потому нечего его писать на С++, есть более удобные инструменты.
Поэтому, если
йа мудагмне пофигу на строгую типизацию, то я могу использовать динамическую типизацию без каких либо обид или заззрений совести.А у тебя по моей видимости (в данный момент это мое мнение) имеется религиозно-идеологический штамп - "отсутствие строгой типизации означает что йа мудаг."
Я понятно объяснил, что на момент написания ничего подобного про мудака я не имел ввиду?
no subject
Date: 2009-07-18 08:11 am (UTC)Это как раз твой подход - ты однажды головкой ударился, и до сих пор глаза косят (на #define-ы) :)
[ качество/время = результат ~= деньги ]
Если скажешь, что я собираюсь жертвовать качеством, то пойдешь на хуй. Но временем я тоже жертвовать не хочу. Как раз наоборот: используя более экономные (по времени) методы кодирования, можно больше времени оставить на отладку-полировку. Надо искать оптимум. И ты функциональность забыл - третий ключевой фактор.
[ Я не говорю о внешнем вызове, а о внутреннем использовании. ]
Внутри using-и придется переименовывать.
Допустим, ты использовал одно и то же название класса в субпроектах 1 и 2. namespace-ы красиво помогли избежать конфликтов. Казалось бы. Но стоит тебе скопипастить этот класс из одного проекта в другой, как начнутся конфликты. И тогда тебе придется заниматься переименованиями. Причем, процесс переименования может оказаться геморройным, так как в некоторых случаях будет неочевидно, какой из классов используется - от проекта 1 или от проекта 2, так как строка на замену у тебя перед глазами в середине файла, а using где-то в начале файла и вне экрана. А сложные названия с уникальными префиксами можно переименовать за пару секунд в автоматическом режиме find/replace.
Так что тут одна вещь исключает другую. Либо ты допускаешь одинаковые имена - и тогда твой прием копипаста класса не дает выгоды. Либо ты не допускаешь одинаковые имена - но тогда namespace-ы не нужны.
[ Цитирую (это к вопросу о памяти): ]
А к вопросу о скорости, значит, тебя таки несло без пургена?
Про память написано нечто странное, мягко говоря. Поясняю.
Пусть есть оператор a += c, где c - числовая константа. Компилятор может преобразовать это в ассемблерную команду, где константа лежит с сегменте кода, составляя часть команды (add или fadd). Каждый (a += c) будет генерировать такую команду и очередную копию константы.
А также компилятор может завести переменную в сегменте данных и в ассемблерной команде сослаться на нее. При этом ему придется включить в команду адрес константы. Адрес будет лежать в сегменте кода - в дополнение к константе в сегменте данных. Каждый (a += c) будет генерировать такую команду (add/fadd) и очередную копию адреса константы, сама константа при этом может не копироваться. При этом есть одна неприятность: команда должна обращаться и к сегменту кода, и к сегменту данных, что теоретически ведет к замедлению. Но это только теоретически - реально там тонна факторов, которые могут все снивелировать.
Таким образом, придется многократно копировать либо адреса, либо константы. Поскольку речь идет о числовых переменных, то объемы адресов и констант сопоставимы, иногда будет экономия при первом способе, иногда - при втором.
Худший случай для первого способа - это константа типа double, long double или long long при 32-разрядной адресации. Тогда адрес был бы короче, давая выигрыш 4-6 байт на каждую команду. Худший случай для второго способа - константа char или unsigned char при 64-разрядной адресации. Тогда адрес был бы длиннее, давая уже проигрыш в 7 байт на каждую команду плюс необходимость лезть в сегмент данных.
Но! Все, что я написал, относится и к const, и к define, и к enum. Для всех трех случаев компилятор может использовать и первый способ, и второй. Для второго способа компилятор должен заметить, что используется одна и та же константа - он это сделает либо, сравнивая имена, либо, сравнивая литералы - что в лоб, что по лбу.
Так где там экономия по объему?
Я не обсуждал производительность и память по той простой причине, что эти факторы в данном конкретном случае не влияют. В другом случае - влияют, и в другом случае у меня были претензии к афтару как раз в плане производительности.
Досье сравнил - первые упоминания C++ относятся к 1990 году. В это время я был на 2-3 курсе института, и как раз торчал в комп. классе, ковыряясь с Turbo C, и только что появившимся Borland C++ 1.0 под MS-DOS. Только статеек не писал :)
no subject
Date: 2009-07-19 02:29 am (UTC)Знаю таких "оптимутмистов". После которых проектный код проще просто выкинуть и написать нормально. Уже не в первый раз сталкиваюсь и не только на С++. Потому что вылетают ошибки из ниоткуда, память протекает абы как и приложение держит нагрузку в единицы транзакций в секунду вместо потенциальных сотен и тысяч. Это разница между экономичным и профессиональным кодом. Когда проект делается не впопыхах к вчера, а с соблюдением всех фаз и проверок на всех этапах.
Что ты хотел сказать про функциональность?
>.. А сложные названия с уникальными префиксами можно переименовать за пару секунд в автоматическом режиме find/replace.
Ещё раз: find/replace для внешних сущностей делается и там, и там. Для внутренних он необходим для define, для namespace он уже не нужен.
Разница define и namespace - именно в том, что define - это препроцессор, не относящийся к языку никаким боком. namespace - это языковое средство, которое контролирует, использует и понимает уже не только программист, но и компилятор.
И различных особенностей и преимуществ namespace много. Например, подключили библиотеку X и библиотеку Y, и оказалось, что в них конфликт имен Z. Для namespace проблема решается легко:
namespace X {
#include X
}
namespace Y {
#include Y
}
X::Z
Y::Z
что же ты будешь делать с #define?
Или например namespace имеют свойство вложенности. Когда текущий проект можно моментально сделать подпроектом одним namespace.
Я не специалист по холиварам и всех особенности и того и другого не назову. Для этого есть умные книжки и справочники. То, что в С++ систематически убивается препроцессор, ясно и понятно уже давно. Есс-но этому сопротивляется С-ишное старье и привычки. Отношение создателя С++ к препроцессору очень хорошо показано в главе "18. Препроцессор С" книги "Дизайн и эволюция С++" Страуструпа (с примерами, особенностями и инструментами замены). И это не идеология. А естественный процесс отмирания атавизма.
>Пусть есть оператор a += c, где c - числовая константа. Компилятор может преобразовать это в ассемблерную команду, где константа лежит с сегменте кода, составляя часть команды (add или fadd).
>А также компилятор может завести переменную в сегменте данных и в ассемблерной команде сослаться на нее.
Ключевой момент в том, что компилятор может. Он знает, что сущность - константа, а после define'а он может об этом только догадываться. Поэтому в случае константы у компилятора есть выбор и он может с'опитимизировать работу программы как в сторону экономии памяти, так и в сторону ускорения работы.
>А к вопросу о скорости, значит, тебя таки несло без пургена?
const std::string c_str("ABC");
#define C_STR std::string("ABC")
В каждом define сработает конструктор. В const объект создается один раз.
И это оченьвидный пример. Но главное, что компилятор знает, что константа - это одинаковая неизменяемая сущность во многих кусках кода, а define для него - это фигня, разбросанная по всему коду, о сущности которой можно только догадываться. Поэтому основное правило заключается в том, что чем больше компилятор знает о коде, тем об лучше сможет его с'оптимизировать.
>Но! Все, что я написал, относится и к const, и к define, и к enum. Для всех трех случаев компилятор может использовать и первый способ, и второй.
"Шушпанчики могут работать 365 дней в году. Но не работают." (с)
>При этом есть одна неприятность: команда должна обращаться и к сегменту кода, и к сегменту данных, что теоретически ведет к замедлению.
В современных процессорах необходимые данные на последующую команду загружаются для последующей обработки заранее. Аппаратная эволюция не стоит на месте.
>Я не обсуждал производительность и память по той простой причине, что эти факторы в данном конкретном случае не влияют. В другом случае - влияют, и в другом случае у меня были претензии к афтару как раз в плане производительности.
Как оказывается - влияют. Потенциально не всегда, но - влияют. И чем умнее и совершеннее компилятор - тем больше.
(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2009-07-19 02:29 am (UTC)Это дата первой публикации. Мейерс занимался C++ с 1986-го года, когда во всем мире было порядка 2000 пользователей С++. "Effective C++" появился уже в 1991-м.
(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2009-07-17 11:16 pm (UTC)Тогда наверное единственная книжка, на которую ты не будешь настаивать - это телефонный справочник. Авторский налет уметь снимать надо. А также воспринимать чужой опыт.
>На свое мнение я тоже имею право, так как вожусь с этим языком по времени, наверное, не меньше, чем сей афтар.
На здоровье (;
Можно взглянуть на досье и сравнить? Если уж такая аппеляция пошла.