- Overview
-
Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
- Tips and Techniques
- Five Things You Need to Know About C++11 Unions
- A Tour of C99
- A Tour of C1X
-
C++0X: The New Face of Standard C++
- Reference Wrapper
- The Performance Technical Report
- auto for the People
- Ironing Templates' Syntactic Wrinkles
- Visual C++ Becomes ISO Compliant
- A Garbage Collector for C++
- C99 Core Features in C++0X
- The <code>shared_ptr</code> Class
- The shared_ptr Class, II
- Lambda Expressions and Closures, Part I
- Lambda Expressions and Closures, Part II
- Lambda Expressions and Closures, Part III
- The Type Traits Library, Part I
- The Type Traits Library, Part II
- The Type Traits Library, Part III
- finally Revisited
- The Any Library
- The nullptr Keyword Proposal
- Delegating Constructors
- The Explicit Conversion Operators Proposal
- Conditionally-Supported Behavior
- The weak ptr Class Template, Part I
- The weak ptr Class Template, Part II
- POD Types Revisited
- The rvalue Reference Proposal, Part I
- The rvalue Reference Proposal, Part II
- Proposal for New String Algorithms
- Concepts, Part I
- Concepts, Part II
- constexpr: Generalized Constant Expressions
- The <u>constexpr</u> Proposal: Constructors
- Strongly-Typed enum Types
- C++09: The Road Ahead
- C++09: Proposals by Statuses
- Changing Undefined Behavior to Diagnosable Errors
- New Character Types
- The __func__ Predeclared Identifier is Coming to C++
- Static Assertions
- The extern template Proposal
- Variadic Templates, Part I
- Variadic Templates, Part II
- Variadic Templates, Part III -- Critique
- Using unique_ptr, Part I
- Using unique_ptr, Part II
- Unrestricted Unions, Part I
- Unrestricted Unions, Part II
- Unrestricted Unions, Part III
- Types With No Linkage as Template Arguments
- New Initialization Syntax
- Initializer Lists and Sequence Constructors
- New Standard Library Algorithms
- Class Member Initializers
- Inheriting Constructors
- Introducing Attributes
- The Removal of Concepts From C++0x
- The Future of C++0x, Part I
- The Future of C++0X, Part II
- The Debate About Attributes, Part I
- The Debate About Attributes, Part II
- The Debate About Attributes, Part III
- The Debate About Attributes, Part IV
- Forward Declarations of Enum Types
- The SCARY Iterators Proposal, Part I
- The SCARY Iterators Proposal, Part II
- Heading for Deprecation: <tt>export</tt>, Exception Specification and <tt>register</tt>
- The Rejection of the Unified Function Syntax Proposal
- Rvalue References as Object Members
- FCD Approved
- The Debate on noexcept, Part I
- The Debate on noexcept, Part II
- The Debate on noexcept, Part III
- About-face -- [[Attributes]] to Be Replaced with Keywords
- Will Delegating Constructors Be Removed From C++0x?
- Rvalue References: Past, Present and Future, Part I
- Rvalue References: Past, Present and Future, Part II
- Rvalue References: Past, Present and Future, Part III
- A Move in the Right Direction, Part I
- A Move in the Right Direction, Part II
- New Keywords for Inheritance Control, Part I
- New Keywords for Inheritance Control, Part II
- FDIS Approved
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
The Debate on noexcept, Part III
Last updated Jan 1, 2003.
In the final part of this series I will summarize the pros and cons and conclude the discussion about the fate of noexcept and its usefulness.
Redundant? Not Quite
In the previous part I raised the "redundancy claim", which essentially suggests that noexcept might be redundant because in some cases at least, the compiler can check a function's code to determine whether it will throw an exception. If the compiler can prove that a function will not throw, it doesn't need noexcept in the first place.
The proponents of noexcept raise an important counter-argument. Indeed, when the compiler processes a function definition it can sometimes tell whether that function will not throw without a noexcept declaration. However, this is true only for functions whose definitions are visible to the compiler. If a certain translation unit contains a call to a function defined in a different translation unit, the compiler has no way of knowing whether that function throws. That's where the noexcept keyword proves to be most useful -- it allows both the programmer and the compiler to tell that a certain function doesn't throw. Looking back at our previous example:
void f2() noexecpt;
void f1() noexcept
{
f2(); //OK, calling a noexcept function
}
Adding noexcept to the prototype of f2() seemingly resolves the dilemma -- the compiler assumes that the call to f2() will not throw, which means that f1() will not throw either. But what if the programmer who wrote the declaration of f2() with noexcept was wrong? What if the definition of f2() changes in the future, turning f2() into a function that does throw? Will the programmer remember to update all the declarations of f2()? Unlike inline, which can't cause too much harm even if it's wrong, noexcept isn't to be taken lightly -- a noexcept violation can be disastrous. That is why I believe that noexcept is bad idea to begin with. Indeed, it may improve performance in some cases but the risks are too high. The proposal also assumes that the programmer is an exception safety expert, which is rarely the case.
Summarizing the Problems with noexcept
Let's summarize the problems with the current specification of noexcept.
No existing practice. The committee fell again into the well-known trap of "design by committee", standardizing a feature that had never been implemented in the real world. If noexcept had been proposed a couple of years ago, at least we would have had some time to evaluate it, fine-tune it or even scrap it. Alas, the noexcept proposal appeared out of the blue, just days before the FCD's closing date.
Underspecification. The proposal boasts "compile-time checking" but that's false advertising. In some cases, the compiler is supposed to validate the noexcept guarantee. However, there are cases in which the compiler can't do that. Worse yet, the proposal doesn't state which tests the compiler should perform and what's considered a "show-stopper". For example, is it OK to declare a function that might rarely throw noexcept? Should the compiler dig deep into every possible execution path of a noexcept function?
Benchmarking. Thus far, no official benchmark results have been published. It's therefore not clear what the potential performance gain of noexcept is. What if it turns out to be negligible? Will that justify the risks associated with noexcept? Even if the performance improvement is staggering, the results should have been published before the Pittsburgh meeting, not after.
Disagreement about noexcept violations. Although the proposal requires that std::terminate() shall be called if a noexcept function throws, that policy is both controversial and underspecified. Which resources are supposed to be released in such case? Should the program crash unconditionally, causing resource leaks and risking data integrity? I can understand why stack unwinding is ruled out but what about other resources such as locks and system I/O buffers? Letting an airplane crash just because a sloppy programmer forgot to remove noexcept from an old header file doesn't sound reassuring.
Compile-time checking is unrealistic. Let's admit it: unless the C++ standard enforces Whole Program Analysis, it's simply ridiculous to assume that the compiler will apply compile-time checking of noexcept. If the compiler can do that only in certain cases, that's the worst option because programmers will never know whether a successful compilation means that a noexcept function has been validated by the compiler or does that mean that the compiler was unable to validate the noexcept guarantee and therefore trusted the programmer's judgment. We have plenty of experience with register and inline suggesting that programmers' judgment -- as far as optimization is concerned -- doesn't necessarily outwit the compiler's.
In Conclusion
Although noexcept is in the FCD, we still don't have full specifications thereof nor do we have an exhaustive checklist of what's required of the implementation. I believe that as with other questionable C++0x features, noexcept is a recipe for trouble, and that its benefits are offset by its drawbacks. Premature optimization is evil, as we all know too well.
