<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type"
    content="text/html; charset=us-ascii" />
  <title>Dynamic memory allocation for over-aligned data</title>
  <style type="text/css">
    .decl {
      margin-left: -0.5in;
    }

    .right {
      float: right;
    }

    .new {
      border-style: solid;
      border-width: thin;
    }

    .ed {
      background-color: #FF9;
      font-style: italic;
    }

      .ed:before {
        content: "[";
      }

      .ed:after {
        content: "]";
      }

    div.new {
      padding: 0 1em 0 1em;
    }

    p.numbered {
      text-indent: -0.5in;
      counter-increment: p;
    }

      p.numbered:before {
        content: counter(p) "\A0\A0\A0";
      }

    h4 {
      counter-reset: p;
    }

    del {
      background-color: #FCC;
    }

    ins {
      background-color: #CFC;
    }

    pre, ul {
      background-color: inherit;
    }
  </style>
</head>
<body>
  <table border="1" class="right">
    <tbody>
      <tr>
	<th>Doc. No.:</th>
	<td>P0035R1</td>
      </tr>
      <tr>
	<th>Revises:</th>
	<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3396.htm">N3396</a></td>
      </tr>
      <tr>
	<th>Date:</th>
	<td>2015-12-29</td>
      </tr>
      <tr>
	<th>Reply to:</th>
	<td>Clark Nelson</td>
      </tr>
      <tr>
	<th>Phone:</th>
	<td>+1-503-712-8433</td>
      </tr>
      <tr>
	<th>Email:</th>
	<td><a href="mailto:clark.nelson@intel.com">clark.nelson@intel.com</a></td>
      </tr>
      <tr>
	<th>Audience:</th>
	<td>Core, Library Evolution</td>
      </tr>
    </tbody>
  </table>
  <h1>Dynamic memory allocation for over-aligned data</h1>
  <h2>Problem statement</h2>
  <p>To codify widespread existing practice,
    C++11 added the ability to specify increased alignment
    (a.k.a. over-alignment) for class types.
    Unfortunately (but also consistently with existing practice),
    C++11 did not specify any mechanism
    by which over-aligned data can be dynamically allocated correctly
    (i.e. respecting the alignment of the data).
    For example:</p>
  <pre>class alignas(16) float4 {
	float f[4];
};
float4 *p = new float4[1000];</pre>
  <p>In this example,
    not only is an implementation of C++ <strong>not</strong> required
    to allocate properly-aligned memory for the array,
    for practical purposes it is very nearly required
    to do the allocation incorrectly.
    In any event,
    it is certainly required to perform the allocation by a process
    that does <strong>not</strong> take the specified alignment
    value into account.</p>
  <p>This represents a hole in the support for alignment in the language,
    which really needs to be filled.</p>
  <div class="new">
    <h2>History</h2>
    <p>With the exception of new paragraphs, which are boxed,
      and a few updates taking into account recent WD changes
      (mostly sized deallocation),
      this document is substantially the same as N3396,
      which was discussed by EWG at the 2012 Portland meeting.</p>
    <p>Since that time, Intel has released a compiler
      that largely implements the language changes discussed herein,
      except that, to guarantee backward compatibility,
      the additional overloads are declared in a new header
      (<code>&lt;aligned_new&gt;</code>),
      instead of being predeclared or
      declared in <code>&lt;new&gt;</code>.</p>
    <p>To date,
      there has not yet been enough experience with the implementation
      to prove its viability.
      Nevertheless, it seems appropriate
      to get this issue back on the committee's radar,
      so that a decision can be made about it
      for the C++17 time frame.</p>
    <h2>Acknowledgements</h2>
    <p>Pablo Halpern has provided me with much valuable feedback
      and assistance.</p>
  </div>
  <h2>Design considerations</h2>
  <h3>Backward compatibility</h3>
  <p>One of the first questions that needs to be settled
    about the future direction is
    the degree to which backward compatibility with C++11/14
    needs to be maintained.
    On the one hand, in an ideal world, for an example like the one above,
    it would be obvious that the specified alignment
    should be honored.</p>
  <p>On the other hand,
    there's no way to achieve that ideal
    without at least potentially changing the behavior
    of some programs conforming to an earlier standard.
    For example, a program might asssume control of dynamic allocation
    through the use of class-specific <code>operator new</code>
    and <code>operator delete</code> functions,
    or by replacing the global functions.
    These functions don't take any alignment argument.
    If a different function is used instead,
    which is somehow passed an alignment value,
    some degree of backward compatibility is lost.</p>
  <p>When backward compatibility
    and the ideal future direction are in conflict,
    which should take precedence, and to what degree?</p>
  <p>If perfect backward compatibility were required,
    one way to ensure that might be to require that a new header
    &mdash; say <code>&lt;aligned_new&gt;</code> &mdash;
    be included in order to get new dynamic allocation
    for over-aligned types.
    But that would sacrifice convenience and/or correctness;
    using <code>alignas</code> by itself would presumably never be enough
    to get correctly aligned dynamic allocation.</p>
  <p>Another obvious position to take
    would be that backward compatibility with C++98,
    which had no alignment specifier, needs to be complete.
    This might suggest that dynamic allocation should differ
    between types involving alignment specifiers
    and types that don't &mdash;
    which some might consider to be an unfortunate complication.</p>
  <p>In C++11/14, when an over-aligned class type
    has its own dynamic memory allocation functions,
    it would be reasonable to hope
    that those functions already do the right thing
    with respect to alignment, and dangerous to make any change.
    However, the only way over-alignment could be accommodated
    by global allocation and deallocation functions
    would be to replace them with functions
    that always provide the strictest alignment
    used by any type in the program.
    It may be reasonable to assume
    that very few programs go to that length,
    instead of using class-specific allocation/deallocation.</p>
  <p>Therefore, it may be acceptable to abandon backward compatibility
    with C++14 with respect to calling a global allocation function
    for dynamic allocation of an over-aligned type.
    But if so, that may well be the only acceptable case.</p>
  <h3>Passing the alignment value</h3>
  <p>To minimize the possibility of conflict
    with existing placement allocation functions,
    it might be advisable to invent a new standard enumeration type
    to use for alignment parameters; for example:</p>
  <pre>namespace std {
	enum class align_val_t: size_t;
};
void *operator new(std::size_t, std::align_val_t);	// new overload</pre>
  <p>It's not clear that this type would need
    any named constants of its own;
    it just needs to be able to represent alignment values,
    which are associated with type <code>size_t</code>.
    It should perhaps nevertheless be a scoped enumeration,
    to prevent the possibility that a value of that type
    would inadvertently be converted to some integer type,
    and match an existing placement allocation function.</p>
  <p>If an allocation function that takes an alignment value is available,
    it should be used, for the sake of generality;
    but if no such function is available,
    a function that doesn't take one should be used,
    for backward compatibility.
    This suggests a new rule for new-expressions:
    attempting to find an allocation function in two phases,
    with two different sets of arguments.
    <!--But Pablo Halpern suggested a different possibility,
	which wouldn't require a special meta-overload-resolution rule:-->
  </p>
  <!--
    <pre>namespace std {
	class aligned_size {
		size_t size, alignment;
	public:
		aligned_size(size_t size, size_t alignment);
		operator size_t();	// returns the size
	};
};
void *operator new(std::aligned_size);	// new overload</pre>
    <p>If for <code>new T</code> the compiler synthesized a call
	to <code>operator new(aligned_size(sizeof(T), alignof(T))</code>,
	the existing overload resolution rules would prefer a function
	with an <code>aligned_size</code> parameter,
	but would accept a function
	with a <code>size_t</code> parameter instead.</p>
    <p>The advantage of this approach
	is that no new language rule related to overload resolution
	would be needed.
	One disadvantage would be that it would be necessary to relax
	the current restriction that the first parameter
	of an allocation function have type <code>size_t</code>;
	it's not clear exactly what (if anything) should then be disallowed.
	Another disadvantage is that there would be
	a new language-support component of the library,
	on which the compiler would depend for correctness.
	The standard might not need to say anything about this,
	but for backward compatibility compilers might need to continue
	to use the old method
	if <code>std::aligned_size</code> is not defined.</p>
    <p>(It could be argued that the above <code>align_val_t</code> type
	would also imply a dependency by the compiler on the library,
	but that would actually involve far fewer necessary assumptions
	by the compiler.)</p>
    -->
  <h3>Class-specific allocation and deallocation</h3>
  <p>It should be kept in mind that,
    under the current language rules,
    any class-specific allocation functions effectively hide
    all global allocation functions,
    including the ones in the standard library.
    For example, the following is invalid:</p>
  <pre>#include &lt;new&gt;
class X {
	void *operator new(size_t);
	// no operator new(size_t, std::nothrow_t&amp;)
	void operator delete(void *);
};
X *p1 = new X;		// uses X::operator new(size_t)
X *p2 = new(nothrow) X;	// error
// ::operator new(size_t, std::nothrow_t&amp;) is not considered</pre>
  <p>It is possible to imagine adjusting the rules
    to enable finding an alignment-aware allocation function more often,
    but that would also make it more likely
    that some programmers would write programs believing
    &mdash; incorrectly &mdash;
    that they have taken over complete control
    of the way that their class is dynamically allocated.</p>
  <h3>Unified vs. distinct arenas</h3>
  <p>What implementation techniques should the standard allow
    for allocation and deallocation of aligned memory?</p>
  <p>In POSIX, there is a function named <code>posix_memalign</code>
    that can allocate over-aligned memory;
    <code>free</code> is used to free the blocks it allocates.</p>
  <p>On Windows, on the other hand, of course <code>malloc</code>,
    <code>realloc</code> and <code>free</code> are supported
    for default-aligned memory.
    In addition, for over-aligned memory, there are functions named
    <code>_aligned_malloc</code>, <code>_aligned_realloc</code>,
    and <code>_aligned_free</code>.
    Memory that's allocated by <code>_aligned_malloc</code>
    must be freed by <code>_aligned_free</code>,
    and memory that's allocated by <code>malloc</code>
    must be freed by <code>free</code>.
    So logically, there are two disjoint, non-interoperable memory arenas;
    the program has to know to which arena a block belongs
    (i.e. how it was allocated)
    in order to be able to free it.</p>
  <p>This is almost certain to be true of any implementation
    where over-aligned memory allocation is layered
    on top of &ldquo;plain old&rdquo; default-aligned memory allocation.
    There are probably many such implementations,
    and they're not likely to go away soon.</p>
  <p>In an environment where information about the method used
    to allocate a block of memory can be lost,
    having distinct arenas (i.e. distinct deallocation functions)
    could be inconvenient.
    A program whose operation depends on the assumption
    that <code>operator new</code> is equivalent to <code>malloc</code>
    is effectively an environment where information about the method
    used to allocate a block of memory is lost.</p>
  <p>But in a well-written, portable C++ program,
    at the point where memory is deallocated,
    the type of the object being deleted &mdash;
    and therefore whether it is over-aligned &mdash; is known.
    This knowledge could, and probably should,
    be used to support layered implementations
    of over-aligned memory allocation.</p>
  <p>This implies that, just as a new-expression for an over-aligned type
    should look for an alignment-aware allocation function,
    so should a delete-expression for a pointer to an over-aligned type
    look for an alignment-aware deallocation function.
    Presumably this would be done by selecting a deallocation function
    to which the alignment value can be passed,
    even though probably very few implementations
    will actually have any use for that value.</p>
  <div class="new">
    <h3>Nitty-gritty</h3>
    <p>For exactly what classes should the allocation method change?
      Plausible answers include:</p>
    <ol>
      <li>Those affected by an <code>alignas</code>
	that actually specifies over-alignment.</li>
      <li>Those affected by an explicit <code>alignas</code>,
	even if the alignment value is basic (i.e. small).</li>
    </ol>
    <p>The first answer seems to be right from a pragmatic perspective,
      but one consequence is that the behavior of a program might depend
      (in a new way)
      on an implementation-defined parameter.
      But if the only difference between alignment-aware
      and alignment-unaware
      allocation/deallocation functions
      is the actual allocation mechanism
      (i.e., in a well-designed program),
      this should not be a problem.
      It's rather like the implementation's license
      to elide certain copies,
      which implies that a copy constructor
      had really better just make a copy.</p>
    <p>The below WD changes use the first answer,
      through use of &ldquo;over-aligned&rdquo;.
      The Intel implementation uses the first answer by default,
      but has a command-line option to select the second answer,
      for the sake of experimentation.</p>
    <p>Also, it should be noted that the over-alignment threshold
      used by the Intel implementation doesn't exactly match
      the standard's definition of basic alignment.
      The threshold used is actually the alignment
      observed to be guaranteed
      by the implementation of <code>malloc</code>
      for the target environment.
      (In all of the environments tested,
      this turned out to be twice the size of a pointer.)</p>
    <p>Assuming the existence of a variety of allocation functions,
      which one should be used for an over-aligned allocation?
      I believe the answer should be
      the first one from the following list that is known to exist:</p>
    <ol>
      <li>class-specific and alignment-aware</li>
      <li>class-specific and alignment-unaware</li>
      <li>global and alignment-aware</li>
      <li>[global and alignment-unaware]</li>
    </ol>
    <p>It makes sense for a class-specific,
      alignment-unaware allocation function to be preferred
      over one that is global and alignment-aware,
      because there are many cases
      where a class-specific allocation function has enough information,
      even without an explicit parameter,
      to do the allocation with sufficient alignment.
      (Likely exceptions include
      a template class with a base or member
      of a type that is a template parameter,
      and a derived class that inherits its allocation function
      from a base class,
      and also adds a member or base of over-aligned type.)</p>
    <p>If a global, alignment-aware allocation function is predeclared,
      then it will never be necessary
      to use a global, alignment-unaware allocation function
      for an over-aligned type;
      hence the brackets around item 4.</p>
    <p>It should be noted that an alignment-aware allocation function
      would be perfectly capable of performing an alignment
      that would suffice for an alignment-unaware function.
      In other words, from some perspective,
      it would make sense to let <code>operator new(size_t)</code>
      call <code>operator new(size_t, align_val_t)</code>,
      filling in the alignment value that it feels it needs to satisfy,
      and move the allocation loop to the alignment-aware function.
      But that would be pretty novel,
      so I have chosen not to propose it.</p>
  </div>
  <h2>Outline of possible working paper changes</h2>
  <div class="new">
    <p>The following changes are believed to be substantially complete.
      The particularly important changes are presented first.</p>
  </div>
  <p>Mainly for simplicity,
    here I suggest that the new overloads
    should be added to <code>&lt;new&gt;</code>,
    and for consistency with that,
    that they should also be predeclared.
    But if 100% backward compatibility with C++14 is considered necessary,
    then the new overloads probably need to be declared
    in a new library header (possibly <code>&lt;aligned_new&gt;</code>).
    It's also possible to imagine
    requiring the declarations be in a new header,
    but making it implementation-defined whether that header
    is included by <code>&lt;new&gt;</code>,
    perhaps with the expectation
    that the actual choice will be left to users,
    under the control of a command-line option or macro setting.</p>
  <p>There is one change of terminology worth noting.
    Today, the phrase &ldquo;placement new&rdquo; is ambiguous.
    In some contexts it means adding arguments
    to a call to an allocation function,
    with any types and unspecified purpose.
    In other contexts,
    it is used to refer specifically to cases
    where there is a single additional argument
    of type <code>void *</code>,
    in which case the allocation function
    doesn't actually allocate anything.
    I refer to the latter cases as &ldquo;non-allocating&rdquo;,
    and refer to &ldquo;allocating&rdquo; cases
    to distinguish them when necessary.</p>
  <h3>Principal changes</h3>
  <p>These introduce the required new library functions,
    and specify the language rules that trigger their use.</p>
  <p>Change 18.6, header <code>&lt;new&gt;</code> synopsis:</p>
  <blockquote>
    <pre>namespace std {
	class bad_alloc;
	class bad_array_new_length;
	<ins>enum class align_val_t: size_t;</ins>
	struct nothrow_t {};
	extern const nothrow_t nothrow;
	typedef void (*new_handler)();
	new_handler get_new_handler() noexcept;
	new_handler set_new_handler(new_handler new_p) noexcept;
};
void* operator new(std::size_t size);
void* operator new(std::size_t size, const std::nothrow_t&amp;) noexcept;
void operator delete(void* ptr) noexcept;
void operator delete(void* ptr, const std::nothrow_t&amp;) noexcept;
void operator delete(void* ptr, std::size_t size) noexcept;
void* operator new[](std::size_t size);
void* operator new[](std::size_t size, const std::nothrow_t&amp;) noexcept;
void operator delete[](void* ptr) noexcept;
void operator delete[](void* ptr, const std::nothrow_t&amp;) noexcept;
void operator delete[](void* ptr, std::size_t size) noexcept;
</pre>
    <ins>
      <pre>void* operator new(std::size_t size, std::align_val_t alignment);
void* operator new(std::size_t size, std::align_val_t alignment,
			const std::nothrow_t&amp;) noexcept;
void operator delete(void* ptr, std::align_val_t alignment) noexcept;
void operator delete(void* ptr, std::align_val_t alignment,
			std::nothrow_t&amp;) noexcept;
void operator delete(void* ptr, std::align_val_t alignment,
			std::size_t size) noexcept;
void* operator new[](std::size_t size, std::align_val_t alignment);
void* operator new[](std::size_t size, std::align_val_t alignment,
			const std::nothrow_t&amp;) noexcept;
void operator delete[](void* ptr, std::align_val_t alignment) noexcept;
void operator delete[](void* ptr, std::align_val_t alignment,
			const std::nothrow_t&amp;) noexcept;
void operator delete[](void* ptr, std::align_val_t alignment,
			std::size_t size) noexcept;</pre>
    </ins>
    <pre>void* operator new&nbsp;&nbsp;(std::size_t size, void* ptr) noexcept;
void* operator new[](std::size_t size, void* ptr) noexcept;
void operator delete&nbsp;&nbsp;(void* ptr, void*) noexcept;
void operator delete[](void* ptr, void*) noexcept;</pre>
  </blockquote>
  <p>Change 5.3.4p13:</p>
  <blockquote>
    <p>The <var>new-placement</var> syntax <del>is</del>
      <ins>may be</ins> used
      to supply additional arguments to an allocation function.
      <del>If used, overload</del> <ins>Overload</ins> resolution
      is performed on a function call
      created by assembling an argument list<ins>.</ins>
      <del>consisting of</del>
      <ins>The first argument is</ins> the amount of space requested
      <del>(the first argument)</del>
      <ins>, and has type <code>std::size_t</code>.
      If the type of the allocated object is over-aligned,
      the next argument is the type's alignment,
      and has type <code>std::align_val_t</code>.</ins>
      <del>and the</del>
      <ins>If the <var>new-placement</var> syntax is used, its</ins>
      expressions
      <del>in the <var>new-placement</var> part
	of the <var>new-expression</var> (</del>
      are the <del>second and</del> succeeding arguments<del>)</del>.
      <del>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>.</del>
      <ins>If no matching function is found
	and the allocated object type is over-aligned,
	the alignment argument is removed from the argument list,
	and overload resolution is performed again.</ins></p>
  </blockquote>
  <p>Change 5.3.4p14:</p>
  <blockquote>
    <p>[ <em>Example:</em></p>
    <ul>
      <li><code>new T</code> results in a call of <ins>either</ins>
	<code>operator new(sizeof(T))</code>
	<ins>or <code>operator new(sizeof(T),
	  static_cast&lt;std::align_val_t&gt;(alignof(T)))</code></ins>,</li>
      <li><code>new(2,f) T</code> results in a call of <ins>either</ins>
	<code>operator new(sizeof(T),2,f)</code>
	<ins>or <code>operator new(sizeof(T),
	  static_cast&lt;std::align_val_t&gt;(alignof(T)),2,f)</code></ins>,</li>
      <li><code>new T[5]</code> results in a call of <ins>either</ins>
	<code>operator new[](sizeof(T)*5+x)</code>
	<ins>or <code>operator new[](sizeof(T)*5+x,
	  static_cast&lt;std::align_val_t&gt;(alignof(T)))</code></ins>, and</li>
      <li><code>new(2,f) T[5]</code> results in a call of
	<ins>either</ins>
	<code>operator new[](sizeof(T)*5+y,2,f)</code>
	<ins>or <code>operator new[](sizeof(T)*5+y,
	  static_cast&lt;std::align_val_t&gt;(alignof(T)),2,f)</code></ins>.</li>
    </ul>
    <p>...</p>
  </blockquote>
  <div class="new">
    <p>Change 3.7.4.2p2:</p>
    <blockquote>
      <p>Each deallocation function shall return <code>void</code>
	and its first parameter shall be <code>void*</code>.
	A deallocation function <del>can</del> <ins>may</ins> have
	more than one parameter.
	<del>The global <code>operator delete</code>
	  with exactly one parameter
	    is a usual (nonplacement) 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.<sup>37</sup>
	  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 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.
	    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.</del>
	<ins>A <dfn>usual deallocation function</dfn>
	  is a deallocation function that has:</ins></p>
      <ins>
	<ul>
	  <li>exactly one parameter; or</li>
	  <li>exactly two parameters,
	    the type of the second being
	    either <code>std::align_val_t</code>
	    or <code>std::size_t</code><sup>37)</sup>; or</li>
	  <li>exactly three parameters,
	    the type of the second being <code>std::align_val_t</code>
	    and the type of the third
	    being <code>std::size_t</code>.</li>
	</ul>
      </ins>
      <p><em>Footnote:</em>
	37) <del>This deallocation function</del>
	<ins>The global
	  <code>operator delete[](void*, std::size_t)</code></ins>
	precludes use
	of an allocation function
	<code>void operator new(std::size_t, std::size_t)</code>
	as a placement allocation function (C.3.2).</p>
      <p>A deallocation function <del>can</del> <ins>may</ins>
	be an instance of a function template.
	Neither the first parameter nor the return type
	shall depend on a template parameter.
	[ <em>Note:</em> 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). <em>&mdash;end note</em> ]
	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>
    <p>Adding the new overloads
      to the set of "usual" deallocation functions
      in the same style as the previous formulation
      would have required outrageous verbosity.
      My new formulation is much more concise
      and (to my eyes) comprehensible,
      but there is a technical difference worth noting.</p>
    <p>Previously, in class scope, if deallocation functions
      with and without a size parameter are both declared,
      the one with the size parameter was not "usual".
      My simpler formulation includes both overloads.
      But it is not difficult to tweak the selection algorithm
      to produce the same result as previously.</p>
    <p>Change 5.3.5p10:</p>
    <blockquote>
      <p>If deallocation function lookup finds <del>both
	a</del> <ins>more than one</ins> usual deallocation function
	<del>with only a pointer parameter and
	a usual deallocation function with both a pointer parameter
	and a size parameter</del>,
	the function to be called is selected as follows:</p>
      <ul>
	<li><ins>If the type is over-aligned,
	    a function with an alignment parameter is preferred;
	    otherwise a function with no alignment parameter
	    is preferred.
	    If exactly one preferred function is available,
	    that function is selected
	    and the selection process terminates.
	    If more than one preferred function is available,
	    all non-preferred functions
	    are eliminated from further consideration.</ins></li>
	<li><ins>If the deallocation functions have class scope,
	    the one without a size parameter is selected.</ins></li>
	<li>If the type is complete and if,
	  for the second alternative (delete array) only,
	  the operand is a pointer to a class type
	  with a non-trivial destructor
	  or a (possibly multi-dimensional) array thereof,
	  the function with <del>two parameters</del>
	  <ins>a size parameter</ins> is selected.</li>
	<li>Otherwise, it is unspecified
	  <del>which of the two deallocation functions</del>
	  <ins>whether a deallocation function
	    with a size parameter</ins> is selected.</li>
      </ul>
    </blockquote>
    <p><strong>ISSUE:</strong> What if a class has a trivial destructor
      and only one usual deallocation function, taking a size?
      What value is allowed (or required)
      to be passed as the size argument
      when an array of such type is deleted?
      Should such a class be ill-formed?</p>
    <p>Change 5.3.5p11:</p>
    <blockquote>
      <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<ins>.
	  If a deallocation function with an alignment parameter
	  is used,
	  the alignment of the type is passed
	  as the corresponding argument.</ins>
	<del>and (if the two-parameter</del>
	<ins>If a</ins>
	deallocation function
	<ins>with a size parameter</ins>
	is used<del>)</del><ins>,</ins>
	the size of the block <ins>is passed</ins>
	as <del>its second</del>
	<ins>the corresponding</ins> argument.<sup>82</sup></p>
    </blockquote>
  </div>
  <h3>Consequent changes</h3>
  <p>Most of these changes are just reflecting the implications
    of the above changes through the rest of the document.</p>
  <p>If the new overloads should be predeclared, change 3.7.4p2:</p>
  <blockquote>
    <p>The library provides default definitions
      for the global allocation and deallocation functions.
      Some global allocation and deallocation functions
      are replaceable (18.6.1).
      A C++ program shall provide at most one definition
      of a replaceable allocation or deallocation function.
      Any such function definition replaces the default version
      provided in the library (17.6.4.6).
      The following allocation and deallocation functions (18.6)
      are implicitly declared in global scope
      in each translation unit of a program.</p>
    <pre>void* operator new(std::size_t);
