[image]

Нужны ли public конструкторы?

 
1 2 3 4
US Сергей-4030 #10.12.2007 21:46  @Kernel3#10.12.2007 21:30
+
-
edit
 

Сергей-4030

исключающий третье
★★
Kernel3> Обещанный пример (выдернуто из контекста, поэтому с глупыми комментариями :) ) :
AutoRef<TypedRegValue>> UpperFiltersEx(interface_cast<RegValue>(UpperFilters));
Kernel3> // Здесь будет 2 временных объекта: при вызове interface_cast ("обёртка" вокруг UpperFilters) и
Kernel3> // UpperFiltersEx() (типа TypedRegValue c RegValue в качестве параметра)
Kernel3> if (UpperFiltersEx)
Kernel3> {
Kernel3> result = UpperFiltersEx->SetValue(UpperFiltersEx->GetType(), UpperFiltersEx->GetValue() + NewUpper);
Kernel3> // И здесь 2: результат сложения и "обёртка" вокруг этого результата,
Kernel3> // приводящая его к типу второго аргумента SetValue()
Kernel3> }
Kernel3> Итого к коду из 3-х значащих строчек, по-вашему, надо добавить ещё 4. Соотношение хоть и не 5:20, но лично меня впечатляет.

Только для С++ и только потому, что нет автоматической сборки мусора.

Kernel3> Кстати, "обёртка" вокруг UpperFiltersEx->GetValue() + NewUpper называется Variant и имеет 5 конструкторов с раличными типами аргумента. Что позволяет использовать его в т.ч. в качестве возвращаемого значения. Как вы собираетесь заменить эту функциональность фабриками? ;)

В фабрике тоже может быть сколько хошь разных методов. ;)
   
RU Kernel3 #10.12.2007 21:48  @Сергей-4030#10.12.2007 21:43
+
-
edit
 

Kernel3

аксакал

Сергей-4030> Это будет офигительно лучше. ;) Представьте, у вас система в сто тыщ строк, таких вызовов ( ObjectInterface o = new ObjectImplementation() ) тридцать тысяч. Вы пойдете весь код шерстить?
Нет. Убью архитектора :F Наверное, всё-таки, такие вызовы должны быть в одном месте. Собственно, именно это место вы можете называть фабрикой, если вам так больше нравится. Только причём здесь запрет публичных конструкторов? :)
   
US Сергей-4030 #10.12.2007 21:53  @Kernel3#10.12.2007 21:48
+
-
edit
 

Сергей-4030

исключающий третье
★★
Сергей-4030>> Это будет офигительно лучше. ;) Представьте, у вас система в сто тыщ строк, таких вызовов ( ObjectInterface o = new ObjectImplementation() ) тридцать тысяч. Вы пойдете весь код шерстить?
Kernel3> Нет. Убью архитектора :F Наверное, всё-таки, такие вызовы должны быть в одном месте. Собственно, именно это место вы можете называть фабрикой, если вам так больше нравится.

Ну, то есть, глобальных противоречий у нас нет. ;)

Kernel3> Только причём здесь запрет публичных конструкторов? :)

Для того, чтобы требование "не создавать объектов в обход "одного места" было енфорсано не только строгими глазами начальника, а тупыми ограничениями синтакса.
   
RU riven-mage #10.12.2007 21:56  @Сергей-4030#10.12.2007 21:21
+
-
edit
 

riven-mage

опытный

Сергей-4030> Нет, совсем не поэтому. Они появились оттого, что надо контролировать создание объекта. Как "подкачать"? this инициализировать в конструкторе?

Я неточно выразился. Нужно подкачать язык, а не только конструктор.

Фабрика какие проблемы решает? (оговорюсь, что у меня практики ООП уже года 4 практически нет, да и в крупных С++ - проектах не участвовал) Из того, что помню:

