Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: исключения  (Прочитано 18298 раз)
0 Пользователей и 3 Гостей смотрят эту тему.
KurT
Гость
« : 16-03-2004 00:13 » 

Код:
#include <iostream.h>

class CErrors{
public:
virtual void PrintError()=0;
};

class COutMemory: public CError{
public:
virtual void PrintError() {cout<<"COutMemory";}
}

class COutRange: public CError{
public:
virtual void PrintError() {cout<<"COutRange";}
};

void Func(){
throw COutRange();
}

int main(){
try{
Func();
}
catch(CError& error){
error.PrintError();
}
return 0;
}
Объясните, почему в строке catch(CError& error) должна быть ссылка, а не указатель, с ним происходит ошибка, ведь ссылка- синоним данного, а полиформизм делается через указатели.
« Последнее редактирование: 25-11-2007 13:12 от Алексей1153++ » Записан
Serega
Гость
« Ответ #1 : 16-03-2004 07:31 » 

Потому что ты выбрасываешь ссылку, выбрасывай указатель и лови указатель
Код:
throw new COutRange();
Код:
catch(CErrors* err)
{
    err->PrintError();
    delete err;
}
« Последнее редактирование: 25-11-2007 13:13 от Алексей1153++ » Записан
KurT
Гость
« Ответ #2 : 16-03-2004 09:37 » 

Ага, спасибо, теперь объясни, почему там ссыслка работает. Ведь код:
Код:
CErrors& error=COutMemory();
не работает, ведь ссылка постоянно ссылается и на адрес error и её переназначить нельзя ,а в исключении всё ок, в чём дело может вопросы глупые, я сразу извеняюсь
« Последнее редактирование: 25-11-2007 13:14 от Алексей1153++ » Записан
Anonymous
Гость
« Ответ #3 : 16-03-2004 11:38 » new

Цитата: KurT
Объясните, почему в строке catch(CError& error) должна быть ссылка, а не указатель


Может быть и копия объекта.

для твоего случая код:

int main(){
   try{
      Func();
   }
   catch(CError error){
      error.PrintError();
   }
   return 0;
}

Ошибка у тебя может получится тк временный объект в

void Func(){
   throw COutRange();
}

уже наверно не существует, а ты требуешь его адрес.

Делай лучше как Serega говорит. Это чисто, просто, понятно.
Записан
KurT
Гость
« Ответ #4 : 16-03-2004 11:41 » 

Тот код, который я привёл работает, я хочу знать почему?
Записан
Anchorite
Гость
« Ответ #5 : 16-03-2004 18:08 » 

Потому что ссылка на самом деле это авторазыменовывающийся указатель.
Записан
NetRaider
Гость
« Ответ #6 : 17-03-2004 01:34 » 

Цитата

Объясните, почему в строке catch(CError& error) должна быть ссылка, а не указатель, с ним происходит ошибка, ведь ссылка- синоним данного, а полиформизм делается через указатели.


Может быть одно из трех:

1. catch(CError& error)
2. catch(CError error)
3. catch(CError* error)

Но, во втором случае происходит срезание полиморфных объектов(и лишнее копирование), а в 3 не совсем понятно, кто должен исключения удалять.
Самый оптимальный вариант - 1. И любые изменения в объекте сохраняются при его дальнейшей обработке.

Цитата

Тот код, который я привёл работает, я хочу знать почему?


Цитата

Ошибка у тебя может получится тк временный объект в

void Func(){
throw COutRange();
}

уже наверно не существует, а ты требуешь его адрес.


Время жизни объектов исключений выброшенных по ссылке отлично от автоматических переменных.
Записан
Red Line
Гость
« Ответ #7 : 17-03-2004 07:02 » 

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

Цитата
Может быть одно из трех:

1. catch(CError& error)
2. catch(CError error)
3. catch(CError* error)

3)
Код:
throw new COutOfMemory();

 Еслия правильно понял, здесь происходит   создание экземпляра класса COutOfMemory а указателем на него будет проинициализированна переменная error. Объект создан, конструктор отбработал... значит после использования объекта надо его удалить. Т.е в секции catch(CError error) нужно вызвать деструктор для разрушения объекта и освобождения занимаемой им памяти.
Т.е вот так:

Код:
catch(CError* error)
{
   error->ShowError();
   delete error;
}

Я правильно понял или нет?

