<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII">

<style type="text/css">

body { color: #000000; background-color: #FFFFFF; }
del { text-decoration: line-through; color: #8B0040; }
ins { text-decoration: underline; color: #005100; }

p.example { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract { margin-left: 2em; background-color: #F5F6A2;
  border: 1px solid #E1E28E; }

p.function { }
.attribute { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;
  padding-right: 1ex; }
.attribute dd { margin-left: 0em; }

blockquote.std { color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stddel { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5empadding-right: 0.5em; ; }

blockquote.stdins { text-decoration: underline;
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3; padding: 0.5em; }

table { border: 1px solid black; border-spacing: 0px;
  margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;
  padding-left: 0.8em; border: none; }
td { text-align: left; vertical-align: top;
  padding-left: 0.8em; border: none; }

</style>

<title>C++ Sized Deallocation</title>
</head>

<body>
<h1>C++ Sized Deallocation</h1>

<p>
ISO/IEC JTC1 SC22 WG21 N3778 - 2013-09-27
</p>

<p>
Lawrence Crowl, Lawrence@Crowl.org
</p>

<p>
<a href="#Problem">Problem</a><br>
<a href="#Solution">Solution</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Unavailable">Size Unavailable</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Compatibility">Backwards Compatiblity</a><br>
<a href="#Implementation">Implementation</a><br>
<a href="#Wording">Wording</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#basic.stc.dynamic">3.7.4 Dynamic storage duration [basic.stc.dynamic]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#basic.stc.dynamic.deallocation">3.7.4.2 Deallocation functions [basic.stc.dynamic.deallocation]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#expr.delete">5.3.4 New [expr.new]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#expr.delete">5.3.5 Delete [expr.delete]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#class.free">12.5 Free store [class.free]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#replacement.functions">17.6.4.6 Replacement functions [replacement.functions]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#support.dynamic">18.6 Dynamic memory management [support.dynamic]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#new.delete.single">18.6.1.1 Single-object forms [new.delete.single]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#new.delete.array">18.6.1.2 Array forms [new.delete.array]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#allocator.members">20.8.9.1 <code>allocator</code> members [allocator.members]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#diff.cpp11.basic">C.?.? Clause 3: Basic concepts [diff.cpp11.basic]</a><br>
<a href="#Revision">Revision History</a><br>
<a href="#References">References</a><br>
</p>


<h2><a name="Problem">Problem</a></h2>

<p>
With C++11,
programmers may define a static member function <code>operator delete</code>
that takes a size parameter indicating the size of the object to be deleted.
The equivalent global <code>operator delete</code> is not available.
This omission has unfortunate performance consequences.
</p>

<p>
Modern memory allocators often allocate in size categories,
and, for space efficiency reasons,
do not store the size of the object near the object.
Deallocation then requires searching for the size category store
that contains the object.
This search can be expensive,
particularly as the search data structures
are often not in memory caches.
</p>


<h2><a name="Solution">Solution</a></h2>

<p>
Permit implementations and programmers
to define sized versions of the global <code>operator delete</code>.
The compiler shall call the sized version
in preference to the unsized version
when the sized version is available.
</p>

<p>
There are two potential problems with this solution.
</p>


<h3><a name="Unavailable">Size Unavailable</a></h3>

<p>
When deleting an incomplete type, there is no size available.
In this case, the unsized version must be used.
This observation implies that calls to one version
must be effectively equivalent to calls to the other version.
Excepting the specific deallocation function called,
we believe that any programs that would change behavior
already have undefined behavior within the standard.
</p>


<h3><a name="Compatibility">Backwards Compatiblity</a></h3>

<p>
Existing programs use only the unsized version.
Linking them with a new system allocation library
that provides the sized version
is safe because the unsized version is equivalent.
Interposing a new user allocation library
on old code is safe for the same reason.
</p>

<p>
New programs using the sized version
linking against an old system allocation library would fail to link.
This can be fixed with the addition of a small shim,
in which a sized version simply forwards to the unsized version.
Likewise with new binaries linked against a new application allocation library.
</p>

<p>
The primary problem occurs when the system allocation library is new,
but an interposed user allocation library is old.
In new programs,
calls to the unsized version would go to the user library,
but calls to the sized version would go to the system library.
However, as currently defined,
default the sized version calls the unsized version.
Programmers that desire the improved performance
must take positive action.
The intent is that in some future standard,
this default will change.
In that case, there would be a mismatch in allocators.
</p>

<p>
The remaining issue is diagnosing the case of a future change in default.
Since interposition is often done at the binary level,
there appears to be no diagnostic solution other than
changing the signature of all allocation functions.
The pain of the ABI change would be larger
than the pain of adding shims at the appropriate places.
</p>

<h2><a name="Implementation">Implementation</a></h2>

<p>
Google has implemented much of this proposal
within GCC (at the library level)
and TCMalloc <a href="#TCM">[TCM]</a>.
It has obtained significant performance improvements.
</p>


<h2><a name="Wording">Wording</a></h2>

<p>
The proposed wording changes are relative to
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3691.pdf">N3691</a>.
</p>

<p>
There are no direct inconsistencies with
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3396.htm">
N3396 Dynamic memory allocation for over-aligned data</a>.
However, the final paper adopted
must address the issue of sized deallocation of over-aligned types.
</p>

<p>
Editorial, resolutions to core issue 255
might affect the proposed text.
</p>


<h3><a name="basic.stc.dynamic">3.7.4 Dynamic storage duration [basic.stc.dynamic]</a></h3>

<p>
Edit within paragraph 2 as follows.
</p>

<blockquote class="std">
<p>
....
The following allocation and deallocation functions (18.6)
are implicitly declared in global scope in each translation unit of a program.
</p>
<blockquote><pre><code>
void* operator new(std::size_t);
void* operator new[](std::size_t);
void operator delete(void*) noexcept;
void operator delete[](void*) noexcept;
<ins>void operator delete(void*, std::size_t) noexcept;
void operator delete[](void*, std::size_t) noexcept;</ins>
</code></pre></blockquote>
<p>
These implicit declarations introduce only the function names
<code>operator new</code>, <code>operator new[]</code>,
<code>operator delete</code>, <code>operator delete[]</code>.
....
</p>
</blockquote>


<h3><a name="basic.stc.dynamic.deallocation">3.7.4.2 Deallocation functions [basic.stc.dynamic.deallocation]</a></h3>

<p>
Edit paragraph 2 as follows.
</p>

<blockquote class="std">
<p>
Each deallocation function shall return <code>void</code>
and its first parameter shall be <code>void*</code>.
A deallocation function can have more than one parameter.

<ins>The global <code>operator delete</code> with exactly one parameter
is a usual (non-placement) deallocation function.
The global <code>operator delete</code>
with exactly two parameters,
the second of which has type <code>std::size_t</code>,
is a usual deallocation function.

Similarly, the global <code>operator delete[]</code> with exactly one parameter
is a usual deallocation function.
The global <code>operator delete[]</code>
with exactly two parameters,
the second of which has type <code>std::size_t</code>,
is a usual deallocation function.
[<i>Footnote:</i>
This deallocation function precludes
use of an allocation function 
<code>void operator new(std::size_t, std::size_t)</code>
as a placement allocation function (C.?.? [diff.cpp11.basic]).
&mdash;<i>end footnote</i>]</ins>

If a class <code>T</code> has a member deallocation function
named <code>operator delete</code> with exactly one parameter,
then that function is a usual <del>(non-placement)</del> deallocation function.
If class <code>T</code> does not declare such an <code>operator delete</code>
but does declare a member deallocation function
named <code>operator delete</code> with exactly two parameters,
the second of which has type <code>std::size_t</code> <del>(18.2)</del>,
then this function is a usual deallocation function.

Similarly, if a class <code>T</code> has a member deallocation function
named <code>operator delete[]</code> with exactly one parameter,
then that function is a usual (non-placement) deallocation function.
If class <code>T</code> does not declare such an <code>operator delete[]</code>
but does declare a member deallocation function
named <code>operator delete[]</code> with exactly two parameters,
the second of which has type <code>std::size_t</code>,
then this function is a usual deallocation function.

A deallocation function can be an instance of a function template.
Neither the first parameter nor the return type
shall depend on a template parameter.
[<i>Note:</i>
that is, a deallocation function template
shall have a first parameter of type <code>void*</code>
and a return type of <code>void</code> (as specified above).
&mdash;<i>end note</i>]
A deallocation function template
shall have two or more function parameters.
A template instance is never a usual deallocation function,
regardless of its signature.
</p>
</blockquote>


<h3><a name="expr.delete">5.3.4 New [expr.new]</a></h3>

<p>
Paragraph 13 is unchanged.
This paragraph is relevant
because one possible global placement new function may become unavailable.
</p>

<blockquote class="std">
<p>
The <var>new-placement</var> syntax
is used to supply additional arguments to an allocation function.
If used, overload resolution
is performed on a function call created by assembling an argument list
consisting of the amount of space requested (the first argument)
and the expressions in the <var>new-placement</var> part
of the <var>new-expression</var> (the second and succeeding arguments).
The first of these arguments has type <code>std::size_t</code>
and the remaining arguments
have the corresponding types of the expressions in the <var>new-placement</var>.
</p>
</blockquote>

<p>
Paragraph 14 is unchanged.
</p>

<blockquote class="std">
<p>
[<i>Example:</i>
</p>
<ul>
<li><p>
<code>new T</code> results in a call of
<code>operator new(sizeof(T))</code>,
</p></li>
<li><p>
<code>new(2,f) T</code> results in a call of
<code>operator new(sizeof(T),2,f)</code>,
</p></li>
<li><p>
<code>new T[5]</code> results in a call of
<code>operator new[](sizeof(T)*5+x)</code>, and
</p></li>
<li><p>
<code>new(2,f) T[5]</code> results in a call of
<code>operator new[](sizeof(T)*5+y,2,f)</code>.
</p></li>
</ul>
<p>
Here, <code>x</code> and <code>y</code>
are non-negative unspecified values
representing array allocation overhead;
the result of the <var>new-expression</var>
will be offset by this amount
from the value returned by <code>operator new[]</code>.
This overhead may be applied in all array <var>new-expressions</var>,
including those referencing the library function
<code>operator new[](std::size_t, void*)</code>
and other placement allocation functions.
The amount of overhead may vary from one invocation of new to another.
&mdash;<i>end example</i>]
</p>
</blockquote>

<p>
Edit paragraph 22 as follows.
This paragraph is relevant
because the example now applies at global scope
as well as at class scope.
</p>

<blockquote class="std">
<p>
A declaration of a placement deallocation function
matches the declaration of a placement allocation function
if it has the same number of parameters and,
after parameter transformations (8.3.5),
all parameter types except the first are identical.
<del>Any non-placement deallocation function
matches a non-placement allocation function.</del>
If the lookup finds a single matching deallocation function,
that function will be called;
otherwise, no deallocation function will be called.
If the lookup finds the two-parameter form
of a usual deallocation function (3.7.4.2)
and that function, considered as a placement deallocation function,
would have been selected as a match for the allocation function,
the program is ill-formed.
<ins>For a non-placement allocation function,
the normal deallocation function lookup is used
to find the matching deallocation function (5.3.5)</ins>
[<i>Example:</i>
</p>
<pre>
<code>struct S {
  <i>// Placement allocation function:</i>
  static void* operator new(std::size_t, std::size_t);
  <i>// Usual (non-placement) deallocation function:</i>
  static void operator delete(void*, std::size_t);
};

S* p = new (0) S; <i>// ill-formed: non-placement deallocation function matches
                  // placement allocation function</i></code>
</pre>
<p>
&mdash;<i>end example</i>]
</p>
</blockquote>


<h3><a name="expr.delete">5.3.5 Delete [expr.delete]</a></h3>

<p>
Paragraph 1 remains unchanged,
though note the restrictions on the delete operand.
</p>

<blockquote class="std">
<p>
....
The operand shall be of pointer to object type of of class type.
If of class type,
the operand is contextually implicitly converted (Clause 4)
to a pointer to object type.
The <var>delete-expression</var>'s result has type void.
[<i>Footnote:</i>
This implies that an object cannot be deleted
using a pointer of type <code>void*</code>
because void is not an object type.
&mdash;<i>end footnote</i>]
</p>
</blockquote>

<p>
Paragraph 2 remains unchanged,
though note the restriction on inheritance
with respect to the <code>delete</code> operand.
</p>

<blockquote class="std">
<p>
....
In the first alternative (<em>delete object</em>),
the value of the operand of <code>delete</code> may be a null pointer value,
a pointer to a non-array object created by a previous <var>new-expression</var>,
or a pointer to a subobject (1.8)
representing a base class of such an object (Clause 10).
If not, the behavior is undefined.
In the second alternative (<em>delete array</em>),
the value of the operand of delete may be a null pointer value
or a pointer value
that resulted from a previous array <var>new-expression</var>.
[<i>Footnote:</i>
For non-zero-length arrays,
this is the same as a pointer to the first element of the array
created by that <var>new-expression</var>.
Zero-length arrays do not have a first element.
&mdash;<i>end footnote</i>]
If not, the behavior is undefined.
[<i>Note:</i>
this means that the syntax of the <var>delete-expression</var>
must match the type of the object allocated by <code>new</code>,
not the syntax of the <var>new-expression</var>.
&mdash;<i>end note</i>]
....
</p>
</blockquote>


<p>
Paragraph 3 remains unchanged,
though note the further restriction on inheritance.
</p>

<blockquote class="std">
<p>
In the first alternative (<em>delete object</em>),
if the static type of the object to be deleted
is different from its dynamic type,
the static type shall be a base class of the dynamic type
of the object to be deleted
and the static type shall have a virtual destructor
or the behavior is undefined.
In the second alternative (<em>delete array</em>)
if the dynamic type of the object to be deleted differs from its static type,
the behavior is undefined.
</p>
</blockquote>

<p>
Paragraph 5 remains unchanged.
</p>

<blockquote class="std">
<p>
If the object being deleted has incomplete class type
at the point of deletion
and the complete class has a non-trivial destructor or a deallocation function,
the behavior is undefined.
</p>
</blockquote>

<p>
Edit paragraph 9 as follows.
</p>

<blockquote class="std">
<p>
When the keyword <code>delete</code> in a <var>delete-expression</var>
is preceded by the unary <code>::</code> operator,
<del>the global deallocation function is used to deallocate the storage.</del>
<ins>the deallocation function's name is looked up in global scope.</ins>
Otherwise,
the lookup considers class-specific deallocation functions (12.5 [class.free]).
If no class-specific deallocation function is found,
the deallocation function's name is looked up in global scope.</ins>
</p>
</blockquote>

<p>
Add a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
If the type is complete and 
if deallocation function lookup finds
both a usual deallocation function with only a pointer parameter
and a usual deallocation function
with both a pointer parameter and a size parameter,
then the selected deallocation function
shall be the one with two parameters.
Otherwise, the selected deallocation function
shall be the function with one parameter.
</p>
</blockquote>

<p>
Move paragraph 5 of 12.5 to here and edit it as follows.
Note the commas inserted into the footnote.
</p>

<blockquote class="std">
<p>
When a <var>delete-expression</var> is executed,
the selected deallocation function shall be called
with the address of the block of storage to be reclaimed as its first argument,
and (if the two parameter <del>style</del>
<ins>deallocation function</ins> is used),
the size of the block as its second argument.
[<i>Footnote:</i>
If the static type of the object to be deleted
<ins>is complete and</ins>
is different from the dynamic type<ins>,</ins>
and the destructor is not virtual<ins>,</ins>
the size might be incorrect,
but that case is already
undefined<del>; see 5.3.5</del><ins>, as stated above</ins>.
&mdash;<i>end footnote</i>]
</p>
</blockquote>


<h3><a name="class.free">12.5 Free store [class.free]</a></h3>

<p>
Edit paragraph 4 as follows.
</p>

<blockquote class="std">
<p>
<ins>Class-specific deallocation function lookup
is a part of general deallocation function lookup (5.3.5 [expr.delete])
and occurs as follows.</ins>
<del>
If a <var>delete-expression</var> begins with a unary <code>::</code> operator,
the deallocation function's name is looked up in global scope.
Otherwise, if</del>
<ins>If</ins> the <var>delete-expression</var>
is used to deallocate a class object whose static type has a virtual destructor,
the deallocation function is the one selected at the point of definition
of the dynamic type's virtual destructor (12.4).
[<i>Footnote:</i>
A similar provision is not needed
for the array version of <code>operator delete</code>
because 5.3.5 requires that in this situation,
the static type of the object to be deleted be the same as its dynamic type.
&mdash;<i>end footnote</i>]
Otherwise, if the <var>delete-expression</var>
is used to deallocate an object of class <code>T</code> or array thereof,
the static and dynamic types of the object shall be identical
and the deallocation function's name
is looked up in the scope of <code>T</code>.
If this lookup fails to find the name,
<del>the name is looked up in the global scope.</del>
<ins>general deallocation function lookup (5.3.5 [expr.delete])
continues.</ins>
If the result of the lookup is ambiguous or inaccessible,
or if the lookup selects a placement deallocation function,
the program is ill-formed.
</p>
</blockquote>

<p>
Move paragraph 5 to 5.3.5/9++.
</p>


<h3><a name="replacement.functions">17.6.4.6 Replacement functions [replacement.functions]</a></h3>

<p>
Edit paragraph 2 as follows.
</p>

<blockquote class="std">
<p>
A C++ program may provide the definition
for any of <del>eight</del> <ins>twelve</ins>
dynamic memory allocation function signatures
declared in header <code>&lt;new&gt;</code>
(3.7.4, <del>Clause 18</del> <ins>18.4 [support.dynamic]</ins>):
</p>
<ul>
<li><code>operator new(std::size_t)</code></li>
<li><code>operator new(std::size_t, const std::nothrow_t&amp;)</code></li>
<li><code>operator new[](std::size_t)</code></li>
<li><code>operator new[](std::size_t, const std::nothrow_t&amp;)</code></li>
<li><code>operator delete(void*)</code></li>
<li><code>operator delete(void*, const std::nothrow_t&amp;)</code></li>
<li><code>operator delete[](void*)</code></li>
<li><code>operator delete[](void*, const std::nothrow_t&amp;)</code></li>
<li><ins><code>operator delete(void*, std::size_t)</code></ins></li>
<li><ins><code>operator delete(void*, std::size_t, const std::nothrow_t&amp;)</code></ins></li>
<li><ins><code>operator delete[](void*, std::size_t)</code></ins></li>
<li><ins><code>operator delete[](void*, std::size_t, const std::nothrow_t&amp;)</code></ins></li>
</ul>
</blockquote>


<h3><a name="support.dynamic">18.6 Dynamic memory management [support.dynamic]</a></h3>

<p>
Edit within the synopsis add the following.
</p>

<blockquote class="std">
<blockquote>
<pre><code>
....
void operator delete(void* ptr) noexcept;
void operator delete(void* ptr, const std::nothrow_t&amp;) noexcept;
<ins>void operator delete(void* ptr, std::size_t size) noexcept;
void operator delete(void* ptr, std::size_t size,
                     const std::nothrow_t&amp;) noexcept;</ins>
....
void operator delete[](void* ptr) noexcept;
void operator delete[](void* ptr, const std::nothrow_t&amp;) noexcept;
<ins>void operator delete[](void* ptr, std::size_t size) noexcept;
void operator delete[](void* ptr, std::size_t size,
                       const std::nothrow_t&amp;) noexcept;</ins>
</code></pre>
</blockquote>
</blockquote>


<h3><a name="new.delete.single">18.6.1.1 Single-object forms [new.delete.single]</a></h3>

<p>
Edit the synopsis before paragraph 10 as follows.
</p>

<blockquote class="std">
<p>
<code>void operator delete(void* ptr) noexcept;<br>
<ins>void operator delete(void* ptr, std::size_t size) noexcept;</ins></code>
</p>
</blockquote>

<p>
Edit paragraph 11 as follows.
</p>

<blockquote class="std">
<p>
<i>Replaceable:</i>
a C++ program may define a function with <del>this function</del> signature
<ins><code>void operator delete(void* ptr) noexcept</code></ins>
that displaces the default version defined by the C++ standard.
<ins>
If this function (without <code>size</code> parameter) is defined,
the program should also define
<code>void operator delete(void* ptr, std::size_t size) noexcept</code>.
If this function with <code>size</code> parameter is defined,
the program
shall also define the version without the <code>size</code> parameter.
[<i>Note:</i>
The default behavior below may change in the future,
which will require replacing both deallocation functions
when replacing the allocation function.
&mdash;<i>end note</i>]
</ins>
</p>
</blockquote>

<p>
After paragraph 13, insert a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
<i>Requires:</i>
If present, the <code>std::size_t size</code> argument
shall equal the size argument passed to the allocation function
that returned <code>ptr</code>.
</p>
</blockquote>

<p>
After paragraph 13, insert a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
<i>Required behavior:</i>
Calls to <code>operator delete(void* ptr, std::size_t size)</code>
may be changed to calls to <code>operator delete(void* ptr)</code>
without affecting memory allocation.
[<i>Note:</i>
A conforming implementation is for 
<code>operator delete(void* ptr, std::size_t size)</code>
to simply call <code>operator delete(ptr)</code>.
&mdash;<i>end note</i>]
</p>
</blockquote>

<p>
Add a new paragraph before paragraph 14 as follows.
</p>

<blockquote class="stdins">
<p>
<i>Default behavior:</i>
the function <code>operator delete(void* ptr, std::size_t size)</code>
calls <code>operator delete(ptr)</code>.
[<i>Note:</i>
See the note in the above <i>Replaceable</i> paragraph.
&mdash;<i>end note</i>]
</blockquote>

<p>
Paragraph 14 is unchanged.
It applies to both functions.
</p>

<blockquote class="std">
If <code>ptr</code> is null, does nothing.
Otherwise, reclaims the storage
allocated by the earlier call to <code>operator new</code>.
</p>
</blockquote>

<p>
Edit the synopsis before paragraph 16 as follows.
</p>

<blockquote class="std">
<p>
<code>void operator delete(void* ptr, const std::nothrow_t&amp;) noexcept;<br>
<ins>void operator delete(void* ptr, std::size_t size, const std::nothrow_t&amp;) noexcept;</ins></code>
</p>
</blockquote>

<p>
Edit paragraph 17 as follows.
</p>

<blockquote class="std">
<p>
<i>Replaceable:</i>
a C++ program may define a function with <del>this function</del> signature
<ins><code>void operator delete(void* ptr,
const std::nothrow_t&amp;) noexcept</code></ins>
that displaces the default version defined by the C++ standard.
<ins>
If this function (without <code>size</code> parameter) is defined,
the program should also define
<code>void operator delete(void* ptr, std::size_t size,
const std::nothrow_t&amp;) noexcept</code>.
If this function with <code>size</code> parameter is defined,
the program
shall also define the version without the <code>size</code> parameter.
[<i>Note:</i>
The default behavior below may change in the future,
which will require replacing both deallocation functions
when replacing the allocation function.
&mdash;<i>end note</i>]
</ins>
</p>
</blockquote>

<p>
After paragraph 18, insert a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
<i>Requires:</i>
If present, the <code>std::size_t size</code> argument
must equal the size argument passed to the allocation function
that returned <code>ptr</code>.
</p>
</blockquote>

<p>
After paragraph 18, insert a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
<i>Required behavior:</i>
Calls to <code>operator delete(void* ptr, std::size_t size,
const std::nothrow_t&amp;)</code>
may be changed to calls to <code>operator delete(void* ptr,
const std::nothrow_t&amp;)</code>
without affecting memory allocation.
[<i>Note:</i>
A conforming implementation is for 
<code>operator delete(void* ptr, std::size_t size,
const std::nothrow_t&amp;)</code>
to simply call <code>operator delete(void* ptr,
const std::nothrow_t&amp;)</code>.
&mdash;<i>end note</i>]
</p>
</blockquote>

<p>
Edit paragraph 19 as follows.
</p>

<blockquote class="std">
<p>
<i>Default behavior:</i>
<ins><code>operator delete(void* ptr, std::size_t size,
const std::nothrow_t&amp;)</code>
calls <code>operator delete(ptr, std::nothrow)</code>, and
<code>operator delete(void* ptr, const std::nothrow_t&amp;)</code></ins>
calls <code>operator delete(ptr)</code>.
</p>
</blockquote>


<h3><a name="new.delete.array">18.6.1.2 Array forms [new.delete.array]</a></h3>

<p>
Edit the synopsis before paragraph 9 as follows.
</p>

<blockquote class="std">
<p>
<code>void operator delete[](void* ptr) noexcept;<br>
<ins>void operator delete[](void* ptr, std::size_t size) noexcept;</ins></code>
</p>
</blockquote>

<p>
Edit paragraph 10 as follows.
</p>

<blockquote class="std">
<p>
<i>Replaceable:</i>
a C++ program may define a function with <del>this function</del> signature
<ins><code>void operator delete[](void* ptr) noexcept</code></ins>
that displaces the default version defined by the C++ standard.
<ins>
If this function (without <code>size</code> parameter) is defined,
the program should also define
<code>void operator delete[](void* ptr, std::size_t size) noexcept</code>.
If this function with <code>size</code> parameter is defined,
the program
shall also define the version without the <code>size</code> parameter.
[<i>Note:</i>
The default behavior below may change in the future,
which will require replacing both deallocation functions
when replacing the allocation function.
&mdash;<i>end note</i>]
</ins>
</p>
</blockquote>

<p>
After paragraph 11, insert a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
<i>Requires:</i>
If present, the <code>std::size_t size</code> argument
must equal the size argument passed to the allocation function
that returned <code>ptr</code>.
</p>
</blockquote>

<p>
After paragraph 11, insert a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
<i>Required behavior:</i>
Calls to <code>operator delete[](void* ptr, std::size_t size)</code>
may be changed to calls to <code>operator delete[](void* ptr)</code>
without affecting memory allocation.
[<i>Note:</i>
A conforming implementation is for 
<code>operator delete[](void* ptr, std::size_t size)</code>
to simply call <code>operator delete[](void* ptr)</code>.
&mdash;<i>end note</i>]
</p>
</blockquote>

<p>
Edit paragraph 13 as follows.
</p>

<blockquote class="std">
<p>
<i>Default behavior:</i>
<ins><code>operator delete[](void* ptr, std::size_t size,
const std::nothrow_t&amp;)</code>
calls <code>operator delete[](ptr, std::nothrow)</code>, and
<code>operator delete[](void* ptr, const std::nothrow_t&amp;)</code></ins>
calls <code>operator delete(ptr)</code>.
</p>
</blockquote>

<p>
Edit the synopsis before paragraph 14 as follows.
</p>

<blockquote class="std">
<p>
<code>void operator delete[](void* ptr, const std::nothrow_t&amp;) noexcept;<br>
<ins>void operator delete[](void* ptr, std::size_t size, const std::nothrow_t&amp;) noexcept;</ins></code>
</p>
</blockquote>

<p>
Edit paragraph 15 as follows.
</p>

<blockquote class="std">
<p>
<i>Replaceable:</i>
a C++ program may define a function with <del>this function</del> signature
<ins><code>void operator delete[](void* ptr,
const std::nothrow_t&amp;) noexcept</code></ins>
that displaces the default version defined by the C++ standard.
<ins>
If this function (without <code>size</code> parameter) is defined,
the program should also define
<code>void operator delete[](void* ptr, std::size_t size,
const std::nothrow_t&amp;) noexcept</code>.
If this function with <code>size</code> parameter is defined,
the program
shall also define the version without the <code>size</code> parameter.
[<i>Note:</i>
The default behavior below may change in the future,
which will require replacing both deallocation functions
when replacing the allocation function.
&mdash;<i>end note</i>]
</ins>
</p>
</blockquote>

<p>
After paragraph 16, insert a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
<i>Requires:</i>
If present, the <code>std::size_t size</code> argument
must equal the size argument passed to the allocation function
that returned <code>ptr</code>.
</p>
</blockquote>

<p>
After paragraph 16, insert a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
<i>Required behavior:</i>
Calls to <code>operator delete[](void* ptr, std::size_t size,
const std::nothrow_t&amp;)</code>
may be changed to calls to <code>operator delete[](void* ptr,
const std::nothrow_t&amp;)</code>
without affecting memory allocation.
[<i>Note:</i>
A conforming implementation is for 
<code>operator delete[](void* ptr, std::size_t size,
const std::nothrow_t&amp;)</code>
to simply call <code>operator delete[](void* ptr,
const std::nothrow_t&amp;)</code>.
&mdash;<i>end note</i>]
</p>
</blockquote>

<p>
Edit paragraph 17 as follows.
</p>

<blockquote class="std">
<p>
<i>Default behavior:</i>
<ins><code>operator delete[](void* ptr, std::size_t size,
const std::nothrow_t&amp;)</code>
calls <code>operator delete[](ptr, std::nothrow)</code>, and
<code>operator delete[](void* ptr, const std::nothrow_t&amp;)</code></ins>
calls <code>operator delete[](ptr)</code>.
</p>
</blockquote>

<h3><a name="allocator.members">20.8.9.1 <code>allocator</code> members [allocator.members]</a></h3>

<p>
Edit paragraph 10 as follows.
</p>

<blockquote class="std">
<p>
<i>Remark:</i>
Uses <code>::operator delete(void*<ins>, std::size_t</ins>)</code> (18.6.1),
but it is unspecified when this function is called.
</p>
</blockquote>


<h3><a name="diff.cpp11.basic">C.?.? Clause 3: Basic concepts [diff.cpp11.basic]</a></h3>

<p>
Add a new paragraph as follows.
</p>

<blockquote class="stdins">
<p>
<b>Change:</b>
New usual (non-placement) deallocator
<br>
<b>Rationale:</b>
Required for new features.
<br>
<b>Effect on original feature:</b>
In C++ 2011,
one could declare a global placement allocation function
and deallocation function as follows.
</p>
<pre>
<code>void operator new(std::size_t, std::size_t);
void operator delete(void*, std::size_t) noexcept;</code>
</pre>
<p>
Now, however, the declaration of <code>operator delete</code>
might match a predefined usual (non-placement) <code>operator delete</code>
(3.7.4 [basic.stc.dynamic]).
If so, the program is ill-formed,
as it was for class member allocation functions and deallocation functions
(5.3.4 [new.expr]).
</p>
</blockquote>


<h2><a name="Revision">Revision History</a></h2>

<p>
This paper revises N3663 - 2013-04-30 as follows.
</p>

<ul>

<li><p>
Update the base document.
Change paragraph numbers.
Remove uses of <code>throws(std::bad_alloc)</code>.
</p></li>

<li><p>
Make implementation support of sized deallocation mandatory.
</p></li>

<li><p>
Clarify precluding placement in 3.7.4.2/2.
</p></li>

<li><p>
Change the handling of placement matching in 5.3.4/22.
</p></li>

<li><p>
Change the handling of implicit deallocation lookup within new expressions
to use normal lookup for the non-placement case in 5.3.4/22.
</p></li>

<li><p>
Replaces uses of "deallocation[s]" refering to functions
with "deallocation function[s]"
in 5.3.5/9.
</p></li>

<li><p>
Replaces uses of "two parameter style"
with "two parameter deallocation function"
in 5.3.5/9.
</p></li>

<li><p>
Add clarifying comma to the last new paragraph in 5.3.5.
</p></li>

<li><p>
Remove
"the class-specific deallocation function lookup has failed"
from text newly inserted in 12.5/4.
</p></li>

<li><p>
Define the default behavior of the sized deallocation functions
to call the unsized deallocations in 18.6.1.
See
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2158.html">
N2158 LWG Issue 206 Linking new/delete operators</a>.
Add a note warning that this may change in the future.
Update the Backwards Compatibility section to reflect the change.
</p></li>

<li><p>
Change <code>std::allocator</code>
to call the sized deallocator in 20.8.9.1.
</p></li>

</ul>

<p>
N3663 revised N3536 as follows.
</p>

<ul>

<li><p>
Revise and clarify the backwards compatibility discussion.
Remove the constraint that
programs defining one deallocator version and not the other
are ill-formed.
</p></li>

<li><p>
Revise and clarify the library sections.
</p></li>

<li><p>
Add a discussion on placement new compatibility.
</p></li>

<li><p>
Change no-throw declarations to no-except declarations.
</p></li>

</ul>

<p>
N3536 revised N3432 - 2012-09-23 as follows.
</p>

<ul>

<li><p>
Provide names for potential solution problems.
</p></li>

<li><p>
Clarify compatibility concerns.
</p></li>

<li><p>
Require a diagnostic when an incompatiblity is detected.
</p></li>

<li><p>
Add a 'Revision History' section.
</p></li>

</ul>


<h2><a name="References">References</a></h2>

<dl>

<dt><a name="TCM">[TCM]</a></dt>
<dd>
<cite>TCMalloc : Thread-Caching Malloc</cite>,
<a href="http://goog-perftools.sourceforge.net/doc/tcmalloc.html">
http://goog-perftools.sourceforge.net/doc/tcmalloc.html</a>.
</dd>

</dl>

</body>
</html>
