информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Spanning Tree Protocol: недокументированное применениеВсе любят мед
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
 Умер Никлаус Вирт 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
[C++] throw classname()... 29.11.01 03:07  Число просмотров: 1144
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
нее
это не ты тормозишь, а
> Microsoft (R) 32-bit C/C++ Optimizing Compiler Version
> 12.00.8804 for 80x86
:)

а посмотри в дебагере Disassemble Window
может чё прояснится
<programming>
[C++] throw classname()... 28.11.01 23:14  
Автор: Biasha <Бяша> Статус: Member
<"чистая" ссылка>
Я думал, что понимаю как throw работает, но, похоже, это не так.
Такой значит вопрос:
#include <iostream.h>
class ce
{
	char data[16];
public:
	ce() { cout << "ce\t" << this << endl; };
	ce(const ce &e) { cout << "cec\t" << this << endl; };
	~ce() { cout << "~ce\t" << this << endl; };
};
main()
{
	try
	{ throw ce(); }
	catch(ce &e)
	{ cout << "catch\t" << &e << endl; }
}

---
Ничего удивительного нет:
ce 0x0012FF5C
catch 0x0012FF5C
~ce 0x0012FF5C

Теперь закомментируем не используемый конструктор копирования
// ce(const ce &e) { cout << "cec\t" << this << endl; };

И что же мы видим:
ce 0x0012FF4C
catch 0x0012FF5C
~ce 0x0012FF5C

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

P.S.
Может это нормально, когда классы сами ходят?

P.P.S.
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
[C++] throw classname()... 29.11.01 03:07  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
нее
это не ты тормозишь, а
> Microsoft (R) 32-bit C/C++ Optimizing Compiler Version
> 12.00.8804 for 80x86
:)

а посмотри в дебагере Disassemble Window
может чё прояснится
[C++] throw classname()... 29.11.01 04:20  
Автор: Biasha <Бяша> Статус: Member
<"чистая" ссылка>
> нее
> это не ты тормозишь, а
Я тоже протормозил - я без ключа -GX cl.exe запускал.

> > Microsoft (R) 32-bit C/C++ Optimizing Compiler Version
> > 12.00.8804 for 80x86
> :)
Но это им не помогло:
ce 0x0012FF4C
~ce 0x0012FF4C
catch 0x0012FF5C
~ce 0x0012FF5C

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

Только не ясно: нафига он там? И почему его нет при явном задании его.
И что делать, если у меня, например, указатель где-то на этот класс...
хм... 29.11.01 21:50  
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
А у меня все как-то буднично и предсказуемо...

MSVC6 SP5

E:\+>cl -GX c.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

c.cpp
c.cpp(16) : warning C4508: 'main' : function should return a value; 'void' return type assumed
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:c.exe
c.obj

E:\+>c.exe
ce 0x0012FF5C
catch 0x0012FF5C
~ce 0x0012FF5C
хм... 29.11.01 23:18  
Автор: Biasha <Бяша> Статус: Member
<"чистая" ссылка>
> А у меня все как-то буднично и предсказуемо...
>
> MSVC6 SP5
Аналогично.

> ce 0x0012FF5C
> catch 0x0012FF5C
> ~ce 0x0012FF5C

Именно так и должно быть.
Причём в обоих случаях - при явно заданом конструкторе копирования и при закоментированном.
хм... 30.11.01 00:26  
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
> > А у меня все как-то буднично и предсказуемо...
> >
> > MSVC6 SP5
> Аналогично.
>
> > ce 0x0012FF5C
> > catch 0x0012FF5C
> > ~ce 0x0012FF5C
>
> Именно так и должно быть.
> Причём в обоих случаях - при явно заданом конструкторе
> копирования и при закоментированном.

Упс, я обманул - когда комментировал, не снял в соседнем окне файл с дебага, и он просто не слинковался. Сейчас перепроверил, картина совпадает с твоей.

Кстати, между catch(ce &e) и catch(ce e) разница такие есть - в последнем случае получается еще на одно копирование больше:

