Исключение в конструкторе + финализатор
От: 0x7be СССР  
Дата: 07.07.10 13:57
Оценка:
Коллеги!

Мне одному кажется неправильным, что при вылете исключения из конструктора класса для недосозданного объекта вызывается финализатор того же класса? Получается, что мы имеем нарушение инварианта — происходит вызов метода объекта, для которого не отработал конструктор.
Re: Исключение в конструкторе + финализатор
От: nikov США http://www.linkedin.com/in/nikov
Дата: 07.07.10 14:08
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Мне одному кажется неправильным, что при вылете исключения из конструктора класса для недосозданного объекта вызывается финализатор того же класса? Получается, что мы имеем нарушение инварианта — происходит вызов метода объекта, для которого не отработал конструктор.


А вдруг конструктор успел захватить какие-то unmanaged ресурсы до того как кинул исключение. Если не вызывать финализатор, то кто будет их освобождать?
Re[2]: Исключение в конструкторе + финализатор
От: 0x7be СССР  
Дата: 07.07.10 14:10
Оценка: +1
Здравствуйте, nikov, Вы писали:

N>А вдруг конструктор успел захватить какие-то unmanaged ресурсы до того как кинул исключение. Если не вызывать финализатор, то кто будет их освобождать?

Пускай он их и освобождает. Мне более правильно кажется логика конструирования/разрушения принятая в C++.
Деструкторы там вызываются только для полностью сконструированных объектов (подобъектов). Ошибки в процессе конструирования должны обрабатываться самим конструктором.
Re[3]: Исключение в конструкторе + финализатор
От: Аноним  
Дата: 07.07.10 14:25
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, nikov, Вы писали:


N>>А вдруг конструктор успел захватить какие-то unmanaged ресурсы до того как кинул исключение. Если не вызывать финализатор, то кто будет их освобождать?

0>Пускай он их и освобождает. Мне более правильно кажется логика конструирования/разрушения принятая в C++.

А почему вам так кажется? Финализатор в любом случае принято писать устойчивым к повторном вызовам.
Re[3]: Исключение в конструкторе + финализатор
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.07.10 14:26
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, nikov, Вы писали:


N>>А вдруг конструктор успел захватить какие-то unmanaged ресурсы до того как кинул исключение. Если не вызывать финализатор, то кто будет их освобождать?

0>Пускай он их и освобождает. Мне более правильно кажется логика конструирования/разрушения принятая в C++.
Дублирование получается.
Re[4]: Исключение в конструкторе + финализатор
От: 0x7be СССР  
Дата: 07.07.10 14:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А>А почему вам так кажется? Финализатор в любом случае принято писать устойчивым к повторном вызовам.

Речь совсем не о повторных вызовах.
Re[3]: Исключение в конструкторе + финализатор
От: Аноним  
Дата: 07.07.10 14:29
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Пускай он их и освобождает.

А если исключение бросает конструктор класса-наследника, то как родителю освободить ресурс?
Re[4]: Исключение в конструкторе + финализатор
От: 0x7be СССР  
Дата: 07.07.10 14:29
Оценка:
Здравствуйте, samius, Вы писали:

0>>Пускай он их и освобождает. Мне более правильно кажется логика конструирования/разрушения принятая в C++.

S>Дублирование получается.
Дублирование устраняется другими методами.
Re[4]: Исключение в конструкторе + финализатор
От: 0x7be СССР  
Дата: 07.07.10 14:32
Оценка:
Здравствуйте, Аноним, Вы писали:

0>>Пускай он их и освобождает.

А>А если исключение бросает конструктор класса-наследника, то как родителю освободить ресурс?
Финализаторы успешно сконструированных предков должны вызываться.
Re[3]: Исключение в конструкторе + финализатор
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 07.07.10 14:34
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Пускай он их и освобождает. Мне более правильно кажется логика конструирования/разрушения принятая в C++.


В C++ данные могут быть непроинициализированными. Почему деструктор никак не сможет установить, что конкретно было проинициализировано, а где просто мусор. Так что это вынужденная мера.

0>Ошибки в процессе конструирования должны обрабатываться самим конструктором.


Это неудобно, потому что усложняет конструктор.
Re[5]: Исключение в конструкторе + финализатор
От: Аноним  
Дата: 07.07.10 14:37
Оценка: 3 (1)
Здравствуйте, 0x7be, Вы писали:

0>Финализаторы успешно сконструированных предков должны вызываться.

Здесь, есть еще такой ньюанс — в managed языках создание объекта идет, не как в C++ от предка к родителю, а фактически наоборот (как в java):
class X : Base { public X(int x) { super(x); } }

B Eсли например, вызвать в конструкторе предка виртуальный метод переопределенный в потомке, то вызовется метод потомка. Т.е. с точки зрения среды гораздо сложнее сообразить, кто уже сконструирован, а кто нет.
Re[4]: Исключение в конструкторе + финализатор
От: 0x7be СССР  
Дата: 07.07.10 14:38
Оценка:
Здравствуйте, Mystic, Вы писали:

M>В C++ данные могут быть непроинициализированными. Почему деструктор никак не сможет установить, что конкретно было проинициализировано, а где просто мусор. Так что это вынужденная мера.

С выделенным не согласен. Это очень логичное поведение, целиком укладывающееся в идею, что язык предоставляет программисту ряд инвариантов.

0>>Ошибки в процессе конструирования должны обрабатываться самим конструктором.

M>Это неудобно, потому что усложняет конструктор.
Количество сложности не изменяется. Усложняется конструктор, упрощается финализатор.
Re[6]: Исключение в конструкторе + финализатор
От: 0x7be СССР  
Дата: 07.07.10 14:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>B Eсли например, вызвать в конструкторе предка виртуальный метод переопределенный в потомке, то вызовется метод потомка.

А это второй большой глюк, за который авторам С# надо что-нибудь оторвать
Re[5]: Исключение в конструкторе + финализатор
От: Аноним  
Дата: 07.07.10 14:42
Оценка: -3
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, Аноним, Вы писали:


А>>А почему вам так кажется? Финализатор в любом случае принято писать устойчивым к повторном вызовам.

0>Речь совсем не о повторных вызовах.
Написание такого финализатора очень похоже на реализацию финализатора для неполностью сконструированного объекта.

Короче — подсказываю — вам так кажется, потому что вы к этому привыкли. А на самом деле — в c++ тут допущена ошибка дизайна, которую подправили в .net.
Re[7]: Исключение в конструкторе + финализатор
От: Аноним  
Дата: 07.07.10 14:43
Оценка:
Здравствуйте, 0x7be, Вы писали:
0>А это второй большой глюк, за который авторам С# надо что-нибудь оторвать
Это не баг, а фича Причем не C#, а всего .net, и как я уже говорил, специфичная не только для .net.
Видимо, эта "фича" что-то упрощает для среды исполнения управляемых языков, самому если честно всегда было интересно — что конкретно.
Re[6]: Исключение в конструкторе + финализатор
От: 0x7be СССР  
Дата: 07.07.10 14:44
Оценка: +2 -1
Здравствуйте, Аноним, Вы писали:

А>Короче — подсказываю — вам так кажется, потому что вы к этому привыкли. А на самом деле — в c++ тут допущена ошибка дизайна, которую подправили в .net.

Не согласен. Я считаю, что С++-ный подход вернее. Мои аргументы заключается в том, что тамошняя система в бОльшей степени сохраняет гарантии программисту относительно целостности объекта при вызове его методов (в т.ч. и деструктора). Это, кстати, относится и к возможности вызывать виртуальные методы в конструкторе.
Почему Вы считаете, что это неверный подход?
Re[8]: Исключение в конструкторе + финализатор
От: 0x7be СССР  
Дата: 07.07.10 14:46
Оценка:
Здравствуйте, Аноним, Вы писали:

0>>А это второй большой глюк, за который авторам С# надо что-нибудь оторвать

А>Это не баг, а фича Причем не C#, а всего .net, и как я уже говорил, специфичная не только для .net.
А>Видимо, эта "фича" что-то упрощает для среды исполнения управляемых языков, самому если честно всегда было интересно — что конкретно.
Не только для .net. В Дельфи, например, тоже же самое творится. Но там еще к тому же можно:
1. Создавать экземпляры абстрактных классов.
2. Не вызывать конструктор/деструктор базового класса.
3. Подёргать методы базового класса ДО вызова его конструктора или ПОСЛЕ вызова его деструктора

Только за такие "фитчи" дизайнерам языка надо что-то очень плохое сделать
Re: Исключение в конструкторе + финализатор
От: hardcase Пират http://nemerle.org
Дата: 07.07.10 15:10
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Коллеги!


0>Мне одному кажется неправильным, что при вылете исключения из конструктора класса для недосозданного объекта вызывается финализатор того же класса? Получается, что мы имеем нарушение инварианта — происходит вызов метода объекта, для которого не отработал конструктор.


Откровенно говоря, конструктор для CLR уже отработал — память выделена, поля имеют дефолтные значения: null для ссылок, и нули для структур. Конструкторы, с которыми мы имеем дело в языках всего лишь производят инициализацию полей экземпляра, т.е являются всего лишь автоматически вызваемым методом вертающим void (как вы верно заметили в Delphi похожее поведение). Посему вызов финализатора — вполе оправданное действие, ведь код финализатора (грубо говоря Dispose) обязан работать как для неполностью созданного объекта, так и для уже "разрушенного" объекта.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Исключение в конструкторе + финализатор
От: _FRED_ Черногория
Дата: 07.07.10 15:50
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Коллеги!

0>Мне одному кажется неправильным, что при вылете исключения из конструктора класса для недосозданного объекта вызывается финализатор того же класса? Получается, что мы имеем нарушение инварианта — происходит вызов метода объекта, для которого не отработал конструктор.

Просто другая организация работы с памятью. Отсюда и другие правила поведения. В С++ правильно одно в силу стандарта С++ и ничего более. В дотнете и шарпе правильно своё в силу местных стандартов.
Help will always be given at Hogwarts to those who ask for it.
Re[5]: Исключение в конструкторе + финализатор
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 07.07.10 16:38
Оценка: 1 (1)
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, Mystic, Вы писали:


M>>В C++ данные могут быть непроинициализированными. Почему деструктор никак не сможет установить, что конкретно было проинициализировано, а где просто мусор. Так что это вынужденная мера.

0>С выделенным не согласен. Это очень логичное поведение, целиком укладывающееся в идею, что язык предоставляет программисту ряд инвариантов.

Ну смотри. Такой код смотрится красиво, но с ним будут проблемы:

  class test_t
  {
    private:
      inner_test_t* test1;
      inner_test_t* test2;
    public:
      test_t()
      {
        // Код, который может привести к исключению
        test1 = new inner_test_t();
        // Код, который может привести к исключению
        test2 = new inner_test_t(); 
        // Код, который может привести к исключению
      }  

      virtual ~test_t()
      {
        if (test1) delete test1;
        if (test2) delete test2;
      }
  };


Поэтому приходится либо чрезмерно усложнять конструктор, либо признать, что исключения в конструкторе штука стремная, и ее лучше инициализацию вынести в отдельный метод. Собственно говоря, ради возможности такой удобной записи все и затеяно начиная с Delphi.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.