вторник, 5 февраля 2008 г.

not-in-charge конструкторы.

В тщетных попытках отучить gcc создавать копию конструктора зарылся в его исходники...

Как выяснилось, третий тип, complete object allocating constructor, никогда не используется. И на том спасибо, а то это была бы тайна трех конструкторов..

В терминологии gcc эти конструкторы называются in-charge и not-in-charge конструкторами. Разница между ними заключается в том, что not-in-charge конструктор конструирует только поля данного класса, не вызывая родительских конструкторов. В то время как in-charge конструктор конструирует объект полностью.

Использование в дочерних конструкторах not-in-charge конструкторов базовых классов позволяет избежать многочисленных инициализаций. Скорее всего это актуально для множественного наследования. Подробнее можно прочитать здесь.

Но проблема заключается в том, что в классе, у которого нету предков, эти конструкторы полностью идентичны. Их можно было бы представить в виде одного метода с двумя разными именами. Бага, не бага, но штука не очень хорошая.

Не знаю, как с этим обстоят дела в других компиляторах, но пользователям gcc, беспокоящимся об объеме своих программ можно дать такой рецепт: Минимизировать тело конструкторов. Все инициализационные рассчеты выносить в отдельные инициализационные методы.

Мне удалось избежать дублирования, описав тело конструктора в описании класса (inline конструктор), при этом он всеравно оформился в виде функции, но теперь уже однократно.

00000000 W _ZN15RandomGeneratorC1Ev

Вот пожалуй и все...

11 коммент.:

Анонимный комментирует...

Хороший разбор вышел, интересно.

Андрей Валяев комментирует...

Ну для меня это было откровением. А особенно смутило что конструкторы абсолютно одинаковые и два. Если бы они сразу были разные - я бы быстрее сообразил, в какую сторону копать :)

Говорят вот, Watcom спокойно обходится одним конструктором.

Видимо особенность gcc.

Анонимный комментирует...

А что за версия gcc?

Андрей Валяев комментирует...

chizh: У меня - gcc (GCC) 4.1.2 (Gentoo 4.1.2 p1.0.2)

У тебя такой феномен не проявляется? Ты на какой версии пишешь?

Анонимный комментирует...

Не, это я чисто для себя спросил. Сам я уже давно ни чего не пишу, тем более на gcc.
Вообще я думаю, если все ключи и опции компилятора изучить, то что-нибудь в этом роде можно отыскать.
И по идее, если сделать конструктор в секции private, то ни каких копий не должно быть.
Ради интереса, пришли мне файл cpp с примером на akobets@mail.ru , проверю на версии gcc 4.2.2. Также есть смысл проверить на версии 4.3, там новый алгоритм компиляции.

Андрей Валяев комментирует...

Изменение области видимости на private не должно оказывать эффекта. а protected по идее должен, но не оказывает.

Вероятно gcc раздваивает все конструкторы без разбора, в этом то и заключается бага.

Теоретически protected конструкторы не могут быть использованы из потомков даже неявно (надо проверить).

Кроме того нет никакой необходимости раздваивать конструкторы для базовых объектов. Поведение конструкторов различается только у наследников.

Может более свежий gcc такие ситуации и разрулит.

Андрей Валяев комментирует...

А вот нихрена...

protected конструктор по умолчанию неявно всеравно вызывается.

Да и явно вызывается без малейших возражений...

странно это...

Анонимный комментирует...

Попробовал на версии 4.2.2, точно такой же результат. Если знаешь английский, то можно задать
вопрос на форуме
http://groups.google.com/group/comp.lang.c++
или
http://groups.google.com/group/comp.unix.programmer

Андрей Валяев комментирует...

Да мне оно как-то не надо.
К тому же я не настолько знаю английский.

Главное для себя уяснить этот факт и пользоваться конструкторами и деструкторами осмотрительно.

Особенно в системном программировании... :)

icdm комментирует...

Теоретически protected конструкторы не могут быть использованы из потомков даже неявно (надо проверить).Андрей! Это private-конструкторы не могут быть вызваны из потомков, а protected не могут быть вызваны вне класса и его потомка/потомков (если не указан friend для caller'а). Я даже проверил...

Два примера ниже корректно компилируются
-------------------------
class A {
protected:
A (int){}
};
class B : public A {
protected:
B (int a):A(a){}
};
-------------------------
class A {
protected:
A (int){}
};
class B : private A {
public:
B (int a):A(a){}
};

Примера ниже не компилируются
-------------------------
class A {
private:
A (int){}
};
class B : public A {
public:
B (int a):A(a){}
};

Андрей Валяев комментирует...

2icdm: А я уже не помню что хотел сказать, может быть и правда перепутал private и protected. :)