void* operator new[](std::size_t);
void operator delete(void*);
void operator delete[](void*);
void operator delete(void*, std::size_t);
void operator delete[](void*, std::size_t);</pre>
    <ins>
      <pre>void* operator new(std::size_t, std::align_val_t);
void* operator new[](std::size_t, std::align_val_t);
void operator delete(void*, std::align_val_t);
void operator delete[](void*, std::align_val_t);
void operator delete(void*, std::align_val_t, std::size_t);
void operator delete[](void*, std::align_val_t, std::size_t);</pre>
    </ins>
    <p>These implicit declarations introduce only the function names
      <code>operator new</code>, <code>operator new[]</code>,
      <code>operator delete</code>, and <code>operator delete[]</code>.
      [ <em>Note:</em> The implicit declarations do not introduce
      the names <code>std</code>,
      <code>std::size_t</code>,
      <ins><code>std::align_val_t</code>,</ins>
      or any other names that the library uses to declare these names.
      Thus, a <var>new-expression</var>, <var>delete-expression</var>
      or function call that refers to one of these functions
      without including the header <code>&lt;new&gt;</code>
      is well-formed.
      However, referring to <code>std</code> or
      <code>std::size_t</code>
      <ins>or <code>std::align_val_t</code></ins>
      is ill-formed unless the name has been declared
      by including the appropriate header.
      &mdash;<em>end note</em>]
      Allocation and/or deallocation functions <del>can</del>
      <ins>may</ins> also be declared and defined
      for any class (12.5).</p>
  </blockquote>
  <div class="new">
    <p>Change 3.7.4p1:</p>
    <blockquote>
      <p>Objects can be created dynamically
	during program execution (1.9),
	using <var>new-expressions</var> (5.3.4), and
	destroyed using <var>delete-expressions</var> (5.3.5).
	A C++ implementation provides access to,
	and management of, dynamic storage
	via the global <dfn>allocation functions</dfn>
	<code>operator new</code> and <code>operator new[]</code>
	and the global <dfn>deallocation functions</dfn>
	<code>operator delete</code>
	and <code>operator delete[]</code>.
	<ins>[ <em>Note:</em> The non-allocating forms
	  described in [new.delete.placement]
	  are, semantically speaking,
	  not allocation or deallocation functions.
	  &mdash;<em>end note</em>]</ins></p>
    </blockquote>
    <p>This is intended as a clarification
      of what seems already to be implied by [new.delete.placement]:</p>
    <blockquote>
      <p>The provisions of (3.7.4) do not apply
	to these reserved placement forms of
	<code>operator new</code> and <code>operator delete</code>.</p>
    </blockquote>
  </div>
  <p>Change 3.7.4.2p3:</p>
  <blockquote>
    <p>If a deallocation function terminates by throwing an exception,
      the behavior is undefined.
      The value of the first argument
      supplied to a deallocation function
      may be a null pointer value;
      if so, and if the deallocation function
      is one supplied in the standard library,
      the call has no effect.
      <del>Otherwise, the behavior is undefined
	if the value supplied to <code>operator delete(void*)</code>
	in the standard library is not one of the values
	returned by a previous invocation
	of either <code>operator new(std::size_t)</code>
	or <code>operator new(std::size_t,
	const std::nothrow_t&amp;)</code>
	in the standard library, and the behavior is undefined
	if the value supplied to <code>operator delete[](void*)</code>
	in the standard library is not one of the values returned
	by a previous invocation
	of either <code>operator new[](std::size_t)</code>
	or <code>operator new[](std::size_t,
	  const std::nothrow_t&amp;)</code>
	in the standard library.</del></p>
  </blockquote>
  <p>These requirements apply only to the library implementations,
    and are already stated in 18.6.</p>
  <p>Change 3.7.4.3p2:</p>
  <blockquote>
    <p>A pointer value is a <dfn>safely-derived pointer</dfn>
      to a dynamic object only if
      it has an object pointer type and it is one of the following:</p>
    <ul>
      <li>the value returned by a call
	to the C++ standard library implementation of
	<code>::operator new(std::size_t)</code>
	<ins>or <code>::operator new(std::size_t,
	  std::align_val_t)</code></ins>;<sup>37</sup></li>
      <li>...</li>
    </ul>
  </blockquote>
  <div class="new">
    <p>Change 5.3.4p1:</p>
    <blockquote>
      <p>The <var>new-expression</var> attempts to create
	an object of the <var>type-id</var> (8.1)
	or <var>new-type-id</var>
	to which it is applied.
	The type of that object is the <dfn>allocated type</dfn>.
	This type shall be a complete object type,
	but not an abstract class type
	or array thereof (1.8, 3.9, 10.4).
	<del>It is implementation-defined whether over-aligned types
	are supported (3.11).</del> [ <em>Note:</em> ...</p>
    </blockquote>
    <p>Change 5.3.4p8:</p>
    <blockquote>
      <p>A <var>new-expression</var> may obtain storage
	for the object by calling an allocation function (3.7.4.1).
	If the <var>new-expression</var> terminates
	by throwing an exception,
	it may release storage
	by calling a deallocation function (3.7.4.2).
	If the allocated type is a non-array type,
	the allocation functions name
	is <code>operator new</code>
	and the deallocation functions name
	is <code>operator delete</code>.
	If the allocated type is an array type,
	the allocation functions name
	is <code>operator new[]</code>
	and the deallocation functions name
	is <code>operator delete[]</code>.
	[ <em>Note:</em>
	an implementation shall provide default definitions
	for the global allocation functions (3.7.4, 18.6.1.1, 18.6.1.2).
	A C++ program can provide alternative definitions
	of these functions (17.6.4.6)
	and/or class-specific versions (12.5).
	<ins>The set of allocation and deallocation functions
	  that may be called by a <var>new-expression</var>
	  includes functions that are, semantically speaking,
	  not allocation or deallocation functions;
	  for example, see [new.delete.placement].</ins>
	&mdash;<em>end note</em> ]</p>
    </blockquote>
    <p>Change 5.3.4p22:</p>
    <blockquote>
      <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.
	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 <del>the two-parameter form of</del>
	a usual deallocation function
	<ins>with a size parameter</ins> (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.
	For a non-placement allocation function,
	the normal deallocation function lookup is used
	to find the matching deallocation function (5.3.5)</p>
    </blockquote>
    <p>Change 5.3.5p5:</p>
    <blockquote>
      <p>If the object being deleted
	has incomplete class type at the point of deletion
	and the complete class
	<ins>is over-aligned or</ins>
	has a non-trivial destructor or a deallocation function,
	the behavior is undefined.</p>
    </blockquote>
    <p>Consider whether to change 17.6.3.5p10:</p>
    <blockquote>
      <p>If the alignment associated with a specific over-aligned type
	is not supported by an allocator,
	instantiation of the allocator for that type may fail.
	The allocator also may silently ignore the requested alignment.
	[ <em>Note:</em>
	Additionally, the member function <code>allocate</code>
	for that type may fail by throwing
	an object of type <code>std::bad_alloc</code>.
	&mdash;<em>end note</em> ]</p>
    </blockquote>
    <p>Even if the standard allocator is required
      to handle arbitrary alignments,
      it may be reasonable not to make the same requirement
      of user-defined allocators.</p>
  </div>
  <p>Change 17.6.4.6p2:</p>
  <blockquote>
    <p>A C++ program may provide the definition
      for any of <del>twelve</del> <ins>the following</ins>
      dynamic memory allocation function signatures
      declared in header <code>&lt;new&gt;</code> (3.7.4, 18.6):</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*, std::size_t)</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*, std::size_t)</code></li>
    </ul>
    <ins>
      <ul>
	<li><code>operator new(std::size_t,
		    std::align_val_t)</code></li>
	<li><code>operator new(std::size_t, std::align_val_t,
		    const std::nothrow_t&amp;)</code></li>
	<li><code>operator new[](std::size_t,
		    std::align_val_t)</code></li>
	<li><code>operator new[](std::size_t, std::align_val_t,
		    const std::nothrow_t&amp;)</code></li>
	<li><code>operator delete(void*, std::align_val_t)</code></li>
	<li><code>operator delete(void*, std::align_val_t,
		    const std::nothrow_t&amp;)</code></li>
	<li><code>operator delete(void*, std::align_val_t,
		    std::size_t)</code></li>
	<li><code>operator delete[](void*,
		    std::align_val_t)</code></li>
	<li><code>operator delete[](void*, std::align_val_t,
		    const std::nothrow_t&amp;)</code></li>
	<li><code>operator delete[](void*, std::align_val_t,
		    std::size_t)</code></li>
      </ul>
    </ins></blockquote>
  <p>Change the title of section 18.6.1.3:</p>
  <blockquote>
    <h4>18.6.1.3 <del>Placement</del> <ins>Non-allocating</ins> forms
	    <span class="right">[new.delete.placement]</span></h4>
  </blockquote>
  <div class="new">
    <p>Change 20.7.9.1p5:</p>
    <blockquote>
      <p><em>Returns:</em>
	A pointer to the initial element of an array of storage
	of size <code>n * sizeof(T)</code>,
	aligned appropriately for objects of type <code>T</code>.
	<del>It is implementation-defined
	    whether over-aligned types are supported (3.11).</del></p>
    </blockquote>
  </div>
  <p>Change 20.7.9.1p6:</p>
  <blockquote>
    <p><em>Remark:</em> the storage is obtained
      by calling <code>::operator new<del>(std::size_t)</del></code>
      (18.6.1),
      but it is unspecified when or how often
      this function is called.
      The use of <code>hint</code> is unspecified,
      but intended as an aid to locality
      if an implementation so desires.</p>
  </blockquote>
  <p>Change 20.7.9.1p10:</p>
  <blockquote>
    <p><em>Remarks:</em>
      Uses <code>::operator delete<del>(void*, std::size_t)</del></code>
      (18.6.1), but it is unspecified when this function is called.</p>
  </blockquote>
  <div class="new">
    <h2>Specifications of library allocation
      and deallocation functions</h2>
    <p>Change section 18.6.1.1 as follows.
      (Some technically irrelevant editorial improvements are included;
      in CWG, these would be called &ldquo;en passant&rdquo;
      or &ldquo;drive-by&rdquo; changes.)
    </p>
    <blockquote>
      <h4>18.6.1.1 Single-object forms</h4>
      <p class="decl"><code>void* operator new(std::size_t size);<br />
	<ins>void* operator new(std::size_t size,
		    std::align_val_t alignment);</ins></code></p>
      <p class="numbered"><em>Effects:</em>
	The allocation <del>function</del> <ins>functions</ins>
	([basic.stc.dynamic.allocation])
	called by a <var>new-expression</var> ([expr.new])
	to allocate <code>size</code> bytes of storage<ins>.
	The first form is called
	for a type with fundamental alignment,
	and allocates storage</ins>
	suitably aligned to represent any object of that size.
	<ins>The second form is called for an over-aligned type,
	  and allocates storage
	  with the specified alignment.</ins></p>
      <p class="numbered"><em>Replaceable:</em>
	a C++ program may define
	<del>a function with this function signature
          that displaces</del>
	<ins>functions with either of these function signatures,
          and thereby displace</ins>
	the default <del>version</del> <ins>versions</ins>
	defined by the C++ standard library.</p>
      <p class="numbered">
	<em>Required behavior:</em>
	Return a non-null pointer
	to suitably aligned storage ([basic.stc.dynamic]),
	or else throw a <code>bad_alloc</code> exception.
	This requirement is binding on <del>a</del> <ins>any</ins>
	replacement <del>version</del> <ins>versions</ins>
	of <del>this function</del> <ins>these functions</ins>.</p>
      <p class="numbered"><em>Default behavior:</em></p>
      <ul>
	<li>Executes a loop:
	  Within the loop,
	  the function first attempts to allocate
	  the requested storage.
	  Whether the attempt involves a call
	  to the Standard C library function
	  <code>malloc</code>
	  <ins>or <code>aligned_alloc</code></ins>
	  is unspecified.</li>
	<li>Returns a pointer to the allocated storage
	  if the attempt is successful.
	  Otherwise, if the
	  current <code>new_handler</code> ([get.new.handler]) is
	  a null pointer value, throws
	  <code>bad_alloc</code>.</li>
	<li>Otherwise, the function calls the current
	  <code>new_handler</code> function ([new.handler]).
	  If the called function returns, the loop repeats.</li>
	<li>The loop terminates when an attempt to allocate
	  the requested storage is
	  successful or when a called
	  <code>new_handler</code>
	  function does not return.</li>
      </ul>
      <p class="decl"><code>void* operator new(std::size_t size,
		const std::nothrow_t&amp;) noexcept;<br />
	<ins>void* operator new(std::size_t size,
		    std::align_val_t alignment,
		    const std::nothrow_t&amp;) noexcept;</ins></code></p>
      <p class="numbered"><em>Effects:</em>
	Same as above, except that <del>it is</del>
	<ins>these are</ins>
	called by a placement version of a <var>new-expression</var>
	when a C++ program prefers a null pointer result
	as an error indication,
	instead of a <code>bad_alloc</code> exception.</p>
      <p class="numbered"><em>Replaceable:</em>
	a C++ program may define a function
	with this function signature
	that displaces the default version defined by the
	C++ standard library.
	<span class="ed">This should be changed similarly
	    to paragraph 2.</span></p>
      <p class="numbered"><em>Required behavior:</em>
	Return a non-null pointer
	to suitably aligned storage ([basic.stc.dynamic]),
	or else return a null pointer.
	<del>This</del> <ins>Each of these</ins> nothrow
	<del>version</del> <ins>versions</ins> of
	<code>operator new</code>
	returns a pointer
	obtained as if acquired
	from the (possibly replaced) ordinary version.
	This requirement is binding on a
	replacement version
	of this function.
	<span class="ed">The last sentence should be changed
	    similarly to paragraph 3.</span></p>
      <p class="numbered"><em>Default behavior:</em>
	Calls <code>operator new(size)</code><ins>,
	or respectively
	<code>operator new(size, alignment)</code></ins>.
	If the call returns normally,
	returns the result of that call.
	Otherwise, returns a null pointer.</p>
      <p class="numbered">[ <em>Example:</em></p>
      <pre>T* p1 = new T; // throws bad_alloc if it fails
T* p2 = new(nothrow) T; // returns nullptr if it fails</pre>
      <p>&mdash;<em>end example</em> ]</p>
      <p class="decl"><code>void operator delete(void* ptr) noexcept;<br />
	void operator delete(void* ptr,
		std::size_t size) noexcept;<br />
	<ins>void operator delete(void* ptr,
		    std::align_val_t alignment) noexcept;<br />
	  void operator delete(void* ptr,
		    std::align_val_t alignment,
		    std::size_t size) noexcept;</ins>
      </code></p>
      <p class="numbered"><em>Effects:</em>
	The deallocation function ([basic.stc.dynamic.deallocation])
	called by a <var>delete-expression</var>
	to render the value of <code>ptr</code> invalid.</p>
      <p class="numbered">
	<em>Replaceable:</em>
	a C++ program may define
	<del>a function with signature
	<code>void operator delete(void* ptr) noexcept</code>
	  that displaces</del>
	<ins>functions with any of these signatures,
	and thereby displace</ins>
	the default version<ins>(s)</ins> defined by the
	C++ standard library.
	If <del>this</del> <ins>a</ins> function
	<del>(</del>without <ins>a</ins>
	<code>size</code> parameter<del>)</del>
	is defined,
	the program should also define
	<del><code>void operator delete(void* ptr,
	    td::size_t size) noexcept</code></del>
	<ins>the corresponding function
	  with a <code>size</code> parameter</ins>.
	If <del>this</del> <ins>a</ins> function
	with <ins>a</ins> <code>size</code> parameter is defined,
	the program shall also define
	the <ins>corresponding</ins> version
	without the <code>size</code> parameter.
	[ <em>Note:</em> The default behavior below
	may change in the future,
	which will require replacing both deallocation functions
	when replacing the allocation function.
	&mdash;<em>end note</em> ]</p>
      <p class="numbered"><em>Requires:</em>
	<code>ptr</code> shall be a null pointer or
	its value shall <del>be a value returned</del>
	<ins>point to a block of memory allocated</ins> by an
	earlier call to <del>the</del> <ins>a</ins> (possibly replaced)
	<code>operator new<del>(std::size_t)</del></code>
	<del>or
	  <code>operator new(std::size_t,
	    const std::nothrow_t&amp;)</code></del>
	which has not been invalidated by an intervening call to
	<code>operator delete<del>(void*)</del></code> <del>or
	    <code>operator delete(void*, std::size_t)</code></del>.</p>
      <p class="numbered"><em>Requires:</em>
	If an implementation
	has strict pointer safety ([basic.stc.dynamic.safety])
	then <code>ptr</code> shall be a safely-derived pointer.</p>
      <p class="numbered"><em>Requires:</em>
	<ins>If the <code>alignment</code> parameter is not present,
	  <code>ptr</code> shall have been returned
	  by an allocation function
	  not taking an alignment argument.
	  If present, the <code>alignment</code> argument shall equal
	  the alignment argument passed to the allocation function
	  that returned <code>ptr</code>.</ins>
	If present,
	the <code><del>std::size_t</del> size</code> argument
	shall equal the size argument passed to the allocation function
	that returned <code>ptr</code>.</p>
      <p class="numbered"><em>Required behavior:</em>
	<del>Calls</del> <ins>A call</ins> to <ins>an</ins>
	<code>operator delete<del>(void* ptr,
		    std::size_t size)</del></code>
	<ins>taking a size</ins>
	may be changed to <del>calls</del> <ins>a call</ins> to
	<ins>the corresponding</ins>
	<code>operator delete<del>(void* ptr)</del></code>
	<ins>not taking a size,</ins>
	without affecting memory allocation.
	[ <em>Note:</em> A conforming implementation is for
	<code>operator delete(void* ptr,
	    std::size_t size)</code> to simply call
	<code>operator delete(ptr)</code>.
	&mdash;<em>end note</em> ]</p>
      <p class="numbered">
	<em>Default behavior:</em>
	the function
	<code>operator delete(void* ptr, std::size_t size)</code> calls
	<code>operator delete(ptr)</code>.
	<ins>The function
	<code>operator delete(void* ptr,
	    std::align_val_t alignment, std::size_t)</code> calls
	<code>operator delete(ptr, alignment)</code>.</ins>
	[ <em>Note:</em> See the note
	in the above <em>Replaceable</em> paragraph.
	&mdash;<em>end note</em> ]</p>
      <p class="numbered">
	<em><del>Default</del>  <ins>Required</ins> behavior:</em>
	If <code>ptr</code> is null, does nothing.
	Otherwise, reclaims the storage allocated
	by the earlier call to <code>operator new</code>.</p>
      <p class="numbered"><em>Remarks:</em>
	It is unspecified under what conditions part or all of such
	reclaimed storage will be allocated by subsequent calls to
	<code>operator new</code>
	or any of
	<ins><code>aligned_alloc</code>,</ins>
	<code>calloc</code>,
	<code>malloc</code>,
	or
	<code>realloc</code>,
	declared in
	<code>&lt;cstdlib&gt;</code>.</p>
      <p class="decl">
	<code>void operator delete(void* ptr,
		    const std::nothrow_t&amp;) noexcept;<br />
	  <ins>void operator delete(void* ptr,
			std::align_val_t alignment,
			const std::nothrow_t&amp;) noexcept;</ins></code>
      </p>
      <p class="numbered"><em>Effects:</em>
	The deallocation function ([basic.stc.dynamic.deallocation])
	called by the implementation
	to render the value of <code>ptr</code> invalid
	when the constructor invoked
	from a nothrow placement version
	of the <var>new-expression</var> throws an exception.</p>
      <p class="numbered"><em>Replaceable:</em>
	a C++ program may define a function with
	<del>signature
	<code>void operator delete(void* ptr,
	    const std::nothrow_t&amp;) noexcept</code>
	  that displaces</del>
	<ins>either of these signatures, and thereby displace</ins>
	the default version<ins>(s)</ins>
	defined by the C++ standard library.</p>
      <p class="numbered"><em>Requires:</em>
	If an implementation
	has strict pointer safety ([basic.stc.dynamic.safety])
	then <code>ptr</code> shall be a safely-derived pointer.</p>
      <p class="numbered"><em>Default behavior:</em>
	<ins>The function</ins> <code>operator delete(void* ptr,
	    const std::nothrow_t&amp;)</code> calls
	<code>operator delete(ptr)</code>.
	<ins>The function <code>operator delete(void* ptr,
	    std::align_val_t alignment,
	    const std::nothrow_t&amp;)</code> calls
	<code>operator delete(ptr, alignment)</code>.</ins></p>
    </blockquote>
    <p>Change section 18.6.1.2:</p>
    <blockquote>
      <h4>18.6.1.2 Array forms</h4>
      <p class="decl"><code>void* operator new[](std::size_t size);<br />
	<ins>void* operator new[](std::size_t size,
		  std::align_val_t alignment);</ins></code></p>
      <p class="numbered"><em>Effects:</em>
	The allocation <del>function</del>
	<ins>functions</ins> ([basic.stc.dynamic.allocation])
	called by the array form of a
	<var>new-expression</var> ([expr.new])
	to allocate <code>size</code> bytes of storage<ins>.
	The first form is called for a type
	with fundamental alignment,
	and allocates storage</ins>
	suitably aligned to represent any array
	object of that size or smaller.
	<ins>The second form is called for an over-aligned type,
	  and allocates storage
	  with the specifed alignment.</ins></p>
      <p><em>Footnote:</em> It is not the direct responsibility of
	<code>operator new[](std::size_t)</code>
	or
	<code>operator delete[](void*)</code>
	to note the repetition count or element size of the array.
	Those operations are performed elsewhere in the array
	<code>new</code>
	and
	<code>delete</code>
	expressions.
	The array
	<code>new</code>
	expression, may, however,
	increase the <code>size</code> argument to
	<code>operator new[](std::size_t)</code>
	to obtain space to store supplemental information.</p>
      <p class="numbered">
	<em>Replaceable:</em>
	a C++ program <del>can</del> <ins>may</ins> define a
	function with this function signature
	that displaces the default version
	defined by the C++ standard library.
	<span class="ed">This should be changed
	  similarly to paragraph 2 above.</span></p>
      <p class="numbered">
	<em>Required behavior:</em>
	Same as for
	<del><code>operator new(std::size_t)</code></del>
	<ins>the corresponding single-object forms</ins>.
	This requirement is binding on a
	replacement version
	of this function.
	<span class="ed">The last sentence should be changed
	  similarly to paragraph 3 above.</span></p>
      <p class="numbered">
	<em>Default behavior:</em>
	Returns
	<code>operator new(size)</code>,
	<ins>or respectively
	    <code>operator new(size, alignment)</code></ins>.</p>
      <p class="decl"><code>void* operator new[](std::size_t size,
		const std::nothrow_t&amp;) noexcept;<br />
	<ins>void* operator new[](std::size_t size,
		    std::align_val_t alignment,
		    const std::nothrow_t&amp;) noexcept;</ins></code></p>
      <p class="numbered">
	<em>Effects:</em>
	Same as above, except that <del>it is</del>
	<ins>these are</ins> called by a placement version of a
	<var>new-expression</var>
	when a C++ program prefers a null pointer result
	as an error indication,
	instead of a
	<code>bad_alloc</code>
	exception.</p>
      <p class="numbered">
	<em>Replaceable:</em>
	a C++ program <del>can</del> <ins>may</ins> define a
	function with this function signature
	that displaces the default version
	defined by the C++ standard library.
	<span class="ed">This should be changed
	    similarly to paragraph 2.</span></p>
      <p class="numbered">
	<em>Required behavior:</em>
	Return a non-null pointer
	to suitably aligned storage ([basic.stc.dynamic]),
	or else return a null pointer.
	<del>This</del> <ins>Each of these</ins>
	nothrow <del>version</del> <ins>versions</ins>
	of <code>operator new[]</code> returns
	a pointer obtained as if
	acquired from the (possibly replaced)
	<del><code>operator new[](std::size_t)</code> function</del>
	<ins>ordinary version</ins>.
	This requirement is binding
	on a replacement version of this function.
	<span class="ed">The last sentence should be changed
	    similarly to paragraph 3.</span></p>
      <p class="numbered">
	<em>Default behavior:</em>
	Calls <code>operator new[](size)</code><ins>,
	    or respectively
	    <code>operator new[](size, alignment)</code></ins>.
	If the call returns normally,
	returns the result of that call.
	Otherwise, returns a null pointer.</p>
      <p class="decl"><code>void operator delete[](void* ptr) noexcept;<br />
	void operator delete[](void* ptr,
		std::size_t size) noexcept;<br />
	<ins>void operator delete[](void* ptr,
		    std::align_val_t alignment) noexcept;<br />
	  void operator delete[](void* ptr,
		    std::align_val_t alignment,
		    std::size_t size) noexcept;</ins>
      </code></p>
      <p class="numbered">
	<em>Effects:</em>
	The deallocation function ([basic.stc.dynamic.deallocation])
	called by the array form of a
	<var>delete-expression</var>
	to render the value of <code>ptr</code> invalid.</p>
      <p class="numbered">
	<em>Replaceable:</em>
	a C++ program <del>can</del> <ins>may</ins> define
	<del>a function with signature
	<code>void operator delete[](void* ptr) noexcept</code>
	  that displaces</del>
	<ins>functions with any of these signatures,
	    and thereby displace</ins>
	the default version<ins>(s)</ins>
	defined by the C++ standard library.
	If <del>this</del> <ins>a</ins> function
	<del>(</del>without <ins>a</ins> <code>size</code>
	parameter<del>)</del> is defined,
	the program should also define
	<del><code>void operator delete[](void* ptr,
	    std::size_t size) noexcept</code></del>
	<ins>the corresponding function
	    with a <code>size</code> parameter</ins>.
	If <del>this</del> <ins>a</ins> function
	with <ins>a</ins> <code>size</code> parameter is defined,
	the program shall also define
	the <ins>corresponding</ins> version
	without the <code>size</code> parameter.
	[ <em>Note</em>: The default behavior below
	may change in the future,
	which will require replacing both deallocation functions
	when replacing the allocation function.
	&mdash;<em>end note</em> ]</p>
      <p class="numbered">
	<em>Requires:</em>
	<code>ptr</code> shall be a null pointer or its value shall
	<del>be the value returned</del>
	<ins>point to a block of memory allocated</ins>
	by an earlier call to
	<ins>a (possibly replaced)</ins>
	<code>operator new[]<del>(std::size_t)</del></code>
	<del>or
	<code>operator new[](std::size_t,
	    const std::nothrow_t&amp;)</code></del>
	which has not been invalidated by an intervening call to
	<code>operator delete[]<del>(void*)</del>(</code> <del>or
	    <code>operator delete[](void*,
	      std::size_t)</code></del>.</p>
      <p class="numbered">
	<em>Requires:</em>
	<ins>If the <code>alignment</code> parameter is not present,
	    <code>ptr</code> shall have been returned
	    by an allocation function
	    not taking an alignment argument.
	    If present, the <code>alignment</code> argument shall equal
	    the alignment argument passed to the allocation function
	    that returned <code>ptr</code>.</ins>
	If present,
	the <code><del>std::size_t</del> size</code> argument
	<del>must</del> <ins>shall</ins> equal the size
	argument passed to the allocation function
	that returned <code>ptr</code>.</p>
      <p class="numbered">
	<em>Required behavior:</em>
	<del>Calls</del> <ins>A call</ins> to
	<code>operator delete[]<del>(void* ptr,
	    std::size_t size)</del></code>
	<ins>taking a size</ins>
	may be changed to <del>calls</del> <ins>a call</ins> to
	<code>operator delete[]<del>(void* ptr)</del></code>
	<ins>not taking a size,</ins>
	without affecting memory allocation.
	[ <em>Note:</em> 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;<em>end note</em> ]</p>
      <p class="numbered">
	<em>Requires:</em>
	If an implementation
	has strict pointer safety ([basic.stc.dynamic.safety])
	then <code>ptr</code> shall be a safely-derived pointer.</p>
      <p class="numbered">
	<em>Default behavior:</em>
	<del><code>operator delete[](void* ptr,
	    std::size_t size)</code> calls
	<code>operator delete[](ptr)</code>, and
	<code>operator delete[](void* ptr)</code> calls
	<code>operator delete(ptr)</code>.</del>
	<ins>The functions that have a <code>size</code> parameter
	    call and forward their other parameters
	    to the corresponding function
	    without a <code>size</code> parameter.
	    The functions that do not have
	    a <code>size</code> parameter
	    call and forward their parameters
	    to the corresponding <code>operator new</code>
	  (single-object) function.</ins>
      </p>
    </blockquote>
    <p class="ed">This is the one place in the standard
      where the default behavior needs to be specified
      for four replaceable functions.
      My senses of esthetics and propriety rebelled
      at the prospect of enumerating them all,
      especially in a single flowing paragraph.</p>
    <blockquote>
      <p class="decl"><code>void operator delete[](void* ptr,
		const std::nothrow_t&amp;) noexcept;<br />
	<ins>void operator delete[](void* ptr,
		    std::align_val_t alignment,
		const std::nothrow_t&amp;) noexcept;</ins>
      </code></p>
      <p class="numbered">
	<em>Effects:</em>
	The deallocation function ([basic.stc.dynamic.deallocation])
	called by the implementation
	to render the value of <code>ptr</code> invalid
	when the constructor invoked from a nothrow
	placement version of the array <var>new-expression</var>
	throws an exception.</p>
      <p class="numbered">
	<em>Replaceable:</em>
	a C++ program may define a function with <del>signature
	<code>void operator delete[](void* ptr,
	    std::align_val_t alignment,
	    const std::nothrow_t&amp;) noexcept</code>
	  that displaces</del>
	<ins>either of these signatures, and thereby displace</ins>
	the default version defined by the
	C++ standard library.</p>
      <p class="numbered">
	<em>Requires:</em>
	If an implementation
	has strict pointer safety ([basic.stc.dynamic.safety])
	then <code>ptr</code> shall be a safely-derived pointer.</p>
      <p class="numbered">
	<em>Default behavior:</em>
	<ins>The function</ins> <code>operator delete[](void* ptr,
	    const std::nothrow_t&amp;)</code>
	calls
	<code>operator delete[](ptr)</code>.
	<ins>The function <code>operator delete[](void* ptr,
		std::align_val_t alignment,
		const std::nothrow_t&amp;)</code>
	  calls
	  <code>operator delete[](ptr, alignment)</code>.</ins></p>
    </blockquote>
  </div>
</body>
</html>
