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] http://technorati.com/people/technorati/ketmar (from livejournal.com) 2009-07-19 06:58 am (UTC)(link)
э… а где западло-то? компилятор сделал точно то, о чём его попросили же. с какой стороны я не смотрел, но равенства «Base» и «Derived» в упор не увидел. более того — не увидел даже фигнюшки для преобразования одного в другое (тогда, емнип, компилер мог бы нашаманить преобразование и вызов конструктора, уж не помню, лень проверять, это идиотизм всё равно). а для случая «коструктор копирования отсутствует» стандарт прямо предписывает его неявно зашаманить, а не ебстись с преобразованием типов. именно поэтому конструктор копирования, если он не очевиден, всегда объявляют явно. а дальше пишут там *this = aValue (при наличии унаследованного — или своего — operator =, натурально).

итого: «а этот пацак всё время думает на языках, продолжения которых не знает!» (ц)

[identity profile] http://technorati.com/people/technorati/ketmar (from livejournal.com) 2009-07-19 07:08 am (UTC)(link)
тьфу, йопт. про преобразование — это ж и есть «второй конструктор», ага. %-)

[identity profile] psilogic.livejournal.com 2009-07-19 08:48 am (UTC)(link)
ну вот и получается, что смотришь и думаешь: конструктор копирования есть, все ништях. никто не забыт, ничто не забыто. а его нет :)

[identity profile] http://technorati.com/people/technorati/ketmar (from livejournal.com) 2009-07-19 01:30 pm (UTC)(link)
не, ну как, как можно подумать, что он есть, если сразу видно, что его нет нифига? O_O

ты ж, вроде бы, не первый год на цпп пишешь, вообще должен «влёт» такое замечать. если уж я, который цпп люто ненавидит и пишет в нём в 90% случаев c-style код, вижу…

это, по-моему, во всех книжках напрочь говорится почти сразу: «если явного конструктора копирования нет, компилятор нашаманит свой. везде и завсегда».

зыж херня это всё. (томно вздыхает) вот шаблоооны… «ах, швецiя!» (ц)

[identity profile] psilogic.livejournal.com 2009-07-19 02:18 pm (UTC)(link)
да это все понятно, просто сочетание всех факторов создает неочевидный глюк. ворнинг тут был бы пользителен.

а про Щаблоны хошь задачку прикольную? :)

[identity profile] http://technorati.com/people/technorati/ketmar (from livejournal.com) 2009-07-19 02:27 pm (UTC)(link)
неа, не хочу. я не умею делать шаблоны, только использовать готовые, у которых хорошая документация. я ж не Ъ-цпп-кодер. я вон до недавних пор не знал, что от шаблонизированного класса можно наследоваться (в смысле, например, от QList<int>).

[identity profile] psilogic.livejournal.com 2009-07-19 02:36 pm (UTC)(link)
ну если захочешь потренироваться то тута:
http://psilogic.livejournal.com/326274.html