1. Невозможно понять после исполнения new, проинициализировался объект до конца или нет (фабрика может вернуть null, если что не так, конструктор - не может. Решения - или бросать в конструкторе исключение (а снаружи - try/catch), или чтобы new мог null-ы возвращать.

2. Борьба с утечками памяти. Недоинициализировнные объекты надо как-то прибивать, а delete из конструктора не вызовешь. Решение - сборщик мусора.

Что-то еще? Вернее, не так. Что такого можно инкапсулировать в фабрике, что нельзя засунуть в new? Если угодно, применительно к Си++.
   
Это сообщение редактировалось 10.12.2007 в 22:02
US Сергей-4030 #10.12.2007 22:02  @riven-mage#10.12.2007 21:56
+
-
edit
 

Сергей-4030

исключающий третье
★★
Сергей-4030>> Нет, совсем не поэтому. Они появились оттого, что надо контролировать создание объекта. Как "подкачать"? this инициализировать в конструкторе?
riven-mage> Я неточно выразился. Нужно подкачать язык, а не только конструктор.
riven-mage> Фабрика какие проблемы решает? (оговорюсь, что у меня практики ООП уже года 4 практически нет, да и в крупных С++ - проектах не участвовал)

Фабрика решает описанные выше проблемы. Конкретно, выделяет создание экземпляров объекта в "одно место", где можно заняться проблемами кэширования, изменения конкретного типа объекти и т.п изолированно от остального кода.

riven-mage> 1. Невозможно понять после исполнения new, проинициализировался объект до конца или нет (фабрика может вернуть null, если что не так, конструктор - не может. Решения - или бросать в конструкторе исключение (а снаружи - try/catch), или чтобы new мог null-ы возвращать.
riven-mage> 2. Борьба с утечками памяти. Недоинициализировнные объекты надо как-то прибивать, а delete из конструктора не вызовешь. Решение - сборщик мусора.

Оба этих предмета не являются ключевыми. Кстати, бросать в конструкторе исключения - в С++ это очень плохо, очень. Даже в Джава лучше не бросать.

riven-mage> Что-то еще?

Да, см. выше.
   
RU Kernel3 #10.12.2007 22:05  @Сергей-4030#10.12.2007 21:53
+
-
edit
 

Kernel3

аксакал

Сергей-4030> Ну, то есть, глобальных противоречий у нас нет. ;)
Если вы согласны оставить публичные конструкторы хотя бы только в С++, то нет ;)
Сергей-4030> Для того, чтобы требование "не создавать объектов в обход "одного места" было енфорсано не только строгими глазами начальника, а тупыми ограничениями синтакса.
Всё ж таки это создаст дополнительные трудности с сомнительным положительным эффектом. По крайней мере, в одном отдельно взятом языке с отсутствующей автоматической сборкой мусора ;)
   
RU Kernel3 #10.12.2007 22:07  @Сергей-4030#10.12.2007 22:02
+
-
edit
 

Kernel3

аксакал

Сергей-4030> Кстати, бросать в конструкторе исключения - в С++ это очень плохо, очень.
?? Это почему? В деструкторе - да, очень плохая идея. А в конструкторе-то с чего вдруг?
   
US Сергей-4030 #10.12.2007 22:11  @Kernel3#10.12.2007 22:07
+
-
edit
 

Сергей-4030

исключающий третье
★★
Сергей-4030>> Кстати, бросать в конструкторе исключения - в С++ это очень плохо, очень.
Kernel3> ?? Это почему? В деструкторе - да, очень плохая идея. А в конструкторе-то с чего вдруг?

Вот почему:

A C++ object's lifetime begins only after its constructor completes successfully. Therefore throwing an exception from a constructor always means (and is the only way of reporting) that construction failed. There is no way to recover from failed construction of a base or member subobject, so if construction of any base or member subobject fails, the whole object's construction must fail.

