psilogic: (Default)
psilogic ([personal profile] psilogic) wrote2009-07-14 04:31 pm

Западло

[ Предупреждение: для непрограммистов неинтересно ]

Пусть у нас есть два класса - базовый 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) { /* важные манипуляции */ }
};


Но ведь и вляпаться тоже легко...

[identity profile] bsivko.livejournal.com 2009-07-17 02:07 pm (UTC)(link)
[ Я кажется уже написал, что попадал в такую 'редкую' ситуацию. ]
Ну и на здоровье :))))
---------
Это говорит о том, что ситуация не такая уж и редкая.
---------
Ну он просто дает аналогичный эффект - гарантирует, что не будет одноименных констант. Хотя компилятор обычно и так ругается на повторный #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 там, где это оправдано. Так что все корректно и к месту.

>И нехуй мне тут пиздить, что я хуем по заголовкам читаю.
Так что пиздить мне тут хуй (;

Все ещё настаиваешь на обвинении Майерса в пособии необоснованных правил для чайников?