|
Boost : |
From: Greg Colvin (gcolvin_at_[hidden])
Date: 1999-07-18 15:00:19
I've been traveling away from my email, so I may have missed
something important, but here are few observations.
The whole point of shared_ptr is sharing, so the current
implementation is optimized for efficient parameter passing
and copying, rather than efficient initial construction.
The canonical example of shared_ptr initialization is:
shared_ptr<T> p(new T);
In this case it makes very little difference who throws
the exception: operator new(size_t), T(), or shared_ptr<T>().
The expression fails regradless, and there is no memory leak.
Of course you can write code that breaks up this expression:
void* pv = operator new(sizeof T);
T* pt = new(pv) T;
shared_ptr<T> p(pt);
Now each line can throw, for three different reasons, and
in principle you could write code that handles each exception
differently:
try {
void* pv = operator new(sizeof T);
try {
T* pt = new(pv) T;
try {
shared_ptr<T> p(pt);
} catch {
// ...
} catch {
// ...
} catch {
// ...
}
However, the current shared_ptr will destroy *pt and delete pt
if its constructor throws, making recovery harder.
If I undertand him correctly, Kevin suggests a change which would
make recovery easier, by making it so that pt remains valid if the
shared_ptr constructor throws.
One question is: Do we care enough about ease of recovery in this
case to sacrifice fast copying?
Another question is: How do you avoid a leak in the canonical
example?
shared_ptr<T> p(new T);
If the shared_ptr constructor throws there is no way to delete
the new T. So it seems you would be forced to write:
T* pt = new T;
try {
shared_ptr<T> p(pt);
} catch {
delete pt;
throw;
}
Or, since the point of Kevin's examples is to be able to use pt
regardless:
T* pt = new T;
try {
shared_ptr<T> p(pt);
} catch {
// do important stuff with pt
// ...
delete pt;
throw;
}
// do (the same?) important stuff with pt
// ...
// also do stuff with p
// ...
If you really need such logic, it seems you are better off with:
T* pt = new T;
// do important stuff with pt
// ...
shared_ptr<T> p(pt);
// also do stuff with p, unless a throw prevents
// ...
Which works with the current shared_ptr semantics.
I'll also point out that in most modern environments running out
of virtual memory is rare, and typically causes operating system
performance to degrade horribly, so I see little point in splitting
hairs over which call to new runs out of memory first.
------------------------------------------------------------------------
eGroups.com home: http://www.egroups.com/group/boost
http://www.egroups.com - Simplifying group communications
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk