throw в конструкторе?
От: slava_phirsov Россия  
Дата: 29.12.09 08:16
Оценка:
Доброго всем времени суток, читая уважаемого С.Майерса возник вот такой вопрос.

Во второй части эпохального труда "Effective C++", в правиле 26 дается пример класса с ограничением числа экземпляров, которое обеспечивается за счет генерации исключений в конструкторе, примерно вот так:

Foo::Foo()
{
    if (_num_instances >= NUM_INSTANCES_MAX)
        throw TooManyInstances();
}


Предполагается, что в случае, если будет сделана попытка создать слишком много экземпляров класса, возникшее исключение не позволит довести процесс до конца. Если исключение не будет перехвачено, то приложение просто вылетит, если будет перехвачено, но экземпляр Foo будет создаваться в стеке — за счет выравнивания стека выделенная для экземпляра память будет возвращена системе. Однако что будет в случае, когда экземпляр создается в куче, а исключение перехватывается? Перед вызовом конструктора будет вызван new и выделена память, в конструкторе будет сгенерировано исключение, вызывающий код его перехватит, а выделенная память — так и останется висеть, и приложение в принципе не может получить указатель на эту память и уж тем более освободить ее. Так? Или стандарт как-то эту ситуацию оговаривает особо? Или я чего-то недопонимаю?

Заранее благодарю за разъяснения.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re: throw в конструкторе?
От: Igore Россия  
Дата: 29.12.09 08:20
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

_>Предполагается, что в случае, если будет сделана попытка создать слишком много экземпляров класса, возникшее исключение не позволит довести процесс до конца. Если исключение не будет перехвачено, то приложение просто вылетит, если будет перехвачено, но экземпляр Foo будет создаваться в стеке — за счет выравнивания стека выделенная для экземпляра память будет возвращена системе. Однако что будет в случае, когда экземпляр создается в куче, а исключение перехватывается? Перед вызовом конструктора будет вызван new и выделена память, в конструкторе будет сгенерировано исключение, вызывающий код его перехватит, а выделенная память — так и останется висеть, и приложение в принципе не может получить указатель на эту память и уж тем более освободить ее. Так? Или стандарт как-то эту ситуацию оговаривает особо? Или я чего-то недопонимаю?


_>Заранее благодарю за разъяснения.


Объект не удалось сконструировать, значит память не выделена. Ничего освобождать не надо.
Re: throw в конструкторе?
От: remark Россия http://www.1024cores.net/
Дата: 29.12.09 08:21
Оценка: +3
Здравствуйте, slava_phirsov, Вы писали:

_>Перед вызовом конструктора будет вызван new и выделена память, в конструкторе будет сгенерировано исключение, вызывающий код его перехватит, а выделенная память — так и останется висеть, и приложение в принципе не может получить указатель на эту память и уж тем более освободить ее. Так? Или стандарт как-то эту ситуацию оговаривает особо? Или я чего-то недопонимаю?


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


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: throw в конструкторе?
От: slava_phirsov Россия  
Дата: 29.12.09 08:25
Оценка:
Здравствуйте, remark, Вы писали:

R>В таком случае память будет освобождена автоматически. Если из конструктора объекта вылетает исключение, то вызывается соответствующий delete.


Ссылку на пункт в стандарте дай, плиз, если помнишь. Не то чтобы я тебе совсем не доверял, но просто самому интересно лишний раз перечитать.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[3]: throw в конструкторе?
От: remark Россия http://www.1024cores.net/
Дата: 29.12.09 08:36
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

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


R>>В таком случае память будет освобождена автоматически. Если из конструктора объекта вылетает исключение, то вызывается соответствующий delete.


_>Ссылку на пункт в стандарте дай, плиз, если помнишь. Не то чтобы я тебе совсем не доверял, но просто самому интересно лишний раз перечитать.


Не помню. Должно быть там, где про new/delete для объектов.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: throw в конструкторе?
От: jazzer Россия Skype: enerjazzer
Дата: 29.12.09 08:43
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

_>за счет выравнивания стека выделенная для экземпляра память будет возвращена системе.

за счет чего-чего?

_>Или стандарт как-то эту ситуацию оговаривает особо?