2) Ссылка на объект - это авторазименовывющийся указатель, т.е его использование избавляет программиста от применения операции снятия ссылки при написании кода. Т.е по сути то же самое что и обычный указатель, только работь проще. Здесь я правильно понял? Если да, то вариант 2) ничем по идее не должен отличаться от 3)

Код:
throw COutOfMemory();

...
...
...

catch(CError& error)
{
   error.ShowError();
   А кто тогда будет удалять объект?
}

Насколько я понял, если мы применяем указатель или ссылку копируется только она, а если так:
Код:
catch(CError error)
{
   error.ShowError();
}

то в стек заталкивается весь объект целиком т.е происходит копирование по полям , и получается что мы имеем копию объекта - т.е их уже два что ли, кто всё это должен освобождать.

Это моё виденье и наверняка ошибочное Улыбаюсь
Буду очень благодарен всем кто поможет разобрать по косточкам все эти три случая- очень хочется понять!

Заранее благодарен!
« Последнее редактирование: 25-11-2007 13:16 от Алексей1153++ » Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #8 : 18-03-2004 14:17 » 

ту все предельно прозрачно....

Цитата
Может быть одно из трех:

1. catch(CError& error)
2. catch(CError error)
3. catch(CError* error)
начнем c 1 если ты пишешь так
Код:
throw COutOfMemory(); 
...
catch(CError& error)
{
   error.ShowError();
}
то объект созданный здесь (вот таким образом throw COutOfMemory(); ) стековый и уничтожится САМ при выходе его из области видимость (т.е. в нашем примере после закрывающейся фигурной скобки после вызова error.ShowError(); ) и все будет хорошо

если рассмотреть второй вариант
Код:
throw COutOfMemory(); 
...
catch(CErrors error)
{
   error.ShowError();
}
то тут сначала создается на стеке объект типа COutOfMemory (вот туточки создается throw COutOfMemory(); ), при попадании в catch создается НОВЫЙ объект типа ммммммм МИНУТОЧКУ!!! так как класс CErrors АБСТРАКТНЫЙ!!!!то это
Код:
throw COutOfMemory(); 
...
catch(CErrors error)
{
   error.ShowError();
}
вообще компилиться не будет. Теперь чтобы све прояснить предположим что CErrors объявлен так
Код:
class CErrors{
public:
   virtual void PrintError() {}
};
тогда в catch происходит создание стекового объекта типа CErrors (с вызовом копирующего конструктора) и естьественно происходит срезание начального объекта  (напомню он был типа COutOfMemory) :twisted: , затем опять после вызова error.ShowError(); после закрытия } удаляется САМ временный (стековый) объект типа CErrors, а потом опять же САМ удаляется стековый объест типа COutOfMemory. И опять таки все у нас с память ю хорошо (чего нельзя сказать о логике функционирования  :twisted:  потому как мы расчитывали на то что при вызове error.ShowError(); будет выведено сообщение о конкретной ошибке)

ну и наконец третий вариант
Код:
throw new COutOfMemory(); 
...
catch(CErrors * error)
{
   error->ShowError();
   delete error;
}
тут у нас для начала создаетя в КУЧЕ!!!! объект типа COutOfMemory, далее  мы бросаемся этим самым объектом Ага потом ловим его и тут уже естественно надо его замочить Отлично потому как память отожрана.

3 вариант самый дорогой потому как new и delete достаточно медленно работают
2 вариант потенциально опасен (как и в нашем случае)
1 вариант наиболее подходящий для таких случаев

кажись все Отлично
« Последнее редактирование: 25-11-2007 13:19 от Алексей1153++ » Записан

С уважением Lapulya
Red Line
Гость
« Ответ #9 : 18-03-2004 15:59 » 

lapulya,

Класс COutOfMemory является производным от CError. Я не знаком с термином "срезание объекта", но судя по всему ты имеешь ввиду процедуру приведения типа указателя производного класса к типу указателя на бозовый класс. Благодаря этому через этот указатель будет виден только фрагмент базового класса, а фрагмент производного класса окажется невиден. Т.е вот так:

Код:
 static_cast <CError*> (COutOfMemory*);

Если я правильно тебя понял это и обозначает термин "срезание". Если да, то и в этом случае:

Цитата
начнем c 1 если ты пишешь так
Код:
throw COutOfMemory();
...
catch(CError& error)
{
   error.ShowError();
 }

