powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / деструктор... catch...
25 сообщений из 37, страница 1 из 2
деструктор... catch...
    #38308146
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доброго времени суток.

1. В коде приведённого ниже метода main, переменной b я присваиваю новое значение после её инициализации. Поскольку переменная - это именованный участок памяти, то присвоение b (ссылке на этот участок) нового значения - это запись новых данных в этот именованный участок, т.е. перезапись существующего контента.

Согласно логу вывода (см. ниже) я вижу, что сразу после задания нового значения, происходит вызов его деструктора, хотя ещё не достигнута граница области видимости этой переменной. Я так понимаю, что компилятор C++ пытается вызвать деструктор ранее хранившегося по указанной ссылке объекта, однако делает это уже после того, как объект был перезаписан. В результате вызывается деструктор нового объекта и получается, что он создаётся и тут же уничтожается. Я правильно понимаю поведение?

2. В ходе выполнения программы, она аварийно завершается. Почему не срабатывают catch?

Исходный код
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
/*
test.cpp
© Andrey Bushman, 24/06/2013
Chapter 17.5.2
*/
//--------------------------------------------------------------------
#include "../std_lib_facilities.h"
//********************************************************************
namespace Bushman{
//--------------------------------------------------------------------
	class A
	// some class A
	{
	private:
		string n;
	public:
		A(const string& name): n(name){ cout 
			<< "A::A(const string& name): " << n << " constructor." 
			<< endl;}
		virtual ~A(){cout << "A::~A(): " << n << " destructor." 
			<< endl; }
		string name() const { return n;}
	};
//--------------------------------------------------------------------
	class B{
	private:
		A* a;
	public:
		B(const string& name):a(new A(name)){ cout 
			<< "B::B(const string& name): " << a->name() 
			<< " constructor." << endl; }
		virtual ~B(){cout << "B::~B(): " << a->name() << " destructor."
			<< endl; 
			delete a; }
		string name() const { return a->name();}
	};
//--------------------------------------------------------------------
	class C: public B{
	public:
		C(const string& name): B(name){ cout 
			<< "C::C(const string& name): " << B::name() 
			<< " constructor." << endl; }
		virtual ~C(){cout << "C::~C(): " << B::name() 
			<< " destructor." << endl; }
	};
}
//====================================================================
int main()
try{
	namespace B = Bushman;
	B::A* a = new B::A("Anton");
	delete a;
	cout << endl;
	
	B::B b("Boris");
	cout << "&b = " << &b << endl;
	
	b = B::B("Boris2");
	cout << "&b = " << &b << endl;
	cout << endl;
	
	B::C* c = new B::C("Ciprus");
	cout << endl;
	delete c;
}
catch(exception& e){
	cerr << e.what() << endl;
	return 1;
}
catch(...){
	cerr << "Unknown exception." << endl;
	return 2;
}



Результат
A::A(const string& name): Anton constructor.
A::~A(): Anton destructor.

A::A(const string& name): Boris constructor.
B::B(const string& name): Boris constructor.
&b = 00000000002CF630
A::A(const string& name): Boris2 constructor.
B::B(const string& name): Boris2 constructor.
B::~B(): Boris2 destructor.
A::~A(): Boris2 destructor.
&b = 00000000002CF630

A::A(const string& name): Ciprus constructor.
B::B(const string& name): Ciprus constructor.
C::C(const string& name): Ciprus constructor.

C::~C(): Ciprus destructor.
B::~B(): Ciprus destructor.
A::~A(): Ciprus destructor.
B::~B(): destructor.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308186
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositumя вижу, что сразу после задания нового значения, происходит вызов его
деструктора, хотя ещё не достигнута граница области видимости этой переменной.

Достигнута. Это деструктор временной переменной B::B, которая уничтожается сразу после
копирования её в b.
В твоём коде ошибка - не определён конструктор копирования для B, что приводит к затиранию
указателя на А без его освобождения.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308192
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Убрал неотносящийся к вопросу мусор (можно в следующий раз не загромождать код ?)

Код: plaintext
1.
2.
3.
4.
5.
&b = 00000000002CF630
B::B(const string& name): Boris constructor. вызван конструктор старого значения b
B::B(const string& name): Boris2 constructor.  вызван конструктор временного значения перед присвоением его в b 
B::~B(): Boris2 destructor. вызван деструктор старого значения b  перед присвоением
&b = 00000000002CF630
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308197
?
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
?
Гость
Compositum, откройте для себя временные объекты и конструктор копирования
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308198
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А, здесь ошибка у меня. В третей строке должно быть:
Код: plaintext
1.
B::~B(): Boris2 destructor. вызван деструктор  временного значения после присвоения


(Как Дмитрий выше написал)
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308237
_&lt;&gt;_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry Sibiryakov- не определён конструктор копирования для B

Точнее копирующий оператор присваивания
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308295
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_<>_Dimitry Sibiryakov- не определён конструктор копирования для B

Точнее копирующий оператор присваивания

Есть копирующий конструктор ( copy constructor ) и оператор присваивания (assignment operator) и в Cx11 есть ещё конструктор перемещения.

А понятия "копирующий оператор присваивания" не существует.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308306
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumСогласно логу вывода (см. ниже) я вижу, что сразу после задания нового значения, происходит вызов его деструктора, хотя ещё не достигнута граница области видимости этой переменной. Я так понимаю, что компилятор C++ пытается вызвать деструктор ранее хранившегося по указанной ссылке объекта, однако делает это уже после того, как объект был перезаписан. В результате вызывается деструктор нового объекта и получается, что он создаётся и тут же уничтожается. Я правильно понимаю поведение?


Неправильно.

Удаляется временный объект, созданный тут:
Код: plaintext
1.
b = B::B("Boris2");



Справа от присваивания стоит временный объект класса B::B, он создаётся, присваивается в b, а затем он должен уничтожится,
что и происходит.

Ты бы это сам понял, если бы печатал в своих трейсах ещё и идентификатор объекта, который создаётся или уничтожается (идентификатор объекта -- это в С++ его адрес).
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308317
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
до конструкторов копирования и копирующего присваивания я ещё не дочитал: я дочитываю 17-ю главу, а они в 18-й. :)
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308322
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

несколько замечаний.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
	class A
	// some class A
	{
	private:
		string n;
	public:
		A(const string& name): n(name){ cout 
			<< "A::A(const string& name): " << n << " constructor." 
			<< endl;}
		virtual ~A(){cout << "A::~A(): " << n << " destructor." 
			<< endl; }
		string name() const { return n;}
	};



Лучше
Код: plaintext
1.
const string& name() const { return n;}



Если данный объект доступен, то его член n также всегда доступен, что позволяет возвращать его значение по константной ссылке,
а не по значению. Это позволяет съэкономить на копировании объекта.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
	class B{
	private:
		A* a;
	public:
		B(const string& name):a(new A(name)){ cout 
			<< "B::B(const string& name): " << a->name() 
			<< " constructor." << endl; }
		virtual ~B(){cout << "B::~B(): " << a->name() << " destructor."
			<< endl; 
			delete a; }
		string name() const { return a->name();}
	};



Рассмотрим

Код: plaintext
1.
string name() const { return a->name();}



a - указатель на A. Он может быть невалидным. Если он невалидный, то его разименовывать нельзя,
и в теле надо проверять, что он невалидный и (видимо) выкидывать исключение.

Код: plaintext
1.
string name() const { if( a ) return a->name(); else throw someException(); }



Но если a валиден, то он всегда содержит n и может его вернуть по ссылке, т.о. это мы можем сделать и тут:

Код: plaintext
1.
const string& name() const { if( a ) return a->name(); else throw someException(); }
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308340
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivЕсли данный объект доступен, то его член n также всегда доступен, что позволяет возвращать его значение по константной ссылке,
а не по значению. Это позволяет съэкономить на копировании объекта.
Да, спасибо, это я упустил.
MasterZiva - указатель на A. Он может быть невалидным. Если он невалидный, то его разименовывать нельзя,
и в теле надо проверять, что он невалидный и (видимо) выкидывать исключение.
Да, я в курсе, но не делал проверки в этом примере, дабы сократить код. В реальном коде я, конечно же, буду выполнять проверку всех входящих параметров и проверку результата, прежде чем его возвращать.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308765
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,
catch не срабатывает, потому что у тебя не исключение происходит, а просто падает программа. Это не должно транслироваться в исключение, в MS C такой режим есть, но он не стандартнеый.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308792
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivCompositum,
catch не срабатывает, потому что у тебя не исключение происходит, а просто падает программа. Это не должно транслироваться в исключение, в MS C такой режим есть, но он не стандартнеый.То есть "по стандарту" бывают исключения а бывают "просто умерли"? Какие интересные стандарты.
Я всегда считал что исключения изначально были придуманы именно для того чтобы программы не падали.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308796
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivcatch не срабатывает, потому что у тебя не исключение происходит, а просто падает программа. Это не должно транслироваться в исключение, в MS C такой режим есть, но он не стандартный.
Честно говоря, я ожидал, что catch(...) должен был гарантированно отлавливать любую ситуацию, прошедшую мимо catch(exception& e). Как обычно отлавливают и обрабатывают подобные "падения"? У Стровструпа я перенял обозначенную выше конструкцию, но там не говорилось о том, что что-то может пролететь мимо кассы...
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308800
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumMasterZivcatch не срабатывает, потому что у тебя не исключение происходит, а просто падает программа. Это не должно транслироваться в исключение, в MS C такой режим есть, но он не стандартный.
Честно говоря, я ожидал, что catch(...) должен был гарантированно отлавливать любую ситуацию, прошедшую мимо catch(exception& e). Как обычно отлавливают и обрабатывают подобные "падения"? У Стровструпа я перенял обозначенную выше конструкцию, но там не говорилось о том, что что-то может пролететь мимо кассы...В идеале так и должно быть. В реальности все эти try{}catch отлавливают только то что было кем-то throw. Либо в самой программе, либо в одной из библиотечных функций. Не уверен было ли это сделано специально или получилось "как обычно".
Но для ловли реальных исключений в виндах есть отдельный механизм: Structured Exception Handling. Читай здесь: http://msdn.microsoft.com/en-us/library/ms680657(VS.85).aspx
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308802
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlНо для ловли реальных исключений в виндах есть отдельный механизм: Structured Exception Handling.
А какого-нибудь системно-независимого варианта нет? Чтобы не лепить директивы препроцессора для Windows\Linux...
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308808
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumWhite OwlНо для ловли реальных исключений в виндах есть отдельный механизм: Structured Exception Handling.
А какого-нибудь системно-независимого варианта нет? Чтобы не лепить директивы препроцессора для Windows\Linux...Нет, нету.
Но их собственно говоря всего два: В виндах есть SEH, в остальном мире signal(SIGSEGV).
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308887
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlТо есть "по стандарту" бывают исключения а бывают "просто умерли"?
Нет. По стандарту бывают исключения, как часть языка С++, бывают сигналы, как часть С, и бывают undefined behavior. Все четко и понятно расписано в каком случае что ожидать, или не ожидать (для UB).
Например, деление на 0 в рантайме - это UB. Результатом может быть все что угодно. И естественно нет стандартного способа обрабатывать то, что в стандарте объявлено как UB.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308889
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyWhite OwlТо есть "по стандарту" бывают исключения а бывают "просто умерли"?
Нет. По стандарту бывают исключения, как часть языка С++, бывают сигналы, как часть С, и бывают undefined behavior. Все четко и понятно расписано в каком случае что ожидать, или не ожидать (для UB).
Например, деление на 0 в рантайме - это UB. Результатом может быть все что угодно. И естественно нет стандартного способа обрабатывать то, что в стандарте объявлено как UB.И что мешает объявить все эти UB как какой-нибудь system_exception и отлавливать его в обычном catch()? И тогда не будет никаких UB вообще.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308890
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlИ что мешает объявить все эти UB как какой-нибудь system_exception и отлавливать его в обычном catch()? И тогда не будет никаких UB вообще.
Вы неверно понимаете суть UB.
В С/С++ UB объявляется то, что невозможно эффективно реализовать на большинстве поддерживаемых платформ.
Поэтому обработку любого из случаев UB невозможно сделать частью языка/станд. библиотеки, иначе бы надобности в самих UB не было.
То, что на некоторых платформах такая обработка возможна, ничего не меняет.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308904
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyWhite OwlИ что мешает объявить все эти UB как какой-нибудь system_exception и отлавливать его в обычном catch()? И тогда не будет никаких UB вообще.
Вы неверно понимаете суть UB.Правда? Ну объясните, в чем же эта сакральная суть? "Случилось деление на ноль, программа умерла - значит так хотели высшие силы, смиримся братья." Так что-ли?

Anatoly MoskovskyПоэтому обработку любого из случаев UB невозможно сделать частью языка/станд. библиотеки, иначе бы надобности в самих UB не было.
То, что на некоторых платформах такая обработка возможна, ничего не меняет.В UB надобности вообще никогда нет, на то они и U!
К тому-же, реализацию всех этих исключений которые сейчас отлавливаются только ОС и приводят к смерти приложения можно с легкостью сделать на сигналах (везде кроме виндов) и оформить это как отдельную библиотеку - расширение для stl. Ну не будет эта библиотека на винде работать - не она первая, не она последняя.

И вообще, когда я изобретаю язык - мне до лампочки насколько эффективно какая-то желаемая фича реализуется на большинстве поддерживаемых платформ. Поддерживается хоть как-то, хоть где-то и слава богу. Не поддерживается вообще нигде - не беда, сделаем через эмуляцию.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38308944
?
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
?
Гость
White OwlИ что мешает объявить все эти UB как какой-нибудь system_exception и отлавливать его в обычном catch()? И тогда не будет никаких UB вообще.Ну например то, что в какой-то системе в этом случае программа сразу убивается без шансов что либо сделать (как TerminateProcess или kill -9 в unix).
...
Рейтинг: 0 / 0
деструктор... catch...
    #38309145
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlНу объясните, в чем же эта сакральная суть?
В UB надобности вообще никогда нет
UB нужны для того чтобы дать компилятору возможность более эффективно реализовать остальной язык, те части, где нет UB.
Эффективность - это вообще основная причина, по которой С и С++ до сих пор живы.

White OwlИ вообще, когда я изобретаю язык
К счастью С и С++ изобретены и развиваются не вами :)
...
Рейтинг: 0 / 0
деструктор... catch...
    #38309296
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumMasterZivcatch не срабатывает, потому что у тебя не исключение происходит, а просто падает программа. Это не должно транслироваться в исключение, в MS C такой режим есть, но он не стандартный.
Честно говоря, я ожидал, что catch(...) должен был гарантированно отлавливать любую ситуацию, прошедшую мимо catch(exception& e). Как обычно отлавливают и обрабатывают подобные "падения"? У Стровструпа я перенял обозначенную выше конструкцию, но там не говорилось о том, что что-то может пролететь мимо кассы...


Значит ты ошибался.

Ведь у Страустрапа и обратное наверняка нигде не декларировалось.

В MSVC шном компиляторе есть поддержка SEH и интеграция его с обычными с++ исключениями, но не полная (часть функций SEH недоступна через exceptions).

Общего универсального механизма нет.
...
Рейтинг: 0 / 0
деструктор... catch...
    #38309319
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlAnatoly Moskovskyпропущено...

Нет. По стандарту бывают исключения, как часть языка С++, бывают сигналы, как часть С, и бывают undefined behavior. Все четко и понятно расписано в каком случае что ожидать, или не ожидать (для UB).
Например, деление на 0 в рантайме - это UB. Результатом может быть все что угодно. И естественно нет стандартного способа обрабатывать то, что в стандарте объявлено как UB.И что мешает объявить все эти UB как какой-нибудь system_exception и отлавливать его в обычном catch()? И тогда не будет никаких UB вообще.

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

Кстати если вспомнить какие-нибудь Dec (см эвм) или IBM (ес эвм), там ни исключений, ни сигналов вообще не было, если я не ошибаюсь. Если что — сразу с копыт и в мусорку, никаких разговоров.
...
Рейтинг: 0 / 0
25 сообщений из 37, страница 1 из 2
Форумы / C++ [игнор отключен] [закрыт для гостей] / деструктор... catch...
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]