Avoid function try blocks, not because they're evil but just because they offer few or no benefits over plain try blocks — and when you're hiring you'll find that more people understand the latter than understand the former. This follows the principles of picking the simplest solution that's effective, and of writing for clarity first. Constructor function try blocks are useful only to translate exceptions emitted from base or member constructors, and all other function try blocks are rarely if ever useful at all.
 
   
US Сергей-4030 #10.12.2007 22:15  @Kernel3#10.12.2007 22:05
+
-
edit
 

Сергей-4030

исключающий третье
★★
Сергей-4030>> Ну, то есть, глобальных противоречий у нас нет. ;)
Kernel3> Если вы согласны оставить публичные конструкторы хотя бы только в С++, то нет ;)
Сергей-4030>> Для того, чтобы требование "не создавать объектов в обход "одного места" было енфорсано не только строгими глазами начальника, а тупыми ограничениями синтакса.
Kernel3> Всё ж таки это создаст дополнительные трудности с сомнительным положительным эффектом. По крайней мере, в одном отдельно взятом языке с отсутствующей автоматической сборкой мусора ;)

Нет, не создаст. То есть, понятно, что в случаях описанных выше (с Мишкиным добавлением) надо предоставлять public конструкторы. Во всех остальных случаях - не надо.

ЗЫ Кстати, да, отврат. После 6 лет С++ я очень его любил. Но когда я познакомился с Java, я понял, что любовь прошла. Последние полгода страдал с embedded systems под С++ - очень мне не нравилось. Сейчас вернулся к Java, слава богу.
   
RU Kernel3 #10.12.2007 22:17  @Сергей-4030#10.12.2007 22:11
+
-
edit
 

Kernel3

аксакал

Сергей-4030> Вот почему:
И? :) Из первого абзаца следует скорее то, что нельзя даже пытаться использовать объект, кинувший исключение при конструировании. Во втором даётся совет, когда исключения использовать всё-таки надо (к слову, не помню, чтобы встречал другое их использование в конструкторе). Всё ж не использовать совсем - это слишком сильное утверждение :)
   
RU Kernel3 #10.12.2007 22:19  @Сергей-4030#10.12.2007 22:15
+
-
edit
 

Kernel3

аксакал

Сергей-4030> ЗЫ Кстати, да, отврат. После 6 лет С++ я очень его любил. Но когда я познакомился с Java, я понял, что любовь прошла. Последние полгода страдал с embedded systems под С++ - очень мне не нравилось. Сейчас вернулся к Java, слава богу.
Всё ж таки у С++ спектр решаемых задач пошире будет :) NTшный драйвер на Java написать слабо, к примеру? ;) Или вот эти ваши embedded systems - С++ там же явно не просто так был? :)
   
US Сергей-4030 #10.12.2007 23:17  @Kernel3#10.12.2007 22:19
+
-
edit
 

Сергей-4030

исключающий третье
★★
Сергей-4030>> ЗЫ Кстати, да, отврат. После 6 лет С++ я очень его любил. Но когда я познакомился с Java, я понял, что любовь прошла. Последние полгода страдал с embedded systems под С++ - очень мне не нравилось. Сейчас вернулся к Java, слава богу.
Kernel3> Всё ж таки у С++ спектр решаемых задач пошире будет :) NTшный драйвер на Java написать слабо, к примеру? ;) Или вот эти ваши embedded systems - С++ там же явно не просто так был? :)

Да как бы как раз наоборот. Нынче 2007 год. ;) C++ решает в основном задачи, очень близкие аппаратуре. То, что в 1990 решалось ассемблером. Драйверок там накатать или еще чего подобное. А "большие" задачи, всякие распределенные системы - они сейчас на C++ не пишутся.
   
+
-
edit
 

Mishka

