<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 3044: Strange specification of max_size() for an allocator</title>
<meta property="og:title" content="Issue 3044: Strange specification of max_size() for an allocator">
<meta property="og:description" content="C++ library issue. Status: New">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue3044.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#New">New</a> status.</em></p>
<h3 id="3044"><a href="lwg-active.html#3044">3044</a>. Strange specification of <code>max_size()</code> for an allocator</h3>
<p><b>Section:</b> 16.4.4.6 <a href="https://wg21.link/allocator.requirements">[allocator.requirements]</a> <b>Status:</b> <a href="lwg-active.html#New">New</a>
 <b>Submitter:</b> Jon Cohen <b>Opened:</b> 2017-12-06 <b>Last modified:</b> 2024-01-29</p>
<p><b>Priority: </b>3
</p>
<p><b>View other</b> <a href="lwg-index-open.html#allocator.requirements">active issues</a> in [allocator.requirements].</p>
<p><b>View all other</b> <a href="lwg-index.html#allocator.requirements">issues</a> in [allocator.requirements].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#New">New</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Table 31 in the C++17 standard specifies <code>X::max_size()</code> (where <code>X</code> is an allocator type) as "The largest value 
that can meaningfully be passed to <code>X::allocate()</code>". Noticeably missing is the statement "<i>Throws:</i> Nothing".
<p/>
As an example of why this is an issue, note that <code>vector::max_size()</code> and <code>allocator_traits::max_size()</code> are 
both marked <code>noexcept</code>. We must then interpret <code>max_size()</code> as being allowed to sometimes call 
<code>std::terminate</code>, or else <code>{vector, allocator_traits, ...}::max_size()</code> must be allowed to directly calculate 
<code>numeric_limits&lt;size_type&gt;::max() / sizeof(value_type)</code> instead of querying the allocator, even if 
<code>Alloc::max_size()</code> exists. This seems like a bug in the wording for the requirements of <code>max_size()</code> in an 
allocator type. I think an issue should be opened on this subject to add <i>Throws:</i> Nothing or similar to the requirements 
of <code>max_size()</code> for an allocator.
<p/>
As an example consider writing up a framework to test the exception-safety of types in a given framework, since they were all 
written in an exception-free environment. One of the types in the framework is an allocator which, in a controlled way, 
can throw an exception at any point where it is allowed by the standard. It's important that the test framework be as pedantic 
as possible, so the allocator type throws on <code>max_size()</code>, since it is currently allowed to by the standard. When a 
reasonable <code>vector</code> implementation (at least those in libstdc++ and msvc) is, for example, asked to construct a 
<code>vector</code> from an <code>initializer_list</code>, it will call <code>allocator_traits&lt;Alloc&gt;::max_size()</code>, which will 
terminate the program because the exception thrown in <code>Alloc::max_size()</code> propagated through the <code>noexcept</code> 
traits function. Although this is conformant behavior, I think it's a bug in the standard that a function as benign as 
<code>max_size()</code> can terminate the program in this manner, and I think the fix is that a conformant allocator should be 
required to supply a non-throwing <code>max_size()</code> member function.
<p/>
Daniel:
<p/>
This problem was shortly discussed during review of LWG <a href="lwg-defects.html#2162" title="allocator_traits::max_size missing noexcept (Status: C++14)">2162</a><sup><a href="https://cplusplus.github.io/LWG/issue2162" title="Latest snapshot">(i)</a></sup> (see comment 2012-08-05). At that time
the more drastic but also more consistent requirement that an allocator's <code>max_size</code> function shall not throw
exceptions has not been added. IMO this position should be reconsidered to follow the spirit of the new issue LWG 
<a href="lwg-active.html#3044" title="Strange specification of max_size() for an allocator (Status: New)">3044</a><sup><a href="https://cplusplus.github.io/LWG/issue3044" title="Latest snapshot">(i)</a></sup>.
</p>

<p><i>[2018-01; Priority set to 3 after mailing list discussion]</i></p>


<p><i>[2018-08-21, Jonathan comments and provides wording]</i></p>

<p>
The phrase "the largest value that can meaningfully be passed to <code>X::allocate()</code>" is meaningless. Is it a 
requirement on the caller, so that larger values must not be passed? Or a hint from the allocator implementor that larger 
values will produce a <code>bad_alloc</code> exception? Can the return value change dynamically, based on the free memory
available to the allocator?! &mdash; LWG <a href="lwg-closed.html#197" title="max_size() underspecified (Status: NAD)">197</a><sup><a href="https://cplusplus.github.io/LWG/issue197" title="Latest snapshot">(i)</a></sup> says it can't change.
<p/>
As noted in the LWG <a href="lwg-defects.html#2162" title="allocator_traits::max_size missing noexcept (Status: C++14)">2162</a><sup><a href="https://cplusplus.github.io/LWG/issue2162" title="Latest snapshot">(i)</a></sup> comments, we don't currently guarantee it can be called on a <code>const</code> object 
(so <code>allocator_traits</code> will not use the allocator's <code>max_size()</code> if it's non-<code>const</code>, although that was 
unclear before DR <a href="lwg-defects.html#2284" title="Inconsistency in allocator_traits::max_size (Status: C++14)">2284</a><sup><a href="https://cplusplus.github.io/LWG/issue2284" title="Latest snapshot">(i)</a></sup>). In addition to adding "<i>Throws:</i> nothing" we should ensure it's callable 
on <code>const</code> lvalues, and clarify what "meaningfully" means and who is supposed to care about it. My proposed 
resolution doesn't achieve all of this, but is a start.
</p>

