D
David B. Held
I wanted to post this proposal on c.l.c++.m, but my news
server apparently does not support that group any more.
I propose a new class of exception safety known as the
"smart guarantee". Essentially, the smart guarantee
promises to clean up resources whose ownership is
passed into the function, for whatever defintion of "clean
up" is most appropriate for the resource passed.
Note that this is different from both the basic and the
strong guarantee.
According to David Abrahams, (here:
http://www.boost.org/more/generic_exception_safety.html)
the common guarantees are as follows:
The basic guarantee: that the invariants of the
component are preserved, and no resources
are leaked.
The strong guarantee: that the operation has either
completed successfully or thrown an exception,
leaving the program state exactly as it was before
the operation started.
The no-throw guarantee: that the operation will not
throw an exception.
Now, one could be pedantic and say that the strong
guarantee doesn't really promise that the program state
will be "exactly" as it was before the operation started,
since there is now an exception object present in the
state which was not present before (if an exception is
thrown, of course). However, let us not dwell on that
pedantry, but a different one: what if the "operation" is
a function which receives ownership of a resource,
like so:
void foo(obj* p);
foo(new obj);
Now, before the function is called, a new object is
created on the heap. However, the only reference
to that object is bound to a parameter of foo(). So
technically, foo() is free to allow the last (and only)
reference to obj go out of scope, and still provide
the strong guarantee. If an exception is thrown, foo()
exits, and the object is still on the heap; hence, the
program state is preserved. Thus, foo() can be
strongly exception safe and leak a resource.
Clearly, most implementors of foo() will try to properly
dispose of p in the event of an exception. But now
foo() doesn't offer the strong guarantee, because if
an exception is thrown, the exit state will be different
from the entry state. However, such an implementation
of foo() still offers some measure of safety in the face
of exceptions, and foo() may provide the strong
guarantee for all of the state not including the
resources whose ownership was transferred into the
function.
I propose to call this level of safety the "smart
guarantee". It may seem like an obscure corner
case which does not deserve a name of its own,
because functions which take sole ownership of a
resource are not so common. I argue that if the
language receives fundamental support for move
semantics, then such functions may, in fact, become
more common; and thus this level of exception
safety may become more relevant.
I chose the name "smart" because that seems to
connote an awareness of resources or some type
of automatic management. Note that the smart
guarantee is somewhat orthogonal to the basic and
strong guarantee. So a function could provide the
basic guarantee for local state, and the smart
guarantee for ownership-transfer arguments.
Or, it could offer the strong guarantee for all
ownership-stable state, and the smart guarantee
for ownership-transfer state. It is perhaps useful to
call these situations the "smart basic guarantee"
and the "smart strong guarantee", respectively.
I think of the "smart guarantee" as the "smart
strong guarantee" by default.
To explicitly state that an operation does not
provide the smart guarantee, but does provide
one of the other guarantees, I would say that it
provides the "simple basic" or "simple strong"
guarantee. By default, "basic guarantee" and
"strong guarantee" should mean the simple
versions.
Comments are welcome.
Dave
server apparently does not support that group any more.
I propose a new class of exception safety known as the
"smart guarantee". Essentially, the smart guarantee
promises to clean up resources whose ownership is
passed into the function, for whatever defintion of "clean
up" is most appropriate for the resource passed.
Note that this is different from both the basic and the
strong guarantee.
According to David Abrahams, (here:
http://www.boost.org/more/generic_exception_safety.html)
the common guarantees are as follows:
The basic guarantee: that the invariants of the
component are preserved, and no resources
are leaked.
The strong guarantee: that the operation has either
completed successfully or thrown an exception,
leaving the program state exactly as it was before
the operation started.
The no-throw guarantee: that the operation will not
throw an exception.
Now, one could be pedantic and say that the strong
guarantee doesn't really promise that the program state
will be "exactly" as it was before the operation started,
since there is now an exception object present in the
state which was not present before (if an exception is
thrown, of course). However, let us not dwell on that
pedantry, but a different one: what if the "operation" is
a function which receives ownership of a resource,
like so:
void foo(obj* p);
foo(new obj);
Now, before the function is called, a new object is
created on the heap. However, the only reference
to that object is bound to a parameter of foo(). So
technically, foo() is free to allow the last (and only)
reference to obj go out of scope, and still provide
the strong guarantee. If an exception is thrown, foo()
exits, and the object is still on the heap; hence, the
program state is preserved. Thus, foo() can be
strongly exception safe and leak a resource.
Clearly, most implementors of foo() will try to properly
dispose of p in the event of an exception. But now
foo() doesn't offer the strong guarantee, because if
an exception is thrown, the exit state will be different
from the entry state. However, such an implementation
of foo() still offers some measure of safety in the face
of exceptions, and foo() may provide the strong
guarantee for all of the state not including the
resources whose ownership was transferred into the
function.
I propose to call this level of safety the "smart
guarantee". It may seem like an obscure corner
case which does not deserve a name of its own,
because functions which take sole ownership of a
resource are not so common. I argue that if the
language receives fundamental support for move
semantics, then such functions may, in fact, become
more common; and thus this level of exception
safety may become more relevant.
I chose the name "smart" because that seems to
connote an awareness of resources or some type
of automatic management. Note that the smart
guarantee is somewhat orthogonal to the basic and
strong guarantee. So a function could provide the
basic guarantee for local state, and the smart
guarantee for ownership-transfer arguments.
Or, it could offer the strong guarantee for all
ownership-stable state, and the smart guarantee
for ownership-transfer state. It is perhaps useful to
call these situations the "smart basic guarantee"
and the "smart strong guarantee", respectively.
I think of the "smart guarantee" as the "smart
strong guarantee" by default.
To explicitly state that an operation does not
provide the smart guarantee, but does provide
one of the other guarantees, I would say that it
provides the "simple basic" or "simple strong"
guarantee. By default, "basic guarantee" and
"strong guarantee" should mean the simple
versions.
Comments are welcome.
Dave