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
Ну и на здоровье :))))
---------
Это говорит о том, что ситуация не такая уж и редкая.
---------
Ну он просто дает аналогичный эффект - гарантирует, что не будет одноименных констант. Хотя компилятор обычно и так ругается на повторный #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 там, где это оправдано. Так что все корректно и к месту.
>И нехуй мне тут пиздить, что я хуем по заголовкам читаю.
Так что пиздить мне тут хуй (;
Все ещё настаиваешь на обвинении Майерса в пособии необоснованных правил для чайников?