Topic: Function try blocks
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/05/28 Raw View
In article <smeyersD8wut1.2LK@netcom.com>,
Scott Meyers <smeyers@netcom.com> wrote:
>What is the purpose of a function try block? I thought it was to allow
>for the convenient handling of exceptions thrown in member
>initialization lists,
Correct. The purpose is to permit TRANSLATION of the
exception. NOT cleanup.
> AddressBookEntry::AddressBookEntry(const string& name,
> const char *address,
> const Phones *phoneNumbers)
> try
> : name_(name),
> address_(address ? new string(address) : 0),
> phones_(phoneNumbers ? new Phones(phoneNumbers) : 0)
> {}
> catch (...)
> {
> delete address_; // possibly undefined
> delete phones_; // possibly undefined
> }
NO. The purpose is to TRANSLATE the exception like this:
try { .. }
catch(...) { throw "Address Book Entry Torn"; }
>
>I know I can solve this problem by making address_ and phones_
>auto_ptr objects,
Yes. OR you can put the "new" inside the constructor body.
>but now I'm wondering: how *are* you supposed to use
>function try blocks? They don't seem to help in this case.
The purpose is NOT cleanup and it is NOT for retry.
The purpose is simply to allow the exception to be caught,
analysed in the context of the object, and a more appropriate
exception object thrown.
Cleanup MUST be coded so it works automatically.
There's no way to "intervene" in the "unwinding" process.
(Yep, objects are unwound just like the stack)
Retry MUST be handled by control transfers outside
the object being constructed -- by the subroutine that
attempted to construct the object in the first place
(or one of its parents).
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: tseaver@neosoft.com (Tres Seaver)
Date: 1995/05/23 Raw View
In <smeyersD8wut1.2LK@netcom.com>, smeyers@netcom.com (Scott Meyers) writes:
>What is the purpose of a function try block? I thought it was to allow
>for the convenient handling of exceptions thrown in member
>initialization lists, but consider this code:
>
> class AddressBookEntry {
> private:
> string name_;
> string * const address_;
> Phones * const phones_;
>
> public:
> AddressBookEntry(const string& name,
> const char *address,
> const Phones *phoneNumbers);
> ...
> };
>
>If I try to implement the constructor like this,
>
> AddressBookEntry::AddressBookEntry(const string& name,
> const char *address,
> const Phones *phoneNumbers)
> : name_(name),
> address_(address ? new string(address) : 0),
> phones_(phoneNumbers ? new Phones(phoneNumbers) : 0)
> {}
>
>I have a resource leak if an exception is thrown during initialization
>of phones_, because the object pointed to by address_ will never be
>freed.
>
>However, if I try to use a function try block,
>
> AddressBookEntry::AddressBookEntry(const string& name,
> const char *address,
> const Phones *phoneNumbers)
> try
> : name_(name),
> address_(address ? new string(address) : 0),
> phones_(phoneNumbers ? new Phones(phoneNumbers) : 0)
> {}
> catch (...)
> {
> delete address_; // possibly undefined
> delete phones_; // possibly undefined
> }
>
>I run into trouble in the catch clause, because I can't safely delete
>address_ and phones_ unless I know they've been initialized, and the
>exception may have been thrown during member initialization.
>
>I know I can solve this problem by making address_ and phones_
>auto_ptr objects, but now I'm wondering: how *are* you supposed to use
>function try blocks? They don't seem to help in this case.
>
>Thanks,
>
>Scott
>
>PS - I hope this is an acceptable post to comp.std.c++. Although my
>question isn't about the standard per se, it's about a very new feature
>whose design goals are, at least to me, unknown.
Why not bind the pointer members into "smart pointer" objects? (I forget what
the Draft Standard calls the new class for smart pointers, but this is the technique
in Marshall Clines FAQ book, topic #266). Then the owner ( AddressBookEntry )
does not care which initialization fails, since the smart pointers which have been
successfully initialized are guaranteed to have their destructors called, and will
thus free the allocated memory.
Tres Seaver tseaver@neosoft.com
MACRO Enterprises, Inc. Vox: (713) 827-7273
Houston, Texas, USA Fax: (713) 827-7278
Author: smeyers@netcom.com (Scott Meyers)
Date: 1995/05/21 Raw View
What is the purpose of a function try block? I thought it was to allow
for the convenient handling of exceptions thrown in member
initialization lists, but consider this code:
class AddressBookEntry {
private:
string name_;
string * const address_;
Phones * const phones_;
public:
AddressBookEntry(const string& name,
const char *address,
const Phones *phoneNumbers);
...
};
If I try to implement the constructor like this,
AddressBookEntry::AddressBookEntry(const string& name,
const char *address,
const Phones *phoneNumbers)
: name_(name),
address_(address ? new string(address) : 0),
phones_(phoneNumbers ? new Phones(phoneNumbers) : 0)
{}
I have a resource leak if an exception is thrown during initialization
of phones_, because the object pointed to by address_ will never be
freed.
However, if I try to use a function try block,
AddressBookEntry::AddressBookEntry(const string& name,
const char *address,
const Phones *phoneNumbers)
try
: name_(name),
address_(address ? new string(address) : 0),
phones_(phoneNumbers ? new Phones(phoneNumbers) : 0)
{}
catch (...)
{
delete address_; // possibly undefined
delete phones_; // possibly undefined
}
I run into trouble in the catch clause, because I can't safely delete
address_ and phones_ unless I know they've been initialized, and the
exception may have been thrown during member initialization.
I know I can solve this problem by making address_ and phones_
auto_ptr objects, but now I'm wondering: how *are* you supposed to use
function try blocks? They don't seem to help in this case.
Thanks,
Scott
PS - I hope this is an acceptable post to comp.std.c++. Although my
question isn't about the standard per se, it's about a very new feature
whose design goals are, at least to me, unknown.
Author: smeyers@netcom.com (Scott Meyers)
Date: 1995/05/21 Raw View
In article <3pmpr2$nol@Mars.mcs.com> mikey@MCS.COM (Mike Young) writes:
| Scott Meyers (smeyers@netcom.com) wrote:
| : However, if I try to use a function try block,
|
| : AddressBookEntry::AddressBookEntry(const string& name,
| : const char *address,
| : const Phones *phoneNumbers)
| : try
| : : name_(name),
| : address_(address ? new string(address) : 0),
| : phones_(phoneNumbers ? new Phones(phoneNumbers) : 0)
| : {}
| : catch (...)
| : {
| : delete address_; // possibly undefined
| : delete phones_; // possibly undefined
| : }
|
| address_ and phones_ are both pointers; you can safely assign them to NULL
| in ctors. The constructor body should take care of allocation. NULL
You you can't: they're const pointers in the original posting. The only
way to give them a value is in a member init list. And if an exception is
thrown during their initialization, you can't safely delete them.
Scott
Author: mikey@mcs.com
Date: 1995/05/22 Raw View
In article <smeyersD8xyM3.A4z@netcom.com>, smeyers@netcom.com says...
>
>| address_ and phones_ are both pointers; you can safely assign them to NULL
>| in ctors. The constructor body should take care of allocation. NULL
>
>You you can't: they're const pointers in the original posting. The only
>way to give them a value is in a member init list. And if an exception is
>thrown during their initialization, you can't safely delete them.
>
---------------
Hmmm. So they are. Just the same, I know no other way to safely destroy them when an
exception gets thrown. You can cast away const-ness in the constructor body, or you might
re-evaluate the need for const on the private copy.
Mike.
Author: mikey@MCS.COM (Mike Young)
Date: 1995/05/21 Raw View
Scott Meyers (smeyers@netcom.com) wrote:
: However, if I try to use a function try block,
: AddressBookEntry::AddressBookEntry(const string& name,
: const char *address,
: const Phones *phoneNumbers)
: try
: : name_(name),
: address_(address ? new string(address) : 0),
: phones_(phoneNumbers ? new Phones(phoneNumbers) : 0)
: {}
: catch (...)
: {
: delete address_; // possibly undefined
: delete phones_; // possibly undefined
: }
address_ and phones_ are both pointers; you can safely assign them to NULL
in ctors. The constructor body should take care of allocation. NULL
pointers can always be safely deleted. As for function try blocks,
I've never heard of them, but I would presume the same strategy can
still apply.
Mike.