ce 0x0012FF40
~ce 0x0012FF40
catch 0x0012FF60
~ce 0x0012FF60
~ce 0x0012FF50
хм... 30.11.01 00:34  
Автор: dl <Dmitry Leonov>
Отредактировано 30.11.01 00:54  Количество правок: 1
<"чистая" ссылка>
В принципе, понять, почему происходит копирование, можно. Объект создается на стеке, при выходе за границу блока должен быть удален - тем более, если этот throw случился не тут же, а в какой-нибудь функции f, вызванной из try. Тут как раз претензий нет. А вот почему при наличии копирующего конструктора копирование исчезает, действительно непонятно.

Оставалась небольшая надежда на то, что компилятор шибко умный и даже при отключенной оптимизации что-то там пытается соптимизировать, но ситуация повторилась и при разнесении на три файла класса ce, функции, возбуждающей исключение, и функции - обработчика.

Что забавно, добиться исключения копирования можно и без копирующего конструктора - достаточно добавить в класс любую виртуальную функцию, либо сделать деструктор виртуальным. Причем добавление любого другого констроктора не помогает.
Возможно, при таком минимальном усложнении класса объект-исключение начинает храниться уже не в стеке, а где-то еще.
Спасибо всем, кажеться, можно на этом закончить 30.11.01 01:08  
Автор: Biasha <Бяша> Статус: Member
<"чистая" ссылка>
Кроме как смириться с тем, что даже при catch(ce &e) может произойти копирование об'єкта, похоже делать нечего.
Ну и правильно - нечего писать класс без конструктора копирования. :)
хм... 29.11.01 23:36  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
> Именно так и должно быть.
> Причём в обоих случаях - при явно заданом конструкторе
> копирования и при закоментированном.
не факт
никто этого не гарантирует
механизм исключений это всё-таки не просто вызов обработчика
ватком и борланд даже создают объект не в динамической памяти, а в одной из секций модуля
[C++] throw classname()... 29.11.01 09:15  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
> Только не ясно: нафига он там? И почему его нет при явном
> задании его.
... и почему не видно что он вызывается ? :)

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

мне самому стало интересно - щас попробую, потом напишу чё получилось :)
[C++] throw classname()... 29.11.01 09:41  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
без констр. копии:
ce 0x0012FF4C
~ce 0x0012FF4C
catch 0x0012FF5C
~ce 0x0012FF5C
обрати внимание - не видно второго вызова конструктора :)

вобщем МС просто копирует объект класса

попробуй сделай поле ce* p;
а в конструкторе p = this;

тогда увидишь, что в catch блоке p будет иметь старое значение

вот бы кто с другими компиляторами попробовал
а то лень ставить только из-за этого :)
[C++] throw classname()... 29.11.01 09:44  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
> без констр. копии:
...
> вобщем МС просто копирует объект класса

это я уже торможу - она так и должна делать без конструктора копии
[C++] throw classname()... 29.11.01 09:52  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
вобщем так получается:

если есть констр. копии, то объект не пересоздаётся

если нет констр. копии, то объект удаляется и создаётся новый просто копированием

по идее глюков кажется здесь нет
только странно оно как то всё :)
как всё у маздай :)
[C++] Немного поправлю: 29.11.01 12:35  
Автор: Biasha <Бяша> Статус: Member
Отредактировано 29.11.01 12:51  Количество правок: 3
<"чистая" ссылка>
Бывает явно заданный конструктор копирования, и конструктор копирования класса по умолчанию.
Конструктор копирования у класса есть всегда. Например, он вызывается дважды при вызывове функции типа CName func(CName name);.
К.к. по умолчанию - просто копирует все по очереди переменные-члены.
Чтобы не копировать об'єкт лишний раз, его передают по ссылке, как я и сделал (catch (ce &e)).