модератор
★★★
Kernel3> Итого к коду из 3-х значащих строчек, по-вашему, надо добавить ещё 4. Соотношение хоть и не 5:20, но лично меня впечатляет.
Kernel3> Кстати, "обёртка" вокруг UpperFiltersEx->GetValue() + NewUpper называется Variant и имеет 5 конструкторов с различными типами аргумента. Что позволяет использовать его в т.ч. в качестве возвращаемого значения. Как вы собираетесь заменить эту функциональность фабриками? ;)

В Джаве это не так. Ничего добавлять не надо, кроме, может одной строчки, т.к. не возникает временных значений при передаче параметром. А в операциях +, если их переопределить, доступ к конструктору есть, если надо вернуть временный объект.
   
US Naturalist #10.12.2007 23:20
+
-
edit
 

Naturalist

аксакал

Так они и раньше не писались на С++.
   
+
-
edit
 

Mishka

модератор
★★★
Сергей-4030>> Да-да. ;) А еще мы, серьезные люди, боимся гоуту и вообще - программирования спагетти. По своей ограниченности. ;) Гоуту - в массы, долой предрассудки!
Kernel3> Разумеется. А вы знаете способ проще, выйти из вложенных циклов? (Только не говорите, что вы их не пишете)
Было такое определения языка программирования, как ЯП уровня N, если он позволял выйти из рекурсии на верх за одну операцию на N (или меньше, т.е. от 1 до N) уровней. Предлагалось что-то вроде унарного-бинарного оператора return:


3 return x; — поднятся из рекурсии на 3 шага и вернуть х в качестве результата.

1 return; — один хоп наверх и никакого результата.

Теоретически доказали, что у языков разного уровня разная мощность в каком-то смысле (сейчас не помню в каком :) ).
   
US Mishka #10.12.2007 23:29  @Сергей-4030#10.12.2007 21:21
+
-
edit
 

Mishka

модератор
★★★
riven-mage>> А разве фабрики не появились от ущербности конструкторов? Т.е. если в языке "подкачать" конструкторы, то чем запись:
riven-mage>> o = new SomeObject();
riven-mage>> будет отличаться от:
riven-mage>> o = SomeObject->factory();
Сергей-4030> Нет, совсем не поэтому. Они появились оттого, что надо контролировать создание объекта. Как "подкачать"? this инициализировать в конструкторе?
Дык, а чего спорить-то? Есть книга "банды четырёх" — там подробно расписано для чего нужны фактори метод, фактори паттерн и фактори сама. :)
   
US Naturalist #10.12.2007 23:30  @Mishka#10.12.2007 23:26
+
-
edit
 

Naturalist

аксакал

Сергей-4030>>> Да-да. ;) А еще мы, серьезные люди, боимся гоуту и вообще - программирования спагетти. По своей ограниченности. ;) Гоуту - в массы, долой предрассудки!
Kernel3>> Разумеется. А вы знаете способ проще, выйти из вложенных циклов? (Только не говорите, что вы их не пишете)
Mishka> Было такое определения языка программирования, как ЯП уровня N, если он позволял выйти из рекурсии на верх за одну операцию на N (или меньше, т.е. от 1 до N) уровней. Предлагалось что-то вроде унарного-бинарного оператора return:
Mishka> 3 return x; — поднятся из рекурсии на 3 шага и вернуть х в качестве результата.
Mishka> 1 return; — один хоп наверх и никакого результата.
Mishka> Теоретически доказали, что у языков разного уровня разная мощность в каком-то смысле (сейчас не помню в каком :) ).

Для этого, вроде как, есть эксепшин.
   
US Mishka #10.12.2007 23:38  @Сергей-4030#10.12.2007 21:40
+
-
edit
 

Mishka

модератор
★★★
Сергей-4030> Не согласен. Кто мешает реализовать фабрику как захочешь?

Не, ты не понял.

Вот у тебя есть иерархия:

code text
  1.  
  2. class A
  3. {
  4. };
  5.  
  6. class B : public A
  7. {
  8. };
  9.  
  10. class Factory
  11. {
  12. public:
  13.   A* MakeA( ... );
  14.   B* MakeB( ... );
  15. }