Оговаривает. Память будет освобождена автоматически.
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]: throw в конструкторе?
От: jazzer Россия Skype: enerjazzer
Дата: 29.12.09 08:48
Оценка: 1 (1)
Здравствуйте, Igore, Вы писали:

I>Объект не удалось сконструировать, значит память не выделена. Ничего освобождать не надо.


Это не так.
Сначала выделяется память, потом в ней констурируется объект.
Если не получилось сконструировать — память освобождается автоматически (точнее, автоматически зовется deallocation function).
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: throw в конструкторе?
От: Alexander G Украина  
Дата: 29.12.09 08:52
Оценка:
Здравствуйте, slava_phirsov,

К уже сказанному можно добавить, что корректное освобождение памяти, выделенной new, при исключении из конструктора — это единственная причина, почему при написании своей версии оператора new следует написать и свою версию оператора delete. Компилятором неявно вызывается особая форма оператора delete только при исключении из конструктора, стейтмент delete p; — это деструктор и стандартный delete.
Русский военный корабль идёт ко дну!
Re[3]: throw в конструкторе?
От: Юрий Жмеренецкий ICQ 380412032
Дата: 29.12.09 08:57
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

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


R>>В таком случае память будет освобождена автоматически. Если из конструктора объекта вылетает исключение, то вызывается соответствующий delete.


_>Ссылку на пункт в стандарте дай, плиз, если помнишь. Не то чтобы я тебе совсем не доверял, но просто самому интересно лишний раз перечитать.


5.3.4/17
Re[2]: throw в конструкторе?
От: uzhas Ниоткуда  
Дата: 31.12.09 11:32
Оценка: 7 (1) :)
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, slava_phirsov,


AG>К уже сказанному можно добавить, что корректное освобождение памяти, выделенной new, при исключении из конструктора — это единственная причина, почему при написании своей версии оператора new следует написать и свою версию оператора delete. Компилятором неявно вызывается особая форма оператора delete только при исключении из конструктора, стейтмент delete p; — это деструктор и стандартный delete.


мне кажется, что вы сморозили чушь
рекомендую перечитать 5.3.4 (new) и 5.3.5 (delete)
в двух словах:
5.3.4.8:
A new-expression obtains storage for the object by calling an allocation function (3.7.3.1) If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function (3.7.3.2)

5.3.5.7
The delete-expression will call a deallocation function.

Allocation functions — это operator new(), operator new[]() причем implementation provides default definitions of the global allocation functions
Deallocation functions — это operator delete(), operator delete[]() причем implementation provides default definitions of the global deallocation functions

если написать ::new A(), то используется глобальная функция аллокации, если
new A(), то функция operator new() сначала ищется в скоупе A, затем в глобальном скоупе

вывод:
"при написании своей версии оператора new следует написать и свою версию оператора delete" для того, чтобы не было глюков и память очищалась правильно
Re[3]: throw в конструкторе?
От: Alexander G Украина  
Дата: 31.12.09 13:13
Оценка: 1 (1)
Здравствуйте, uzhas, Вы писали:

AG>>К уже сказанному можно добавить, что корректное освобождение памяти, выделенной new, при исключении из конструктора — это единственная причина, почему при написании своей версии оператора new следует написать и свою версию оператора delete.


U>мне кажется, что вы сморозили чушь


да.

я имел ввиду

почему при написании своей формы оператора new следует написать и свою форму оператора delete.

т.е. допустим

void* opertor new(size_t size, mytag& tag);
void opertor delete(void* p, mytag& tag); // вызыается только либо явно, 
// либо при исключении в конструкторе после вызова new выше.

mytag tag;
X * x = new (tag) X();
delete x; // стандартный operator delete, а не своя форма.
delete (tag) x; // такого не бывает.
Русский военный корабль идёт ко дну!
Re[3]: throw в конструкторе?
От: slava_phirsov Россия  
Дата: 05.01.10 18:47
Оценка:
Здравствуйте, uzhas, Вы писали:

U>A new-expression obtains storage for the object by calling an allocation function (3.7.3.1) If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function (3.7.3.2)


may release, или should release? Глупо, конечно, цепляться к словам, но все же стандарт — это Документ. Слово may вызывает у меня смутные сомнения
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.