Так вот. Когда конструктор копирования задан явно - всё отлично, а когда явно он не задан (а значит при необходимости будет использован к.к. по умолчанию), то происходит копирование об'єкта куда-то. Само собою мы не видим на экране его вызова, так как в к.к по умолчанию нет вывода на экран текста, в отличие от нашего; мы можем понять, что он был вызван, только анализируя порядок вызова конструкторов/деструкторов, адреса об'єктов и содержимое переменных - всё указывает на наличие его вызова.

Вот и не понятно: чего это вдруг передаваемый по ссылке об'єкт понадобилось копировать. И почему этого не нужно делать при явно заданном к.к.

Да, было бы очень интересно другим компилятором попробовать. У меня нету тоже :(
Под С++Builder'ом 5 Interprise Suite получилось так 29.11.01 13:15  
Автор: Xan Статус: Незарегистрированный пользователь
<"чистая" ссылка>

> Да, было бы очень интересно другим компилятором
> попробовать. У меня нету тоже :(

ce 0012FF78
cec 00795362
~ce 0012FF78
catch 00795362
~ce 00795362

Убираем явный вызов КК
ce 0012FF78
~ce 0012FF78
catch 007953A2
~ce 007953A2

Теперь я не понимаю совсем 29.11.01 14:14  
Автор: Biasha <Бяша> Статус: Member
<"чистая" ссылка>
> > Да, было бы очень интересно другим компилятором
> > попробовать. У меня нету тоже :(
>
> ce 0012FF78
> cec 00795362
> ~ce 0012FF78
> catch 00795362
> ~ce 00795362
Зачем же вызвался cec... Ведь передача, кажется, по ссылке...
Если бы было catch(ce e), а не catch(ce &e), то так и должно было бы быть.
Может я ошибаюсь - нет разницы?

> Убираем явный вызов КК
> ce 0012FF78
> ~ce 0012FF78
> catch 007953A2
> ~ce 007953A2
Это меня уже не удивляет...


Теперь совсем не понятно:
Почему MS в случае явно определенного конструктора копирования не создавал временный об'єкт, а borland создаёт...
Теперь я не понимаю совсем 29.11.01 18:12  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
> > ce 0012FF78
> > cec 00795362
> > ~ce 0012FF78
> > catch 00795362
> > ~ce 00795362
> Зачем же вызвался cec... Ведь передача, кажется, по
> ссылке...
> Если бы было catch(ce e), а не catch(ce &e), то так и
> должно было бы быть.
> Может я ошибаюсь - нет разницы?

как я понимаю в throw создаётся временный локальный объект
когда мы выходим из блока try он уничтожается
когда мы доходим до блока catch ссылка была бы уже не правильной
поэтому создаётся копия объекта для блока catch

> Теперь совсем не понятно:
> Почему MS в случае явно определенного конструктора
> копирования не создавал временный об'єкт, а borland
> создаёт...
наверно мс попытался оптимизировать это дело
но почему только в одном случае ?
вот что Watcom сказал 29.11.01 18:24  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
1)
ce 0x12fe60
cec 0x40e608
~ce 0x12fe60
catch 0x40e608
~ce 0x40e608

2)
ce 0x12fe60
~ce 0x12fe60
catch 0x40e608
~ce 0x40e608

по моему всё логично
это мс что то мудрит
и ещё 29.11.01 18:42  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
только мс делает копию выброшенного объекта в стеке

ватком и борланд для этого заранее место оставляют
А вот что Страуструп пишет: 29.11.01 21:49  
Автор: Biasha <Бяша> Статус: Member
<"чистая" ссылка>
Совсем конкретно не нашёл, но

"Служебным является и слово catch. После него идет в скобках описание, которое используется аналогично описанию формальных параметров функции, а именно, в нем задается тип объектов, на которые рассчитан обработчик, и, возможно, имена параметров"
В функциях класс, переданый по ссылке не копируется.
Да и зачем его копировать.
Сас Страуструп у себя в примерах различает catch(ce &e) и catch(ce e). А тут выходит различия нет.
1  |  2 >>  »  




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach