Re[5]: паттерн "Мюнхгаузен"
От: MasterZiv СССР  
Дата: 03.09.09 07:14
Оценка:
Кодт пишет:

> A>Там не отдаётся указатель. *this — это сам объект, т.е. исключение

> кидается по значению.
> ... и происходит срезка!

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

А вот как быть с двойным, вложенным throw ?
Это нормально ? МОжно ?

(во время работы внешнего throw выполняется конструктор и из него
срабатывает внутренний throw).
Posted via RSDN NNTP Server 2.1 beta
Re[6]: паттерн "Мюнхгаузен"
От: Rostislav_Pro  
Дата: 03.09.09 08:08
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Кодт пишет:


>> A>Там не отдаётся указатель. *this — это сам объект, т.е. исключение

>> кидается по значению.
>> ... и происходит срезка!

MZ>Ну тут по-моему очевидно, что наследников у такого исключения не

MZ>должно быть. И по смыслу, и по данному коду, который на это не
MZ>расчитан.

MZ>А вот как быть с двойным, вложенным throw ?

MZ>Это нормально ? МОжно ?

MZ>(во время работы внешнего throw выполняется конструктор и из него

MZ>срабатывает внутренний throw).

По идее конструктор выполняется ДО, а не ВО ВРЕМЯ работы внешнего throw.
Поэтому внешний throw даже не начинает выполняться (т.к. параметр для него не был создан).
Re[6]: паттерн "Мюнхгаузен"
От: Кодт Россия  
Дата: 03.09.09 08:14
Оценка:
Здравствуйте, Erop, Вы писали:

К>>... и происходит срезка!

E>Откуда тут срезка-то? Всё, что более выведенное ещё не сконструировалось!!!

Вот прямо отсюда и будет срезка: кидали SomeMostDerivedException, а вылетело TheVeryBasicException.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[6]: паттерн "Мюнхгаузен"
От: Кодт Россия  
Дата: 03.09.09 08:14
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>А вот как быть с двойным, вложенным throw ?

MZ>Это нормально ? МОжно ?

MZ>(во время работы внешнего throw выполняется конструктор и из него

MZ>срабатывает внутренний throw).

Дело в том, что throw expr — это выражение, вычисляемое, как и положено ему, справа налево.
Сперва вычисляется expr (в нашем случае это конструктор объекта),
затем результат передаётся по значению в throw,
ну а результат throw — void — очевидно, никуда дальше не передаётся.

В нашем случае expr само кидает исключение.
Кстати, можно записать вот такой кошмар
#include <iostream>

struct X {};
struct Y {};

void test(int t)
{
    try
    {
        int v = (t>0)
            ?
                (
                    std::cout << "throwing...",
                    throw
                    (
                        (t>1)
                        ?
                            (
                                std::cout << "throwing X()...",
                                throw X(),
                                Y()
                            )
                        :
                            Y()
                    ),
                    123
                )
            : 456;
        std::cout << "passed " << v << std::endl;
    }
    catch(X)
    {
        std::cout << "caught X" << std::endl;
    }
    catch(Y)
    {
        std::cout << "caught Y" << std::endl;
    }
}

int main()
{
    test(0);
    test(1);
    test(2);
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[5]: паттерн "Мюнхгаузен"
От: Кодт Россия  
Дата: 03.09.09 08:21
Оценка:
Здравствуйте, jazzer, Вы писали:

J>по какому значению, если объект не сконструирован?

J>Тут позовется конструктор копирования, у которого в параметре будет ссылка, указывающая на несуществующий объект — UB при попытке использования.

То есть,
class Foo
{
    .....
    Foo()
    {
        Foo copy (*this); // UB?
    }
    .....
};
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[6]: паттерн "Мюнхгаузен"
От: Centaur Россия  
Дата: 03.09.09 08:58
Оценка: 37 (2)
Здравствуйте, Кодт, Вы писали:

J>>Тут позовется конструктор копирования, у которого в параметре будет ссылка, указывающая на несуществующий объект — UB при попытке использования.


К>То есть,

К>class Foo
К>{
К>    .....
К>    Foo()
К>    {
К>        Foo copy (*this); // UB?
К>    }
К>    .....
К>};


По идее да. Ибо сказано:

3.8 Object Lifetime [basic.life]

1: The lifetime of an object is a runtime property of the object. The lifetime of an object of type T begins when:

А конструктор-то к этому времени ещё и недовыполнился, следовательно, объект ещё не жив. Алсо:

3.8/6:[…] before the lifetime of an object has started but after the storage which the object will occupy has been allocated […] any lvalue which refers to the original object may be used but only in limited ways. […] If an lvalue-to-rvalue conversion (4.1) is applied to such an lvalue, the program has undefined behavior; if the original object will be or was of a non-POD class type, the program has undefined behavior if:

Re[6]: паттерн "Мюнхгаузен"
От: jazzer Россия Skype: enerjazzer
Дата: 03.09.09 09:18
Оценка: 37 (2)
Здравствуйте, Кодт, Вы писали:

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


J>>по какому значению, если объект не сконструирован?

J>>Тут позовется конструктор копирования, у которого в параметре будет ссылка, указывающая на несуществующий объект — UB при попытке использования.

К>То есть,

К>
К>class Foo
К>{
К>    .....
К>    Foo()
К>    {
К>        Foo copy (*this); // UB?
К>    }
К>    .....
К>};
К>


Зависит от того, как написан конструктор копирования. В общем случае — UB. Не UB — только если конструктор копирования (почти) никак не использует свой аргумент.

Дело в том, что жизнь объекта начинается только после того, как отыграл конструктор (и заканчивается с началом работы деструктора) — см. соответствующую главу Object Lifetime.



Другое дело, что оно не очень понятно как должно работать в самом конструкторе/деструкторе, потому что они являются методами, а в них любое образение к члену x трактуется как (*this).x.
При это запрещено для неживого еще объекта дергать его за члены:

If the object will be or was of a non-POD class type, the program has
undefined behavior if:
— the pointer is used to access a non-static data member or call a non-static member function of the object

Что, по идее, верно и внутри конструктора и деструктора, по крайней мере, я не нашел обратного, хотя долго искал.
Получается, что к членам нельзя обращаться внутри конструктора и деструктора, что явная лажа, так что либо я не доглядел явное разрешение, либо его действительно нет (американцы, кстати, выкатили соответствующий дефект-репорт, но он не обсуждался еще: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#793.


В любом случае, к самому объекту как к целому обращаться нельзя, пока он целиком не сконструирован.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: паттерн "Мюнхгаузен"
От: Alexander G Украина  
Дата: 03.09.09 09:35
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Кстати, можно записать вот такой кошмар

                    throw
                    (
                        (t>1)
                        ?
                            (
                                std::cout << "throwing X()...",
                                throw X(),
                                Y()
                            )
                        :
                            Y()
                    ),
                    123

можно короче
Автор: Андрей Тарасевич
Дата: 30.04.09
Русский военный корабль идёт ко дну!
Re: паттерн "Мюнхгаузен"
От: Pzz Россия https://github.com/alexpevzner
Дата: 03.09.09 14:25
Оценка:
Здравствуйте, Rostislav_Pro, Вы писали:

R_P>В связи с этим был придуман (чисто чтоб поржать) подход, позволяющий исправить кривизну его рук:


R_P>
R_P>class FatalException
R_P>{
R_P>public:
R_P>  FatalException()
R_P>  {
R_P>    throw *this; // :)
R_P>  }
R_P>};
R_P>


Ну строго говоря, вы бросаете до конца не сконструированное исключение. Я бы не стал рассчитывать на то, что это всегда будет работать
Re[2]: паттерн "Мюнхгаузен"
От: Alexander G Украина  
Дата: 03.09.09 14:37
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Ну строго говоря, вы бросаете до конца не сконструированное исключение. Я бы не стал рассчитывать на то, что это всегда будет работать


Бросается копия никогда не конструируемого до конца объекта, но сама копия-то до конца сконструированая
Русский военный корабль идёт ко дну!
Re[3]: паттерн "Мюнхгаузен"
От: jazzer Россия Skype: enerjazzer
Дата: 03.09.09 14:43
Оценка:
Здравствуйте, Alexander G, Вы писали:

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


Pzz>>Ну строго говоря, вы бросаете до конца не сконструированное исключение. Я бы не стал рассчитывать на то, что это всегда будет работать


AG>Бросается копия никогда не конструируемого до конца объекта, но сама копия-то до конца сконструированая


Если не считать того, что копия конструируется из несконструированного объекта, что есть UB
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: паттерн "Мюнхгаузен"
От: Feonyf  
Дата: 04.09.09 04:21
Оценка:
Такой паттерн уже есть или его сами придумали ? М.б. его в википедию занести ?
Моя строка построения буста:
.\bjam link=static threading=multi runtime-link=static -j %NUMBER_OF_PROCESSORS% --with-filesystem --with-thread --with-date_time address-model=64
Re[7]: паттерн "Мюнхгаузен"
От: anonim_44ax  
Дата: 04.09.09 08:34
Оценка: -1 :)
К>Из деструктора можно не заморачиваться с throw *this, а тупо писать там terminate(). Ибо, чего уж.
Неправда! terminate() будет только если такой деструктор будет вызван во время раскрутки стека вызванного другим исключением. И хотя подобная техника очень "плохо пахнет", думаю вполне можно бросать исключение из деструктора, который по мнению программиста не может быть вызван во время раскрутки стека :-Р
Re[7]: паттерн "Мюнхгаузен"
От: remark Россия http://www.1024cores.net/
Дата: 04.09.09 08:43
Оценка:
Здравствуйте, jazzer, Вы писали:

J>В любом случае, к самому объекту как к целому обращаться нельзя, пока он целиком не сконструирован.


По-моему, тут всё нормально:

12.6.2/9
Member functions (including virtual member functions, 10.3) can be called for an object under construction.
Similarly, an object under construction can be the operand of the typeid operator (5.2.8) or of a dynamic_-
cast (5.2.7). However, if these operations are performed in a ctor-initializer (or in a function called directly
or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the result
of the operation is undefined.
[ Example:

class A {
public:
  A(int);
};

class B : public A {
  int j;
public:
  int f();
  B() : A(f()), // undefined: calls member function
                // but base A not yet initialized
  j(f()) { } // well-defined: bases are all initialized
};


—end example ]


Дальше:

12.7/1
For an object with a non-trivial constructor, referring to any non-static member or base
class of the object before the constructor begins execution results in undefined behavior. For an object with
a non-trivial destructor, referring to any non-static member or base class of the object after the destructor
finishes execution results in undefined behavior.


Т.е. lifitime-то начинается после завершения работы конструктора. Но фактически после начала выполнения тела конструктора с объектом можно делать всё, что и со сконструированным. По-моему, логично.

з.ы. я смотрю на N2798, драфт от 10/2008. Возможно он отличается от C++03, но я уверен, что в эту часть не было намерения вносить какие-либо принципиальные изменения, исключительно правки формулировок.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[8]: паттерн "Мюнхгаузен"
От: jazzer Россия Skype: enerjazzer
Дата: 04.09.09 11:05
Оценка:
Здравствуйте, remark, Вы писали:

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


J>>В любом случае, к самому объекту как к целому обращаться нельзя, пока он целиком не сконструирован.


R>По-моему, тут всё нормально:


R>Т.е. lifitime-то начинается после завершения работы конструктора. Но фактически после начала выполнения тела конструктора с объектом можно делать всё, что и со сконструированным. По-моему, логично.


Не с ним, а с его членами и сконструированными подобъектами (именно потому что они полностью сконструированы и их жизнь началась). С ним самим как с целым пока что ничего делать нельзя, потому что он еще неживой. Но тут оно вступает в противоречие с тем, что внутри членов-функций обращение к членам переписывается через (*this), и к этому lvalue должны применяться все ограничения про время жизни, запрещающие обращение к членам.

R>з.ы. я смотрю на N2798, драфт от 10/2008. Возможно он отличается от C++03, но я уверен, что в эту часть не было намерения вносить какие-либо принципиальные изменения, исключительно правки формулировок.


Да понятно, что имеется в виду, просто текущая формулировка, имхо, противоречит с тем, что написано про время жизни и ограничения на использование. Это и надо поменять (главу про время жизни, добавить специальную оговорку про то, что обращение к сконструированным членам разрешается, или что-то вроде того). Суть в любом случае остается той же.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: паттерн "Мюнхгаузен"
От: Кодт Россия  
Дата: 04.09.09 11:25
Оценка: :)
Здравствуйте, Feonyf, Вы писали:

F>Такой паттерн уже есть или его сами придумали ? М.б. его в википедию занести ?


Конечно, надо занести! Рядом с Пабликом Морозовым.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[9]: паттерн "Мюнхгаузен"
От: remark Россия http://www.1024cores.net/
Дата: 04.09.09 11:57
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Не с ним, а с его членами и сконструированными подобъектами (именно потому что они полностью сконструированы и их жизнь началась). С ним самим как с целым пока что ничего делать нельзя, потому что он еще неживой. Но тут оно вступает в противоречие с тем, что внутри членов-функций обращение к членам переписывается через (*this), и к этому lvalue должны применяться все ограничения про время жизни, запрещающие обращение к членам.


R>>з.ы. я смотрю на N2798, драфт от 10/2008. Возможно он отличается от C++03, но я уверен, что в эту часть не было намерения вносить какие-либо принципиальные изменения, исключительно правки формулировок.


J>Да понятно, что имеется в виду, просто текущая формулировка, имхо, противоречит с тем, что написано про время жизни и ограничения на использование. Это и надо поменять (главу про время жизни, добавить специальную оговорку про то, что обращение к сконструированным членам разрешается, или что-то вроде того). Суть в любом случае остается той же.


Тут именно про сам объект говорится, а не про члены. И функции у него можно вызывать и typeid и dynamic_cast можно.
12.6.2/9
Member functions (including virtual member functions, 10.3) can be called for an object under construction.
Similarly, an object under construction can be the operand of the typeid operator (5.2.8) or of a dynamic_-
cast (5.2.7). However, if these operations are performed in a ctor-initializer (or in a function called directly
or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the result
of the operation is undefined.




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[9]: паттерн "Мюнхгаузен"
От: MasterZiv СССР  
Дата: 04.09.09 14:28
Оценка: +1
jazzer wrote:

> R>Т.е. lifitime-то начинается после завершения работы конструктора. Но

> фактически после начала выполнения тела конструктора с объектом можно
> делать всё, что и со сконструированным. По-моему, логично.
>
> Не с ним, а с его членами и сконструированными подобъектами (именно
> потому что они полностью сконструированы и их жизнь началась). С ним
> самим как с целым пока что ничего делать нельзя, потому что он еще
> неживой.

Ну по идее-то код конструктора (внутри скобок) == это уже пользовательский
код, не системный. Только программист знает, какое состояние объекта
у него валидное, а какое -- невалидное, соответственно он может написать
так, чтобы наш нещастный THROW был бы в том месте, где уже всё валидно,
например, в самом конце, перед скобкой. Ведь компилятор более ничего
уже не сгенерирует, никакого кода не будет (рассматриваем естественно
ситуацию БЕЗ НАСЛЕДНИКОВ, т.е. финальный класс).

Это -- если просто "по понятиям", без стандартов и формализма.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: паттерн "Мюнхгаузен"
От: Vzhyk  
Дата: 04.09.09 14:50
Оценка:
Feonyf пишет:
>
>
> Такой паттерн уже есть или его сами придумали ? М.б. его в википедию
> занести ?

Сами, сами.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: паттерн "Мюнхгаузен"
От: Vamp Россия  
Дата: 04.09.09 15:40
Оценка:
К>Конечно, надо занести! Рядом с Пабликом Морозовым.
Я только так и не понял, почему Мюнхгаузен? Тот таскал себя за косичку из болота, и летал на ядре — вроде, ничего не применимо?
Да здравствует мыло душистое и веревка пушистая.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.