mirror of
https://gitlab.com/fbb-git/cppannotations
synced 2024-11-18 10:06:54 +01:00
WIP
git-svn-id: https://cppannotations.svn.sourceforge.net/svnroot/cppannotations/trunk@306 f6dd340e-d3f9-0310-b409-bdd246841980
This commit is contained in:
parent
5967641984
commit
f5539539f2
4 changed files with 86 additions and 36 deletions
|
@ -43,6 +43,12 @@ COMMENT(>>>>>>>>>>>>> NEXT <<<<<<<<<<<<<)
|
|||
sect(Exception guarantees)
|
||||
includefile(exceptions/guarantees)
|
||||
|
||||
subsect(The basic guarantee)
|
||||
includefile(exceptions/basic)
|
||||
|
||||
subsect(The strong guarantee)
|
||||
includefile(exceptions/strong)
|
||||
|
||||
lsect(FUNTRY)(Function try blocks)
|
||||
includefile(exceptions/function)
|
||||
|
||||
|
|
55
yo/exceptions/basic.yo
Normal file
55
yo/exceptions/basic.yo
Normal file
|
@ -0,0 +1,55 @@
|
|||
The emi(basic guarantee) dicates that functions that failing to complete their
|
||||
assigned tasks must return all allocated resources, usually memory, before
|
||||
terminating. Since practically all functions and operators may throw
|
||||
exceptions and since a function may repeatedly allocate resources the
|
||||
blueprint of a function allocating resources shown below defines a try block
|
||||
to catch all exceptions that might be thrown. The catch handler's task is to
|
||||
return all allocated resources and then retrow the exception.
|
||||
verb(
|
||||
void allocator(X **xDest, Y **yDest)
|
||||
{
|
||||
X *xp = 0; // non-throwing preamble
|
||||
Y *yp = 0;
|
||||
|
||||
try // this part might throw
|
||||
{
|
||||
xp = new X[nX]; // alternatively: allocate one object
|
||||
yp = new Y[nY];
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
delete xp;
|
||||
throw;
|
||||
}
|
||||
|
||||
delete[] *xDest; // non-throwing postamble
|
||||
*xDest = xp;
|
||||
delete[] *yDest;
|
||||
*yDest = yp;
|
||||
}
|
||||
)
|
||||
In the pre-try code the pointers to receive the addresses returned by the
|
||||
operator tt(new) calls are initialized to 0. Since the catch handler must be
|
||||
able to return allocated memory they must be available outside of the tt(try)
|
||||
block. If the allocation succeeds the memory pointed to by the destination
|
||||
pointers is returned and then the pointers are given new values.
|
||||
|
||||
Allocation and or initialization might fail. If allocation fails tt(new)
|
||||
throws a hi(bad_alloc)tt(std::bad_alloc) exception and the catch handler
|
||||
simply deletes 0 pointers which is OK.
|
||||
|
||||
If allocation succeeds but the construction of (some) of the objects fails
|
||||
by throwing an exception then the following is
|
||||
hi(new: and exceptions)hi(exception: and new) em(guaranteed) to happen:
|
||||
itemization(
|
||||
it() The destructors of all successfully allocated objects are called;
|
||||
it() The dynamically allocated memory to contain the objects is returned
|
||||
)
|
||||
|
||||
Consequently, no memory will leak when tt(new) fails. Inside the above
|
||||
tt(try) block tt(new X) may fail: this will keep the 0-pointers intact and so
|
||||
the catch handler merely deletes 0 pointers. When tt(new Y) fails tt(xp) will
|
||||
point to allocated memory and so it must be returned. This happens inside the
|
||||
catch handler. The final pointer (here: tt(yp)) will only be unequal zero
|
||||
when tt(new Y) properly completes, so there's no need for the catch handler to
|
||||
return the memory pointed at by tt(yp).
|
|
@ -54,7 +54,7 @@ at that many situations?
|
|||
|
||||
Exceptions may be generated in a great many situations, but serious
|
||||
problems will be prevented when we're able to provide at least one of the
|
||||
following exception guarantees:
|
||||
following i(exception guarantees):
|
||||
itemization(
|
||||
it() The em(basic guarantee): no resources are leaked. In practice this
|
||||
means: all allocated memory is properly returned when exceptions are thrown.
|
||||
|
@ -65,38 +65,3 @@ assignment operator provides this guarantee)
|
|||
proven that no exception will be thrown from it.
|
||||
)
|
||||
|
||||
The basic guarantee dicates that functions that fail to complete their
|
||||
work properly must return all allocated resources, usually memory, before
|
||||
returning. Since practically all functions and operators may throw exceptions
|
||||
and since a function may repeatedly allocate resources a try block
|
||||
is used to catch all exceptions that might be thrown. The catch handler may
|
||||
then return all allocated resources and retrow the exception. If all's well
|
||||
verb(
|
||||
void allocator(/* parameters, if any */)
|
||||
{
|
||||
|
||||
X *xp = 0; // non-throwing preamble
|
||||
Y *yp = 0;
|
||||
Z *zp = 0;
|
||||
|
||||
try // this part might throw
|
||||
{
|
||||
xp = allocateX(/* arguments */);
|
||||
yp = allocateY(/* arguments */);
|
||||
zp = allocateZ(/* arguments */);
|
||||
|
||||
thisMightThrowToo();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
delete zp;
|
||||
delete yp;
|
||||
delete xp;
|
||||
throw;
|
||||
}
|
||||
|
||||
xDest = xp; // non-throwing postamble
|
||||
yDest = yp;
|
||||
zDest = zp;
|
||||
}
|
||||
)
|
||||
|
|
24
yo/exceptions/strong.yo
Normal file
24
yo/exceptions/strong.yo
Normal file
|
@ -0,0 +1,24 @@
|
|||
The emi(strong guarantee) dicates that an object's state should not change in
|
||||
the face of exceptions. This is realized by performing all operations that
|
||||
might throw on a separate copy of the data. If all this succeeds then the
|
||||
current object and its (now successfully modified) copy are swapped. An
|
||||
example of this approach can be observed in the canonical overloaded
|
||||
assignment operator:
|
||||
verb(
|
||||
Class &operator=(Class const &other)
|
||||
{
|
||||
Class tmp(other);
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
)
|
||||
The copy construction might throw an exception, but this keeps the current
|
||||
object's state intact. If the copy construction succeeds tt(swap) swaps the
|
||||
current object's contents with tt(tmp)'s contents and returns a reference to
|
||||
the current object. For this to succeed it must be guaranteed that tt(swap)
|
||||
won't throw an exception. Returning a reference (or a value of a primitive
|
||||
data type) is also guaranteed not to throw exceptions. The canonical form of
|
||||
the overloaded assignment operator therefore meets the requirements of the
|
||||
strong guarantee.
|
||||
|
||||
|
Loading…
Reference in a new issue