<p>
<strong>Previous resolution [SUPERSEDED]:</strong>
</p>
<blockquote class="note">
<p>
This wording is relative to <a href="https://wg21.link/N4762" title=" Working Draft, Standard for Programming Language C++">N4762</a>.
</p>

<ol>
<li><p>Change 16.4.4.6 <a href="https://wg21.link/allocator.requirements">[allocator.requirements]</a>, Table 32 &mdash; "Descriptive variable definitions", as indicated:</p>
<blockquote>
<table border="1">
<caption>Table 32 &mdash; Descriptive variable definitions</caption>
<tr>
<th>Variable</th>
<th>Definition</th>
</tr>

<tr>
<td>
<code>T, U, C</code>
</td>
<td>
any <i>cv</i>-unqualified object type (3.9)
</td>
</tr>

<tr>
<td colspan="2" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code>a, a1, a2</code>
</td>
<td>
lvalues of type <code>X</code>
</td>
</tr>

<tr>
<td>
<ins><code>a3</code></ins>
</td>
<td>
<ins>an lvalue of type <code>const X</code></ins>
</td>
</tr>

<tr>
<td colspan="2" align="center">
<code>&hellip;</code>
</td>
</tr>

</table>
</blockquote>
</li>

<li><p>Change 16.4.4.6 <a href="https://wg21.link/allocator.requirements">[allocator.requirements]</a>, Table 33 &mdash; "<i>Cpp17Allocator</i> requirements", as indicated:</p>
<blockquote>
<table border="1">
<caption>Table 33 &mdash; <i>Cpp17Allocator</i> requirements</caption>
<tr>
<th>Expression</th>
<th>Return type</th>
<th>Assertion&#47;note<br/>pre-&#47;post-condition</th>
<th>Default</th>
</tr>

<tr>
<td colspan="4" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code>a<ins>3</ins>.max_size()</code>
</td>
<td>
<code>X::size_type</code>
</td>
<td>
the largest value that can<br/>
meaningfully be passed to<br/>
<code>X::allocate()</code><ins>.<br/> 
[<i>Note:</i> Larger values might cause<br/> 
an exception to be thrown. &mdash; <i>end note</i>]<br/> 
<i>Throws:</i> Nothing.</ins>
</td>
<td>
<code>numeric_limits&lt;size_type&gt;::max()<br/>
/ sizeof(value_type)</code>
</td>
</tr>

<tr>
<td colspan="4" align="center">
<code>&hellip;</code>
</td>
</tr>

</table>
</blockquote>

</li>
</ol>
</blockquote>

<p><i>[2022-04-25; Daniel rebases wording on <a href="https://wg21.link/N4910" title=" Working Draft, Standard for Programming Language C++">N4910</a>]</i></p>



<p id="res-3044"><b>Proposed resolution:</b></p>
<p>
This wording is relative to <a href="https://wg21.link/N4910" title=" Working Draft, Standard for Programming Language C++">N4910</a>.
</p>

<ol>
<li><p>Change 16.4.4.6.1 <a href="https://wg21.link/allocator.requirements.general">[allocator.requirements.general]</a> as indicated:</p>


<blockquote>
<p>
-2- In subclause 16.4.4.6 <a href="https://wg21.link/allocator.requirements">[allocator.requirements]</a>,
</p>
<ol style="list-style-type:none">
<li><p>(2.1) &mdash; [&hellip;]</p></li>
<li><p>[&hellip;]</p></li>
<li><p>(2.6) &mdash; <code>a</code>, <code>a1</code>, <code>a2</code> denote lvalues of type <code>X</code>,</p></li>
<li><p><ins>(?.?) &mdash; <code>a3</code> denotes an lvalue of type <code>const X</code>,</ins></p></li>
<li><p>[&hellip;]</p></li>
</ol>
<p>[&hellip;]</p>
<pre>
a<ins>3</ins>.max_size()
</pre>
<blockquote>
<p>
-50- <i>Result:</i> <code>X::size_type</code>
<p/>
-51- <i>Returns:</i> The largest value that can meaningfully be passed to <code>X::allocate()</code>.
<p/>
<ins>[<i>Note:</i> Larger values might cause an exception to be thrown. &mdash; <i>end note</i>]</ins> 
<p/>
<ins>-?- <i>Throws:</i> Nothing.</ins>
<p/>
-52- <i>Remarks:</i> Default: <code>numeric_limits&lt;size_type&gt;::max() / sizeof(value_type)</code>
</p>
</blockquote>
</blockquote>
</li>

</ol>





</body>
</html>