Вполне законно и нормально создание объектов как А, так и В.

Кто-то добавил класс С:
code text
  1.  
  2. class A
  3. {
  4. };
  5.  
  6. class B : public A
  7. {
  8. };
  9.  
  10. class C : public B
  11. {
  12. };
  13.  
  14. class Factory
  15. {
  16. public:
  17.   A* MakeA( ... );
  18.   B* MakeB( ... );
  19.   C* MakeC( ... );
  20. }


Пришлось добавить метод. Вот про это я и говорю. Иметь их приходится все три, т.к. С* можно вернуть и присвоить А*, а вот А* вернуть как С* — проблема — хаккерство получается.
   
+
-
edit
 

Mishka

модератор
★★★
Сергей-4030>> Это будет офигительно лучше. ;) Представьте, у вас система в сто тыщ строк, таких вызовов ( ObjectInterface o = new ObjectImplementation() ) тридцать тысяч. Вы пойдете весь код шерстить?
Kernel3> Нет. Убью архитектора :F Наверное, всё-таки, такие вызовы должны быть в одном месте. Собственно, именно это место вы можете называть фабрикой, если вам так больше нравится. Только причём здесь запрет публичных конструкторов? :)

Так это и есть фабрика. А запрет за тем, чтобы тот архитектор не смог располтись мысле по древу или c-tor-ами по исходному коду. :F
   
US Mishka #10.12.2007 23:53  @Naturalist#10.12.2007 23:30
+
-
edit
 

Mishka

модератор
★★★
Naturalist> Для этого, вроде как, есть эксепшин.

Не-а, exception раскручивает стек до ближайшего перехватчика (динамическая жизнь статической цепочки, как мы её называли :) ), а не туда, куда хочешь. Т.е., если перехватчик был перед вызововм рекурсивной функции, то рекурсия раскрутится вся, а, если внутри функции, то в ближайшую точку на уровень выше.
   
US Сергей-4030 #10.12.2007 23:57  @Mishka#10.12.2007 23:38
+
-
edit
 

Сергей-4030

исключающий третье
★★
Сергей-4030>> Не согласен. Кто мешает реализовать фабрику как захочешь?
Mishka> Не, ты не понял.
Mishka> Вот у тебя есть иерархия:
Mishka> Пришлось добавить метод. Вот про это я и говорю. Иметь их приходится все три, т.к. С* можно вернуть и присвоить А*, а вот А* вернуть как С* — проблема — хаккерство получается.

Мне кажется, такая идея как-то... эээ.. flawed. Вопрос, собственно, вот в чем - должен пользователь фабрики знать конкретный тип объекта (а не только интерфейс)? Если не должен, если B и С - реализации интерфейса А, то тогда и makeB не должен там быть вовсе. Если должен, то мы имеем дело еще с одной фабрикой, ее нужно создать и, видимо, мы должны явно описать:

B FactoryB.makeObject();

ЗЫ Я так думаю. (С) х/ф Мимино. ;)
   
US Naturalist #11.12.2007 00:10  @Mishka#10.12.2007 23:53
+
-
edit
 

Naturalist

аксакал

Naturalist>> Для этого, вроде как, есть эксепшин.
Mishka> Не-а, exception раскручивает стек до ближайшего перехватчика (динамическая жизнь статической цепочки, как мы её называли :) ), а не туда, куда хочешь.
До ближайшего перехватчика, который не имеет в конце обработки throw.

Mishka> Т.е., если перехватчик был перед вызововм рекурсивной функции, то рекурсия раскрутится вся, а, если внутри функции, то в ближайшую точку на уровень выше.

Опять таки, если в рекурсивной функции делать throw по условию, то все будет как ты хочешь.

Другое дело, я не припомню, чтобы мне такое хоть раз было нужно. Обычно везде работает if(...) return;
Если жалко вызова, можно сделать inline функцию, которая сделает "return 3 up" "чисто".

Сидя в фунции, ты никогда не знаешь, что там наверху по стеку. Да и зачем? Смысл функции пропадает.
   
US Mishka #11.12.2007 00:54  @Naturalist#11.12.2007 00:10
+
-
edit
 

Mishka

модератор
★★★
Naturalist> До ближайшего перехватчика, который не имеет в конце обработки throw.

Не-а. Это идёт до этого, потом оно перевбрасывается. Но остановка на минимальную обрабоку уже была.

Naturalist> Опять таки, если в рекурсивной функции делать throw по условию, то все будет как ты хочешь.

Ну и сделай мне выход из рекурсии любой глубины на 10 уровней ровно всегда. Или по переменной. И увидишь разницу. Тебе придётся тянуть назад и проверять, а на сколько уровней я уже вышел.

Naturalist> Другое дело, я не припомню, чтобы мне такое хоть раз было нужно. Обычно везде работает if(...) return;

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

Naturalist> Если жалко вызова, можно сделать inline функцию, которая сделает "return 3 up" "чисто".
Naturalist> Сидя в фунции, ты никогда не знаешь, что там наверху по стеку. Да и зачем? Смысл функции пропадает.

Нет, не пропадает. Блин, ты не понимаешь. Не просто 3. А вот по условию один, вернулись назад на 1, а по условию 2 вернулись назад на 10.
   
US Naturalist #11.12.2007 01:07  @Mishka#11.12.2007 00:54
+
-
edit
 

Naturalist

аксакал

Naturalist>> До ближайшего перехватчика, который не имеет в конце обработки throw.
Mishka> Не-а. Это идёт до этого, потом оно перевбрасывается. Но остановка на минимальную обрабоку уже была.

Не-а. Остановка была на каждом выходе из каждого скопа с вызовом всех деструкторов и проч.

Naturalist>> Опять таки, если в рекурсивной функции делать throw по условию, то все будет как ты хочешь.
Mishka> Ну и сделай мне выход из рекурсии любой глубины на 10 уровней ровно всегда. Или по переменной. И увидишь разницу. Тебе придётся тянуть назад и проверять, а на сколько уровней я уже вышел.

Можно кинуть класс с счетчиком. В любом случае, эксцепшин не для этого сделан. Этот разговор похож на спор на тему, кто победит, кит или слон. ;)

Naturalist>> Другое дело, я не припомню, чтобы мне такое хоть раз было нужно. Обычно везде работает if(...) return;
Mishka> Да элементарно, Ватсон. Возми сложные обходы деревьев, где некоторые свойства дерева позволяют вернуться сразу на несколько уровней наверх, т.к. известно условие, что, если предикат выполнен в листочке, то поддерево уровня N не содержит больше листков с нужными аттрибутами.

Делаем итератор обхода дерева и все становится попроще...

Naturalist>> Если жалко вызова, можно сделать inline функцию, которая сделает "return 3 up" "чисто".
Naturalist>> Сидя в фунции, ты никогда не знаешь, что там наверху по стеку. Да и зачем? Смысл функции пропадает.
Mishka> Нет, не пропадает. Блин, ты не понимаешь. Не просто 3. А вот по условию один, вернулись назад на 1, а по условию 2 вернулись назад на 10.

Это должен знать только тот, кто живет на 10 этаже стека, остальным должно быть все равно. Это нарушает концепцию структурного программирования. Поэтому таких чудес в структурном программировании нет. Даже в Ц.
   
US Naturalist #11.12.2007 01:14
+
-
edit
 

Naturalist

аксакал

Кстати, почему не сделать переменную bool hurray_we_found_it=false;?
   
1 2 3 4

в начало страницы | новое
 
Поиск
Настройки
Твиттер сайта
Статистика
Рейтинг@Mail.ru