объект созданный здесь (вот таким образом throw COutOfMemory(); ) стековый и уничтожится САМ при выходе его из области видимость (т.е. в нашем примере после закрывающейся фигурной скобки после вызова error.ShowError(); ) и все будет хорошо

(по логике), то же должно происходить срезание. Бросается потомок, а ловится то предок...  Так или нет?
 
Продолжаю размышление Отлично

Фраза "пападает в catch()" означает, что указателем на созданый объект инициализируется переменная error в блоке catch. Областью видимости этой переменной и является этот самый блок catch(..){}. При выходе из блока catch(...) стековый объект уничтожается автоматически, значит вызов деструктора не понадобится.
Правильно я понял?

Код:
throw COutOfMemory(); 
...
catch(CErrors error)
{
   error.ShowError();
}

Тут не много другая история...
Сначала создаётся объект-исключение ( throw COutOfMemory(); ). Т.к в блоке catch объявлена не ссылка и не указатель, а именно переменна с типом класс, то происходит создание ещё одного объекта, но на этот раз базового класса. Таким образом в стеке уже два объекта.  Далее происходит срезание объекта производного класса (того которым бросались тут - throw COutOfMemory(); ) и копирование его при помощи конструктора копирования в объект который был создан тут catch(CErrors error) ... Область видимости этого объекта - блок catch(...) - это ясно. Т.е когда будет выполнен выход из блока catch(...) то этот экземпляр будет автоматически разрушен вызовом его деструктора, - а какая область видимости будет у объекта созданного throw COutOfMemory(); ? - сколько он будет висеть в стеке? Предполагаю, что до тех пор, пок не будет выполнено завершение подпрограммы которя бросала исключение.

Проясни этот момент пожалуйста.

И последнее:

Цитата
ну и наконец третий вариант
Код:
throw new COutOfMemory();
...
catch(CErrors * error)
{
   error->ShowError();
   delete error;
}

тут у нас для начала создаетя в КУЧЕ!!!! объект типа COutOfMemory, далее мы бросаемся этим самым объектом  потом ловим его и тут уже естественно надо его замочить  потому как память отожрана.

Я думаю, что в этом случае, вместо
Цитата
бросаемся этим самым объектом

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

Заранее благодарен!
« Последнее редактирование: 25-11-2007 13:21 от Алексей1153++ » Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #10 : 19-03-2004 13:12 » 

Для на чала надо выяснить один принципиальный вопрос из-за которого возможна полная лажа в дискуссии, так вот собственно сам вопрос в твоем примере
Код:
#include <iostream.h> 

class CErrors{
public:
virtual void PrintError()=0;
};

class COutMemory: public CError{
public:
virtual void PrintError() {cout<<"COutMemory";}
}

class COutRange: public CError{
public:
virtual void PrintError() {cout<<"COutRange";}
};

void Func(){
throw COutRange();
}

int main(){
try{
Func();
}
catch(CError& error){
error.PrintError();
}
return 0;
}
НЕТ сласса CError!!! если это просто опечатка и CErrors = CError то продолжаем разговор...
ты писал
Цитата
Класс COutOfMemory является производным от CError. Я не знаком с термином "срезание объекта", но судя по всему ты имеешь ввиду процедуру приведения типа указателя производного класса к типу указателя на бозовый класс. Благодаря этому через этот указатель будет виден только фрагмент базового класса, а фрагмент производного класса окажется невиден. Т.е вот так:
Код:
static_cast <CError*> (COutOfMemory*);

Если я правильно тебя понял это и обозначает термин "срезание"...
Нет ты понял не правильно, срезание объекта это следующее (кстати при использовании указателей или ссылок срезания полиморфных объектов НЕ происходит, оно и понятно веть имея поинтер на базовый класс и вызывая виртуальную функцию... вызовется функция того объекта который реально был создан, т.е. если был создан объект производного класс то и вызовется функция производного класса (еще раз обращу внимание это при условии что поинтер то был на БАЗОВЫЙ) - это просто описание работы виртуальных функций), продолжим про срезание... так вот .. этот код
Код:
throw COutOfMemory(); 
...
catch(CErrors error)
{
error.ShowError();
}
эквивалентен следующему В ПЛАНЕ СРЕЗАНИЯ (а не времени жизни объектов)

Код:
COutOfMemory outOfMemory(); 
CError error(outOfMemory); // вот здесь и происходит срезание т.к. объект error
              // имеет тип CError и ничего об COutOfMemory не знает в том числе
              // и то что функция ShowError() объеска error никакого сообщения
              //НЕ выдает, отсюда и термин срезание... т.е. мы срезали объект
              // с типом COutOfMemory (и функционалом объекта типа COutOfMemory),
              // до типа CError (и соответственно функционалом объекта типа CError)
...
catch(CErrors  &  error) // здесь ссылка для того чтобы не создавать ЕЩЕ один
                                    // временнный объект
{
error.ShowError();
}
идем дальше
Цитата
Код:
throw COutOfMemory(); 
...
catch(CErrors error)
{
error.ShowError();
}
Тут не много другая история...
Сначала создаётся объект-исключение ( throw COutOfMemory(); ). Т.к в блоке catch объявлена не ссылка и не указатель, а именно переменна с типом класс, то происходит создание ещё одного объекта, но на этот раз базового класса. Таким образом в стеке уже два объекта.
Абсолютно верно, я же именно это и написал вот смотри
Цитата
если рассмотреть второй вариант
Код:
throw COutOfMemory(); 
...
catch(CErrors error)
{
error.ShowError();
}
то тут сначала создается на стеке объект типа COutOfMemory (вот туточки создается throw COutOfMemory(); ) ......
и далее
Цитата
.......
тогда в catch происходит создание стекового объекта типа CErrors (с вызовом копирующего конструктора)
.......

Это
Цитата
Далее происходит срезание объекта производного класса (того которым бросались тут - throw COutOfMemory(); ) и копирование его при помощи конструктора копирования в объект который был создан тут catch(CErrors error) ... Область видимости этого объекта - блок catch(...) - это ясно. Т.е когда будет выполнен выход из блока catch(...) то этот экземпляр будет автоматически разрушен вызовом его деструктора

тоже верно я и об этом написал смотри мой предыдущий ответ, а теперь по поводу этого
Цитата
а какая область видимости будет у объекта созданного throw COutOfMemory(); ? - сколько он будет висеть в стеке? Предполагаю, что до тех пор, пок не будет выполнено завершение подпрограммы которя бросала исключение.

тоже не верная догадка, вот смотри это
throw COutOfMemory();
эквивалентно (в плане жизни объектка) следующему
printf(std::string("bubu").c_str());
спрашивается как же долго будет жить стековый объект типа std::string, а ответ такой, ооочень не долго и по выполнению функции printf он уничтожится, то же самое и утебя после обработки исключения т.е. вот этого
Код:
{
error.ShowError();
}
т.е. после выполнения этого блока сначала уничножится объект типа CError, а потом сразу за ним уничножится объект типа COutOfMemory,кстати я и об этом писал вот
Цитата
...
затем опять после вызова error.ShowError(); после закрытия } удаляется САМ временный (стековый) объект типа CErrors, а потом опять же САМ удаляется стековый объест типа COutOfMemory
...

по поводу этого
Цитата
И последнее:
Цитата
ну и наконец третий вариант
Код:
throw new COutOfMemory(); 
...
catch(CErrors * error)
{
error->ShowError();
delete error;
}

тут у нас для начала создаетя в КУЧЕ!!!! объект типа COutOfMemory, далее мы бросаемся этим самым объектом потом ловим его и тут уже естественно надо его замочить потому как память отожрана.
Я думаю, что в этом случае, вместо
Цитата
бросаемся этим самым объектом
правильно будет говорить:
"бросаемся указателем на этот самый объект"
могу сказать следующее, что не знаю как правильно сказать (объект или указатель) но смысл был именно в этом
« Последнее редактирование: 25-11-2007 13:28 от Алексей1153++ » Записан

С уважением Lapulya
Red Line
Гость
« Ответ #11 : 22-03-2004 14:41 » 

lapulya, я просто повторяю сказанное тобой, но "своими словами" !Просто таким образом мне легче уяснить, что и где я не так понял Отлично Т.е ты читаешь и говоришь - да верно, или нет - ты не прав. По моему здорово получилось Ага  Тем не менее твой последний пост

Цитата
Нет ты понял не правильно, срезание объекта это следующее (кстати при использовании указателей или ссылок срезания полиморфных объектов НЕ происходит, оно и понятно веть имея поинтер на базовый класс и вызывая виртуальную функцию... вызовется функция того объекта который реально был создан, т.е. если был создан объект производного класс то и вызовется функция производного класса (еще раз обращу внимание это при условии что поинтер то был на БАЗОВЫЙ) - это просто описание работы виртуальных функций), продолжим про срезание... так вот .. этот код
Код:
throw COutOfMemory();
...
catch(CErrors error)
{
error.ShowError();
}

эквивалентен следующему В ПЛАНЕ СРЕЗАНИЯ (а не времени жизни объектов)
Код:
COutOfMemory outOfMemory();
CError error(outOfMemory); // вот здесь и происходит срезание т.к. объект error имеет тип CError и ничего об COutOfMemory не знает в том числе и то что функция ShowError() объеска error никакого сообщения НЕ выдает, отсюда и термин срезание... т.е. мы срезали объект с типом COutOfMemory (и функционалом объекта типа COutOfMemory), до типа CError (и соответственно функционалом объекта типа CError)
...
catch(CErrors  &  error) // здесь ссылка для того чтобы не создавать ЕЩЕ один временнный объект
{
error.ShowError();
}

заставил меня целых 12 часов заниматься собственным самообразованием  Жаль  (качал книжку по C++, читал... пробовал осмыслить). в общем вот как я понял срезание (ещё раз своими словами)...

1) throw new COutOfMemory();//здесь создаётся объект типа COutOfMemory (наследник CError)
...
...
...
catch ( 2) CError error)
{
    error.ShowError();
}//здесь разрушается объект, который был создан в 1) т.к происходит выход за пределы областьи видимости и вслед за ним разрушается объект созданный в 2) - по той же самой причине.

Т.к объект созданный в 1) имеет тип COutOfMemory (потомок CError), а объект созданый в блоке catch( 2) ...) имеет тип CError (базовый класс) то при копировании объекта происходит неминуемый вызов конструктора копирования объкта типа CError созданного в 2). Копирование объекта возможно только при помощи конструктора копирования который является обязательным для любого класса. В данном случае будет использован "дефолтовый конструктор копирования" класса CError. Цитирую тебя:

Цитата
этот код
Код:
throw COutOfMemory();
...
catch(CErrors error)
{
error.ShowError();
}

эквивалентен следующему В ПЛАНЕ СРЕЗАНИЯ (а не времени жизни объектов)
Код:
COutOfMemory outOfMemory();
CError error(outOfMemory); // вот здесь и происходит срезание т.к. объект error имеет тип CError и ничего об COutOfMemory не знает в том числе и то что функция ShowError() объеска error никакого сообщения НЕ выдает, отсюда и термин срезание... т.е. мы срезали объект с типом COutOfMemory (и функционалом объекта типа COutOfMemory), до типа CError (и соответственно функционалом объекта типа CError)
...
catch(CErrors  &  error) // здесь ссылка для того чтобы не создавать ЕЩЕ один временнный объект
{
error.ShowError();
}

Строка

Код:
CError error(outOfMemory); 

и есть вызов конструктора копирования, которому в качестве параметра передаётся ссылка (именно ссылка - иначе неизбежна рекурсия!) на объект, который он будет копирвать. В нашем случае это объект созданный тут 1) trow COutOfMemory().

Теперь самое интересное. Задача конструктора копирования сделать "фотографию" объекта перданного ему в качестве парметра по ссылке. Вся суть в том, что объект, который надо копировать имеет в памяти фрагменты, о которых конструктор копирования объекта типа CError ничего не знает. Получив ссылку (тип которой как мне кажется неявно приводится компилятором к типу указателя на объект базового класса) конструктор копирования объекта типа CError скопирует только ту часть от общего фрагмента памяти занимаемой объектом типа COutOfMemory о которой он знает. А если конкректно - только фрагмент памяти, соответствующий объекту базового класса. Т.о произойдет срезание той части фрагмента памяти, которая относится к потомку (часть функционала класса COutOfMemory). в общем если мы переопределим конструктор копирования так:

Код:
//Предок
class A
{
public:
    int x;
    int y;
 
    A(){x = 0; y = 0;}//конструктор умолчания
    A(const A& obj) //конструктор копирования, копирует те поля, о которых знает!
    {
       x = obj.x;
       y = obj.y;
     }
};

//Потомок
class B: public A
{
public:
    int z;
    B(){z = 0;}
};


int _tmain(int argc, _TCHAR* argv[])
{
B objB;//вызов конструктора умолчания класса потомка

//меняем значений полей потомка, чтобы видеть результат   копирования
objB.x = 1;
objB.y = 1;
objB.z = 1;//это поле будет обрезано, т.к его не видит конструктор копирования предка A
   
    A objA = objB; // Создание объекта-предка и копирование функционала из объекта-потомка.
               //В данном случае обрезается поле z класса потомка (B::z)
return 0;
}

то факт срезания будет виден в отладчике.

У-фф... Кажется всё... Правь Отлично
« Последнее редактирование: 25-11-2007 13:30 от Алексей1153++ » Записан
Kuzmich
Гость
« Ответ #12 : 23-03-2004 04:59 » 

Red Line, очень очень полезные выводы. Маладец.
Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #13 : 24-03-2004 13:19 » 

Цитата
заставил меня целых 12 часов заниматься собственным самообразованием  (качал книжку по C++, читал... пробовал осмыслить). в общем вот как я понял срезание (ещё раз своими словами)...

Код:
1) throw new COutOfMemory();//здесь создаётся объект типа COutOfMemory (наследник CError) 
...
...
...
catch ( 2) CError error)
{
error.ShowError();
}//
здесь разрушается объект, который был создан в 1) т.к происходит выход за пределы областьи видимости и вслед за ним разрушается объект созданный в 2) - по той же самой причине.
Если ты опять опечатался и вместо этого
Код:
throw  new  COutOfMemory();//здесь создаётся объект типа COutOfMemory 
хотел написать это
Код:
 throw COutOfMemory();//здесь создаётся объект типа COutOfMemory
то, в общем и целом, довольно коряво, но верно, если это не опечатка, то ты опять все напутал.... пиши будем разбираться
« Последнее редактирование: 25-11-2007 13:33 от Алексей1153++ » Записан

С уважением Lapulya
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #14 : 24-03-2004 13:23 » 

Цитата

Код:
1) throw new COutOfMemory();//здесь создаётся объект типа COutOfMemory (наследник CError)
...
...
...
catch ( 2) CError error)
{
error.ShowError();
}//
здесь разрушается объект, который был создан в 1) т.к происходит выход за пределы областьи видимости и вслед за ним разрушается объект созданный в 2) - по той же самой причине.

Да .. тут не верно .... сначала разрушается объект созданный в 2) а только потом объект созданный в 1) :!:
Записан

С уважением Lapulya
NetRaider
Гость
« Ответ #15 : 25-03-2004 01:40 » 

Цитата
throw COutOfMemory();
эквивалентно (в плане жизни объектка) следующему
printf(std::string("bubu").c_str());
спрашивается как же долго будет жить стековый объект типа std::string, а ответ такой, ооочень не долго и по выполнению функции printf он уничтожится

Не эквивалентно. Время жизни объекта типа std::string действительно ограничено концом полного выражения, а вот с объектом COutOfMemory ситуация другая(пример без наследования):

Код:
struct Error { /*...*/ };

void foo()
{
    throw Error();
}

int main()
{
    try
    {
        foo();
    }
    catch(Error& e)
    {

    }
}
Согласно стандарту throw-expression инициализирует временный объект, который существует так долго, пока выполняется обработчик, т.е. в данном случае оъект созданный выражением 'throw Error()' будет разрушен после выхода из блока 'catch'.

Другой пример:
Код:
int main()
{
    try
    {
        try
        {
            foo();
        }
        catch(Error& e) /*1*/
        {
    throw;
        }

    }
    catch(Error& e) /*2*/
    {
    }
}
Опять же, согласно стандарту если обработчик завершается оператором 'throw;' временный объект сохраняется до тех пор, пока не выполнится последний обработчик(/*2*/). Но, если немного переписать
Код:
/*...*/
        catch(Error& e) /*1*/
        {
    [b]throw e;[/b]
        }
/*...*/

То в этом блоке будет создан новый объект(он будет удален в блоке 2) посредством конструктора копирования, а старый(созданный в 'foo') будет удален.

Цитата
2) Ссылка на объект - это авторазименовывющийся указатель, т.е его использование избавляет программиста от применения опирации снятия ссылки при написании кода. Т.е по сути то же самое что и обычный указатель, только работь проще. Здесь я правильно понял? Если да, то вариант 2) ничем по идее не должен отличаться от 3)

Код:
 
throw COutOfMemory();

...
...
...

catch(CError& error)
{
   error.ShowError();
   А кто тогда будет удалять объект?
}

О том кто и когда будет удалять объект см. выше, а вот насчет того что 'Ссылка на объект - это авторазименовывющийся указатель' ты не прав.
« Последнее редактирование: 25-11-2007 13:35 от Алексей1153++ » Записан
Red Line
Гость
« Ответ #16 : 25-03-2004 07:56 » 

NetRaider,

Цитата

Опять же, согласно стандарту если обработчик завершается оператором 'throw;' временный объект сохраняется до тех пор, пока не выполнится последний обработчик(/*2*/). Но, если немного переписать
Код:

/*...*/
        catch(Error& e) /*1*/
        {
       throw e;
        }
/*...*/

То в этом блоке будет создан новый объект(он будет удален в блоке 2) посредством конструктора копирования, а старый(созданный в 'foo') будет удален.


Где можно посмотреть стандарт?
Что такое передача исключений по цепочке и необработанные исключения?
Как правильно проектировать классы обработки исключений?
И ещё очень важный для меня вопрос.
Если в Т.З на программу сказано, что в программе должна быть предусмотренна структурная обработка ошибок... Что значит фраза структурная обработка ошибок - SEH, обработку исключений в C++ или что-то другое.



Цитата

О том кто и когда будет удалять объект см. выше, а вот насчет того что 'Ссылка на объект - это авторазименовывющийся указатель' ты не прав.


Поясни подробней пожалуйста.
Записан
Kuzmich
Гость
« Ответ #17 : 25-03-2004 12:37 » 

Цитата

Если в Т.З на программу сказано, что в программе должна быть предусмотренна структурная обработка ошибок... Что значит фраза структурная обработка ошибок - SEH, обработку исключений в C++ или что-то другое.

SEH и исключения C++ разные вещи.
Записан
NetRaider
Гость
« Ответ #18 : 26-03-2004 01:27 » 

Цитата
Где можно посмотреть стандарт?
Где-то здесь на сайте был.

Цитата
Что такое передача исключений по цепочке и необработанные исключения?

Передача по цепочке - смотри пример:
Код:
#include <iostream>
#include <string>

class Error
{
std::string _msg;
public:

    Error(const char* s) | addMessage(s); }
    const char* getMessage() { return _msg.c_str(); }

    void addMessage(const char* s) {
        _msg.append(s);
        _msg.append("\n");
    }
};

void f1() | throw Error("f1()"); }

void f2()
{
    try
    {
        /*...*/
        f1();
        /*...*/
    }
    catch(Error& e)
    {
        e.addMessage("f2()");
        throw;
    }
}

void f3()
{
    try
    {
        /*...*/
        f2();
        /*...*/
    }
    catch(Error& e)
    {
        e.addMessage("f3()");
        throw;
    }
}

int main()
{
    try
    {
        /*...*/
        f3();
        /*...*/
    }
    catch(Error& e)
    {
        std::cout << "Error in:\n" << e.getMessage();
    }

    return 0;
}

Необработанные исключения - это исключения которые не были перехвачены блоким 'catch' в течении работы программы. При этом вызывается функция 'std::terminate()' которая по умлчанию завершает программу. Используя ф-ю 'set_terminate' можно зарегистрировать свой обработчик таких ситуаций. Но узнать о типе возникшего исключения в нем невозможно. Смотри пример:
Код:
#include <iostream>
#include <exception>

void term_func()
{
    std::cout << "term_func()\n";
    exit(-1);
}

int main()
{
    set_terminate(term_func);

    try
    {
        //throw 1; 
        throw "1";
    }
    catch(const char*)
    { std::cout << "catch(const char*)\n";}

    return 0;
}


Если расскоментировать строку 'throw 1;', то будет выброшено исключение типа 'int', обработка которого не предусмотренна и соответственно будет вызвана 'term_func', зарегистрированная в качестве обработчика таких ситуаций.

Цитата
Как правильно проектировать классы обработки исключений?

Например, посмотри иерархию исключений в stl.

Цитата
Цитата
... а вот насчет того что 'Ссылка на объект - это авторазименовывющийся указатель' ты не прав.


Поясни подробней пожалуйста.

Основные отличия между ссылкой и указателем:

1. Ссылка в отличии от указателя влияет на время жизни временных объектов.
2. Нельзя присвоить ссылке новое значение. Операция присваивания, вызванная для ссылки, означает присваивание объекту, к которому она была привязана.
3. Не бывает ссылки на 0, а также массива ссылок, указателей на ссылку и ссылки на ссылку(для указателей возможны все перечисленные варианты).
« Последнее редактирование: 25-11-2007 13:36 от Алексей1153++ » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines