Code Complexity - Part II. Sutter, H. In of Guru of the Week.
Code Complexity - Part II [link]Paper  abstract   bibtex   
The challenge: Take the three-line function from GotW #20 and make it strongly exception-safe. This exercise illustrates some important lessons about exception safety. [Excerpt: Exception Safety and Multiple Side Effects] In this case, it turned out to be possible in Attempt #3 to perform both side effects with essentially commit-or-rollback semantics (except for the stream issues). The reason it was possible is that there turned out to be a technique by which the two effects could be performed atomically... that is, all of the "real" preparatory work for both could be completed in such a way that actually performing the visible side effects could be done using only nonthrowing operations. [] Even though we were lucky this time, it's not always that simple: It's impossible to write strongly exception-safe functions that have two or more unrelated side effects that cannot be performed atomically (for example, what if the two side effects had been to emit one message to cout and another to cerr?), since the strong guarantee is that in the presence of exceptions "program state will remain unchanged"... in other words, if there's an exception, there must be no side effects. When you come across a case where the two side effects cannot be made to work atomically, usually the only way to get strong exception safety is to split the one function into two others that can be performed atomically. [] This GotW should illustrate three important things: [::1] Providing the strong exception safety guarantee often (but not always) requires you to trade off performance. [::2] If a function has multiple unrelated side effects, it cannot always be made strongly exception-safe. If not, it can only be done by splitting the function it into several functions each of whose side effects can be performed atomically. [::3] Not all functions need to be strongly exception-safe. Both the original code and Attempt #1 satisfy the basic guarantee. For many clients, Attempt #1 is sufficient and minimizes the opportunity for side effects to occur in the exceptional situations, without requiring the performance tradeoffs of Attempt #3. [Postscript: Streams and Side Effects] As it turns out, our assumption that no called function has side effects is not entirely true. In particular, there is no way to guarantee that the stream operations will not fail after partly emitting a result. This means that we can't get true commit-or-rollback fidelity from any function that performs stream output, at least not on these standard streams. Another issue is that, if the stream output fails, the stream state will have changed. We currently do not check for that or recover from it, but it is possible to further refine the function to catch stream exceptions and reset cout's error flags before rethrowing the exception to the caller.
@incollection{sutterCodeComplexityPart1997,
  title = {Code Complexity - {{Part II}}},
  author = {Sutter, Herb},
  date = {1997},
  url = {http://www.gotw.ca/gotw/021.htm},
  abstract = {The challenge: Take the three-line function from GotW \#20 and make it strongly exception-safe. This exercise illustrates some important lessons about exception safety.

[Excerpt: Exception Safety and Multiple Side Effects]

In this case, it turned out to be possible in Attempt \#3 to perform both side effects with essentially commit-or-rollback semantics (except for the stream issues). The reason it was possible is that there turned out to be a technique by which the two effects could be performed atomically... that is, all of the "real" preparatory work for both could be completed in such a way that actually performing the visible side effects could be done using only nonthrowing operations.

[] Even though we were lucky this time, it's not always that simple: It's impossible to write strongly exception-safe functions that have two or more unrelated side effects that cannot be performed atomically (for example, what if the two side effects had been to emit one message to cout and another to cerr?), since the strong guarantee is that in the presence of exceptions "program state will remain unchanged"... in other words, if there's an exception, there must be no side effects. When you come across a case where the two side effects cannot be made to work atomically, usually the only way to get strong exception safety is to split the one function into two others that can be performed atomically.

[] This GotW should illustrate three important things:

[::1] Providing the strong exception safety guarantee often (but not always) requires you to trade off performance.

[::2] If a function has multiple unrelated side effects, it cannot always be made strongly exception-safe. If not, it can only be done by splitting the function it into several functions each of whose side effects can be performed atomically.

[::3] Not all functions need to be strongly exception-safe. Both the original code and Attempt \#1 satisfy the basic guarantee. For many clients, Attempt \#1 is sufficient and minimizes the opportunity for side effects to occur in the exceptional situations, without requiring the performance tradeoffs of Attempt \#3.

[Postscript: Streams and Side Effects]

As it turns out, our assumption that no called function has side effects is not entirely true. In particular, there is no way to guarantee that the stream operations will not fail after partly emitting a result. This means that we can't get true commit-or-rollback fidelity from any function that performs stream output, at least not on these standard streams. Another issue is that, if the stream output fails, the stream state will have changed. We currently do not check for that or recover from it, but it is possible to further refine the function to catch stream exceptions and reset cout's error flags before rethrowing the exception to the caller.},
  keywords = {*imported-from-citeulike-INRMM,~INRMM-MiD:c-13847341,bifurcation-analysis,codelet,complexity,computational-science,software-uncertainty},
  number = {GotW \#21},
  series = {Guru of the {{Week}}}
}

Downloads: 0