Document number: N3150=10-0140
Date: 2010-10-14
Author:J. Daniel Garcia
Project: Programming Language C++, Library Working Group
Reply to: josedaniel.garcia@uc3m.es

N3150 - Removing non-empty dynamic exception specifications from the library

During the Rapperswil meeting the Library Working Group decided to remove dynamic excepion specifications from the library, as this is a deprecated feature now. This is mostly done by N3114. However, N3114 handles only empty dynamic exception specifications. The only place in the standard library where non-empty dynamic expection specifications are used is in some versions of operator new, which may throw std::bad_alloc. This paper corrects this, making them noexcept(false). This paper presents proposed wording for this change. The paper partially addresses National Body comments CH 16 and GB 60.

Discussion

There are two points in the library where a non-empty dynamic exception specification is used: For both of them the dynamic exception specification may be removed, making those operators noexcept(false) (they may throw). One could argue that then some clarification could be needed fo the exception which is thrown. However, for the first one, this is already done by 18.6.1.1/3, stating that bad_alloc may be thrown:

Required behavior: Return a non-null pointer to suitably aligned storage (3.7.4), or else throw a bad_alloc exception. This requirement is binding on a replacement version of this function.

For the second one, this is implicit in 18.6.1.2/3:

Required behavior: Same as for operator new(std::size_t). This requirement is binding on a replacement version of this function.

Note that this is a way of implicitly stating that operator new[](std::size_t) may throw a std::bad_alloc.

Identified changes

All changes in this paper are against N3126. This paper proposes the following changes:

Acknoledgments

Daniel Krügler reviewed this paper and provided helful feedback.

Wording

3.7.4 Dynamic storage duration

After p. 2
void* operator new(std::size_t) throw(std::bad_alloc);
void* operator new[](std::size_t) throw(std::bad_alloc);
...
These implicit declarations introduce only the function names operator new, operator new[], operator delete, operator delete[]. [ Note: the implicit declarations do not introduce the names std, std::bad_- alloc, and std::size_t, or any other names that the library uses to declare these names. Thus, a newexpression, delete-expression or function call that refers to one of these functions without including the header <new> is well-formed. However, referring to std, std::bad_alloc, and std::size_t is ill-formed unless the name has been declared by including the appropriate header. —end note ] Allocation and/or deallocation functions can also be declared and defined for any class (12.5).

18.6 Dynamic memory management

After p. 1
...
void* operator new(std::size_t size) throw(std::bad_alloc);
...
void* operator new[](std::size_t size) throw(std::bad_alloc);
...

18.6.1.1 Single-object forms

Before p. 1
void* operator new(std::size_t size) throw(std::bad_alloc);

18.6.1.2 Array forms

Before p. 1
void* operator new[](std::size_t size) throw(std::bad_alloc);