Entry tags:
Западло
[ Предупреждение: для непрограммистов неинтересно ]
Пусть у нас есть два класса - базовый 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
Очень полезная книжка, нагуглите.
no subject
no subject
Думаю, иногда 240 стр. не слишком высокая цена за новые знания.
no subject
no subject
no subject
no subject
Использование ссылок в inline-функции, которая в 99% случаев будет работать с простыми типами.
Еще что-то... ах да, идеологических сентенций типа "расширяемость С++ это круто, поэтому давайте все время ориентироваться на нее".
no subject
"Использование const вместо #define для числовых констант"
чуть подробнее.
А то мне предстоит программу на с++ делать, а опыта мало,
тот, что был, почти выветрился.
no subject
Для ламера надо вызубрить некое правило, как можно более простое и бездумное. Например, "препроцессор - плохо, const - хорошо". Без всяких оговорок типа, когда, где и при каких условиях. Если же подходить с практических позиций, то лучше далеко не всегда и не везде. Но это надо чуть-чуть мозги включать и вникать.
Конкретно в отношении const.
1. Для автоматических переменных получается переменная, ограниченная по области видимости. Это бонус, отмечаем его как "+1". Плата за это небольшая - чуть больше писать:
#define MAX_CHANNEL 2
и
const int MAX_CHANNEL = 2;
Поскольку писать надо больше совсем чуть-чуть, можно отметить это не как "-1", а, скажем, "-0.5". Итого: +1 против -0.5. Вывод - для автоматических переменных const немного лучше.
2. Для глобальных переменных у const пропадает бонус ограниченной области видимости. Зато может появиться другой бонус: в отладчике видно ее значение, а значение #define не видно. Но это зависит от отладчика. Иной отладчик и #define видит. Так что получается "+0.5". Далее, начинаются несовместимости между C и C++, разные тонкости с версиями компиляторов. Но это тоже редкое явление, так что тоже "-0.5". И еще "-0.5" за то, что длинее.
Итого: +0.5 против -1. Вывод - для глобальных переменных const немного хуже.
3. Если числовая константа - член класса, то для корректного оформления в виде const придется вносить правку и в хэдер, и в исходник, количество писанины растет:
.h:
static const int MAX_CHANNEL = 2;
.cpp:
const int ClassName::MAX_CHANNEL;
Это уже -1. При написании кода появляется необходимость переключаться между файлами. Еще -1. За одно и то же время можно написать константу через const, либо константу через #define плюс комментарий к ней.
Итого: +1 против -2. Вывод - для констант класса const уже намного хуже.
Но самое прикольное то, что есть enum, который лучше, чем #define и лучше, чем const в случаях 2 и 3. Он и показывается в отладчике, и позволяет ограничивать область видимости классом, и не требует залезать в .cpp, и писанины не больше:
enum { MAX_CHANNEL = 2 };
Но enum - "не идеологичен". ;)
Вывод не для ламеров: для автоматических констант юзать const, для глобальных констант (в том числе констант класса) юзать enum.
no subject
no subject
no subject
no subject
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
no subject
#define MAX_CHANNEL 2
и
const int MAX_CHANNEL = 2;
Поскольку писать надо больше совсем чуть-чуть, можно отметить это не как "-1", а, скажем, "-0.5". Итого: +1 против -0.5. Вывод - для автоматических переменных const немного лучше.
------
Писать больше только для типизации. Если она нужна (а она часто именно нужна, хотя обезьяне с гранатой она обычно не нужна; а в макросах возможности типизации(отобрать гранату) нет).
Если программист привык писать наобум, то держи достойную замену:
const MAX_CHANNEL = 2; // без int, все работает
Ограничение области видимости - это возможность. При желании const можно засунуть в namespace, define же лишены этой привилегии и могут разнести в пух и прах кучу любого подключенного кода, и хорошо если это компилятор заметит. const'ы же избавляют от множества потенциальных ошибок данного рода, за что им в данной шкале +10. Обычно это понимают только после наступленияы
------------
2. Для глобальных переменных у const пропадает бонус ограниченной области видимости.
------------
Глобальное пространство имен лучше вообще не засорять. За всю историю использования плюсов в боевых проектах мне приходилось использовать глобальные константы только в единичных случаях пару раз.
------------
3. Если числовая константа - член класса, то для корректного оформления в виде const придется вносить правку и в хэдер, и в исходник, количество писанины растет:
.h:
static const int MAX_CHANNEL = 2;
.cpp:
const int ClassName::MAX_CHANNEL;
Это уже -1. При написании кода появляется необходимость переключаться между файлами. Еще -1. За одно и то же время можно написать константу через const, либо константу через #define плюс комментарий к ней.
Итого: +1 против -2. Вывод - для констант класса const уже намного хуже.
--------------
Тут вообще глупость написана. Потому что define не может быть членом класса. Потому он не имеет никакого преимущества. Возможность прописать const в класс является дополнительной возможностью, которую можно использовать по своему усмотрению, что несомненно '+'.
--------------
В свое время мой вывод не для ламеров - везде где можно заменить константу define на const - нужно это делать, и при этом провести типизацию.
define же использовать для хитрожопых конструкций замены, экзотических случаев или случаев, когда этого требует комплиятор/библиотека или ещё кто.
no subject
недописано (;
после наступления на грабли и очухивания и обхода их в течении часов или даже дней глубокой отладки.
no subject
Вот это как раз - "достойный" пример бездумного следования религиозной заповеди: "типизация - это хорошо" - всегда, независимо ни от чего. А теперь просвети меня, как и почему в данном конкретном случае типизация - это хорошо? Не в параметрах функций, а вот конкретно для констант. Слабо обосновать? Ну и для закрепления пройденного, подумай: что, у констант типов нет? Суффиксы L, U, F не для эстетов? :)
[ Ограничение области видимости - это возможность. ]
Ты вообще читаешь то, что комментируешь? Я отметил, что "это бонус" - какие претензии, не понимаю.
[ за что им в данной шкале +10 ]
А вот это - уже религиозно-идеологическое воззрение. Для холиваров - прекрасно, для серьезного рассмотрения - негодно. Может, сразу +1000^1000? :) Ну чиста патаму шта эта крута!? :)
[ Потому что define не может быть членом класса. ]
Следи за руками:
#define ClassName__MAX_CHANNEL = 2;
:)
Ну и про enum не забудь, он все равно лучше.
no subject
Вот это как раз - "достойный" пример бездумного следования религиозной заповеди: "типизация - это хорошо" - всегда, независимо ни от чего. А теперь просвети меня, как и почему в данном конкретном случае типизация - это хорошо? Не в параметрах функций, а вот конкретно для констант. Слабо обосновать? Ну и для закрепления пройденного, подумай: что, у констант типов нет? Суффиксы 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
no subject
гы гы гы - сраказм ему мой не понравился видите ли :) за собой то не замечаем, да? :)
[ Без компиляции и запуска ответишь? ]
Отвечу - либо компилятор напишет ошибку (если компилятор не допускает тип int по-умолчанию), либо 48 (ASCII-код символа нуля). А зачем ты такую муру написал? Это не техника #define и некорректная техника для const. Ты пытаешься мне показать, что мура - это мура? Так я соглашусь: мура. :)
[ И что измениться при проведении замены на '0' ]
'0' будет.
А теперь берем технику с #define:
#define CH '0'
Константа типа char, напечатает, опять же, '0'. Ну и где оно - счастье? :)
[ Потому что решение проблемы потенцильной ошибки, на вылавливание которой можно потрать куеву хучу времени намного важнее (в данном случае на порядок) четырех-пяти символов. ]
Это ты какой случай рассматриваешь? Константа-член-класса? Тогда не четырех-пяти, а придется переключаться на файл-исходник и там эту переменную еще и определять. А, если файла-исходника нет, то создавать его, вносить в CVS, в проект. У тебя получается, что куча времени на отлов потенциальной ошибки существует, а куча времени на набивание - не существует? И повторю еще раз: в любом случае enum лучше. В упомянутом же "мучебнике" для ламеров прием с enum рассматривается как нечто устаревшее и отжившее. Гы.
[ Это уже грязный хак. Манипуляторы отрывать надо за такое. ]
Это уже опять пошла религия. Думаешь, сказал слово "хак" и на белого коня влез? :) Это не хак, а классическое определение константы со специальным префиксом, который играет ту же роль, что и namespace. Именно так и надо писать глобальные #define-ы, тогда и не придется тратить "куеву хучу времени" на отлов ошибок из-за повторения констант. Потому, что никаких повторений просто не будет.
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
Накося, выкуси.
Re: Накося, выкуси.
Re: Накося, выкуси.
Re: Накося, выкуси.
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
no subject
И эта... Я не хотел, чтобы Вы втянулись в спор. Извините, если что.
no subject
no subject
Так вот, пару слов.
Во-первых, про enum. Как правильно заметил бсивко, мейерс именно что активно рекомендует использовать enum. Он просто говорит, что в программистских кругах сложилось название для подобного использования enum-а - "enum hack". Но из текста (английского по крайней мере) совершенно никак не следует, что это нечто грязное и нечистоплотное, наоборот, этот "хак" преподносится как нечто, что следует знать и использовать.
Во-вторых, про пункт 3, то есть, про константы - члены класса. Тот же мейерс в той же главе пишет, что для типов int, char и bool объявлять переменную в .cpp не нужно - достаточно декларации в хедере, что является стандартом языка. Правда, некоторые старые компиляторы этого могут не поддерживать, но более-менее новые должны. Поэтому писанины становится меньше в два раза.
Ну и в-третьих, пустые холивары всегда бывают от абсолютизации чего-то. Того же мейерса делать непогрешимым кумиром вряд ли стоит. С другой стороны, также вряд ли стоит утверждать его ламерство, в то время как он является распространенным и уважаемым автором для многих программистских коллективов. Скажем, ты можешь не разделять их и бсивко воззрения на минимизацию времени на отладку и поиск багов, но они в свою очередь, могут не разделить твое видение себя в их рядах в случае поиска работы... :)
no subject
Вот силами таких текстов и сложилось.
[ Правда, некоторые старые компиляторы этого могут не поддерживать, но более-менее новые должны. Поэтому писанины становится меньше в два раза. ]
Здесь вы правы, убедили - поддержка старых компиляторов требуется редко. С сегодняшнего дня начинаю чаще юзать const для констант.
А какое ваше мнение по поводу функции max, где предлагается сделать параметры ссылками?
no subject
[Вот силами таких текстов и сложилось.]
Что ты предлагаешь мне увидеть из этого предложения, кроме того, что ты сердит на текст и оттого, вероятно, необъективен?
[А какое ваше мнение по поводу функции max, где предлагается сделать параметры ссылками?]
Нормальное. Если она будет использоваться для объектов с тяжелым конструктором копирования, то выгоды очевидны.
no subject
А если будет использоваться для простого типа?
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)