<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2062: Effect contradictions w&#47;o no-throw guarantee of std::function swaps</title>
<meta property="og:title" content="Issue 2062: Effect contradictions w&#47;o no-throw guarantee of std::function swaps">
<meta property="og:description" content="C++ library issue. Status: C++17">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2062.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#C++17">C++17</a> status.</em></p>
<h3 id="2062"><a href="lwg-defects.html#2062">2062</a>. Effect contradictions w&#47;o no-throw guarantee of <code>std::function</code> swaps</h3>
<p><b>Section:</b> 22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a>, 22.10.17.3.3 <a href="https://wg21.link/func.wrap.func.mod">[func.wrap.func.mod]</a> <b>Status:</b> <a href="lwg-active.html#C++17">C++17</a>
 <b>Submitter:</b> Daniel Kr&uuml;gler <b>Opened:</b> 2011-05-28 <b>Last modified:</b> 2020-09-06</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#func.wrap.func">issues</a> in [func.wrap.func].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++17">C++17</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Howard Hinnant observed in reflector message c++std-lib-30841 that 22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a> 
makes the member swap <code>noexcept</code>, even though the non-member swap is not <code>noexcept</code>. 
<p/>
The latter was an outcome of the discussions during the Batavia meeting and the Madrid meeting 
involving LWG <a href="lwg-defects.html#1349" title="swap should not throw (Status: C++11)">1349</a><sup><a href="https://cplusplus.github.io/LWG/issue1349" title="Latest snapshot">(i)</a></sup>, which seems to indicate that the remaining <code>noexcept</code> 
specifier at the member swap is incorrect and should be removed.
<p/>
But if we allow for a potentially throwing member swap of <code>std::function</code>, this causes 
another conflict with the exception specification for the following member function:
</p>
<blockquote><pre>
template&lt;class F&gt; function&amp; operator=(reference_wrapper&lt;F&gt; f) <span style="color:#C80000;font-weight:bolder">noexcept</span>;
</pre><blockquote><p>
<i>Effects</i>: <code>function(f).<span style="color:#C80000;font-weight:bolder">swap</span>(*this);</code>
</p>
</blockquote></blockquote>
<p>
Note that in this example the sub-expression <code>function(f)</code> does not cause any problems,
because of the nothrow-guarantee given in 22.10.17.3.2 <a href="https://wg21.link/func.wrap.func.con">[func.wrap.func.con]</a> p. 10. The problem
is located in the usage of the swap which could potentially throw given the general latitude. 
<p/>
So, either the Madrid meeting decision need to be revised (and both member and free swap of 
<code>std::function</code> should be noexcept), or this function needs to be adapted as well,
e.g. by taking the exception-specification away or by changing the semantics.
<p/>
One argument for "swap-may-throw" would be to allow for small-object optimization techniques
where the copy of the target may throw. But given the fact that the swap function has been guaranteed 
to be "Throws: Nothing" from TR1 on, it seems to me that that there would still be opportunities to 
perform small-object optimizations just restricted to the set of target copies that cannot throw. 
<p/>
In my opinion member swap of <code>std::function</code> has always been intended to be no-throw, because
otherwise there would be no good technical reason to specify the effects of several member 
functions in terms of the "construct-swap" idiom (There are three functions that are defined
this way), which provides the strong exception safety in this case. I suggest to enforce that both 
member swap and non-member swap of <code>std::function</code> are nothrow functions as it had been guaranteed 
since TR1 on.
</p>

<p><i>[
2011 Bloomington
]</i></p>

<p>
Dietmar: May not be swappable in the first place.
</p>
<p>
Alisdair: This is wide contact. Then we should be taking noexcept off instead of putting it on. This is preferred resolution.
</p>
<p>
Pablo: This is bigger issue. Specification of assignment in terms of swap is suspect to begin with. It is over specification.
How this was applied to string is a better example to work from.
</p>
<p>
Pablo: Two problems: inconsistency that should be fixed (neither should have noexcept), the other issues is that assignment
should not be specified in terms of swap. There are cases where assignment should succeed where swap would fail. This is easier
with string as it should follow container rules.
</p>
<p>
<b>Action Item</b> (Alisdair): There are a few more issues found to file.
</p>
<p>
Dave: This is because of allocators? The allocator makes this not work.
</p>
<p>
Howard: There is a type erased allocator in shared_ptr. There is a noexcept allocator in shared_ptr.
</p>
<p>
Pablo: shared_ptr is a different case. There are shared semantics and the allocator does move around.
A function does not have shared semantics.
</p>
<p>
Alisdair: Function objects think they have unique ownership.
</p>
<p>
Howard: In function we specify semantics with copy construction and swap.
</p>
<p>
<b>Action Item</b> (Pablo): Write this up better (why assignment should not be defined in terms of swap)
</p>
<p>
Howard: Not having trouble making function constructor no throw.
</p>
<p>
Dietmar: Function must allocate memory.
</p>
<p>
Howard: Does not put stuff that will throw on copy or swap in small object optimization. Put those on heap.
Storing allocator, but has to be no throw copy constructable.
</p>
<p>
Pablo: Are you allowed to or required to swap or move allocators in case or swap or move.
</p>
<p>
Dave: An allocator that is type erased should be different...
</p>
<p>
Pablo: it is
</p>
<p>
Dave: Do you need to know something about allocator types? But only at construction time.
</p>
<p>
Pablo: You could have allocators that are different types.
</p>
<p>
Dave: Swap is two ended operation.
</p>
<p>
Pablo: Opinion is that both have to say propagate on swap for them to swap.
</p>
<p>
John: It is not arbitrary. If one person says no. No is no.
</p>
<p>
Howard: Find noexcept swap to be very useful. Would like to move in that direction and bring container design along.
</p>
<p>
Dave: If you have something were allocator must not propagate you can detect that at construction time.
</p>
<p>
...
</p>
<p>
Pablo: Need to leave this open and discuss in smaller group.
</p>
<p>
Alisdair: Tried to add boost::any as TR2 proposal and ran into this issue. Only the first place where we run into
issues with type erased allocators. Suggest we move it to open.
</p>
<p>
<b>Action Item</b>: Move to open.
</p>
<p>
<b>Action Item</b> (Pablo works with Howard and Daniel): Address the more fundamental issue
(which may be multiple issues) and write up findings.
</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>

<blockquote class="note">
<p>This wording is relative to the FDIS.</p>
<ol>
<li><p>Modify the header <code>&lt;functional&gt;</code> synopsis in 22.10 <a href="https://wg21.link/function.objects">[function.objects]</a> as indicated:</p>
<blockquote><pre>
namespace std {
  [&hellip;]

  template&lt;class R, class... ArgTypes&gt;
  void swap(function&lt;R(ArgTypes...)&gt;&amp;, function&lt;R(ArgTypes...)&gt;&amp;) <ins>noexcept</ins>;

  [&hellip;]
}
</pre></blockquote>
</li>

<li><p>Modify the class template <code>function</code> synopsis in 22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a> as indicated:</p>
<blockquote><pre>
namespace std {
  [&hellip;]

  <i>// [func.wrap.func.alg], specialized algorithms:</i>
  template&lt;class R, class... ArgTypes&gt;
  void swap(function&lt;R(ArgTypes...)&gt;&amp;, function&lt;R(ArgTypes...)&gt;&amp;) <ins>noexcept</ins>;

  [&hellip;]
}
</pre></blockquote>
</li>

<li><p>Modify 22.10.17.3.8 <a href="https://wg21.link/func.wrap.func.alg">[func.wrap.func.alg]</a> as indicated:</p>
<blockquote><pre>
template&lt;class R, class... ArgTypes&gt;
void swap(function&lt;R(ArgTypes...)&gt;&amp; f1, function&lt;R(ArgTypes...)&gt;&amp; f2) <ins>noexcept</ins>;
</pre><blockquote><p>
-1- <i>Effects</i>: <code>f1.swap(f2);</code>
</p></blockquote></blockquote>
</li>
</ol>
</blockquote>

<p><i>[2014-02-28 (Post Issaquah), Pablo provides more information]</i></p>


<p>
For cross-referencing purposes: The resolution of this issue should be
harmonized with any resolution to LWG <a href="lwg-defects.html#2370" title="Operations involving type-erased allocators should not be noexcept in std::function (Status: Resolved)">2370</a><sup><a href="https://cplusplus.github.io/LWG/issue2370" title="Latest snapshot">(i)</a></sup>, which addresses
inappropriate <code>noexcept</code>s in some function constructors.
</p>

<p>We have the following choices:</p>

<ol>
<li>
<p><code>swap()</code> does not throw</p>

<blockquote><p>
<i>Discussion</i>: This definition is desirable, and allows assignment
   to be implemented with the strong exception guarantee, but it does have
   consequences: The implementation cannot use the small-object optimization
   for a function-object <code>F</code> unless <code>F</code> is <code>NothrowMovable</code> 
   (nothrow-swappable is unimportant because <code>F</code> is not swapped with another <code>F</code>). 
   Note that many functors written before C++11 will not have move constructors decorated
   with <code>noexcept</code>, so this limitation could affect a lot of code.
</p>
<p>
It is not clear what other implementation restrictions might be
   needed. Allocators are required not to throw on move or copy. Is that
   sufficient?
</p>
</blockquote>
</li>

<li>
<p><code>swap()</code> can throw</p>

<blockquote>
<p>
<i>Discussion</i>: This definition gives maximum latitude to implementation to
   use small-object optimization. However, the strong guarantee on assignment
   is difficult to achieve.  Should we consider giving up on the strong
   guarantee? How much are we willing to pessimize code for exceptions?
</p>
</blockquote>
</li>
<li>
<p><code>swap()</code> will not throw if both functions have <code>NoThrowMoveable</code> functors</p>

<blockquote>
<p>
<i>Discussion</i>: This definition is similar to option 2, but gives slightly
  stronger guarantees.  Here, <code>swap()</code> can throw, but the programmer can
  theoretically prevent that from happening. This should be straight-forward
  to implement and gives the implementation a lot of latitude for
  optimization. However, because this is a dynamic decision, the program is
  not as easy to reason about. Also, the strong guarantee for assignment is
  compromized as in option 2.
</p>
</blockquote>
</li>
</ol>

<p><i>[2016-08-02, Ville, Billy, and Billy comment and reinstantiate the original P/R]</i></p>

<p>
We (Ville, Billy, and Billy) propose to require that <code>function</code>'s <code>swap</code> is <code>noexcept</code> 
in all cases.
</p>
<ul>
<li><p>libstdc++ does not throw in their <code>swap</code>. It is not <code>noexcept</code> today, but the small functor 
optimization only engages for trivially copyable types.</p></li>
<li><p>msvc++ checks <code>is_nothrow_move_constructible</code> before engaging the small functor optimization and marks 
its <code>swap</code> <code>noexcept</code></p></li>
<li><p>libc++ marks <code>swap</code> <code>noexcept</code> (though I have not looked at its implementation)</p></li>
</ul>
<p>
Moreover, many of the concerns that were raised by providing this guarantee are no longer applicable now that 
<a href="https://wg21.link/p0302r1">P0302</a> has been accepted, which removes allocator support from <code>std::function</code>.
<p/>
Therefore we are re-proposing the original resolution above.
</p>

<p><i>[2016-08 Chicago]</i></p>

<p>Tues PM: Move to Tentatively Ready</p>



<p id="res-2062"><b>Proposed resolution:</b></p>
<p>
This wording is relative to N4606.
</p>

<ol>
<li><p>Modify the header <code>&lt;functional&gt;</code> synopsis in 22.10 <a href="https://wg21.link/function.objects">[function.objects]</a> as indicated:</p>
<blockquote><pre>
namespace std {
  [&hellip;]

  template&lt;class R, class... ArgTypes&gt;
  void swap(function&lt;R(ArgTypes...)&gt;&amp;, function&lt;R(ArgTypes...)&gt;&amp;) <ins>noexcept</ins>;

  [&hellip;]
}
</pre></blockquote>
</li>

<li><p>Modify the class template <code>function</code> synopsis in 22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a> as indicated:</p>
<blockquote><pre>
namespace std {
  [&hellip;]

  <i>// [func.wrap.func.alg], specialized algorithms:</i>
  template&lt;class R, class... ArgTypes&gt;
  void swap(function&lt;R(ArgTypes...)&gt;&amp;, function&lt;R(ArgTypes...)&gt;&amp;) <ins>noexcept</ins>;

  [&hellip;]
}
</pre></blockquote>
</li>

<li><p>Modify 22.10.17.3.8 <a href="https://wg21.link/func.wrap.func.alg">[func.wrap.func.alg]</a> as indicated:</p>
<blockquote><pre>
template&lt;class R, class... ArgTypes&gt;
void swap(function&lt;R(ArgTypes...)&gt;&amp; f1, function&lt;R(ArgTypes...)&gt;&amp; f2) <ins>noexcept</ins>;
</pre><blockquote><p>
-1- <i>Effects</i>: As if by: <code>f1.swap(f2);</code>
</p></blockquote></blockquote>
</li>
</ol>





</body>
</html>
