<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2751: shared_ptr deleter not specified to observe expired weak_ptr instances</title>
<meta property="og:title" content="Issue 2751: shared_ptr deleter not specified to observe expired weak_ptr instances">
<meta property="og:description" content="C++ library issue. Status: New">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2751.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="2751"><a href="lwg-active.html#2751">2751</a>. <code>shared_ptr</code> deleter not specified to observe expired <code>weak_ptr</code> instances</h3>
<p><b>Section:</b> 20.3.2.2.3 <a href="https://wg21.link/util.smartptr.shared.dest">[util.smartptr.shared.dest]</a> <b>Status:</b> <a href="lwg-active.html#New">New</a>
 <b>Submitter:</b> Aaron Jacobs <b>Opened:</b> 2016-07-21 <b>Last modified:</b> 2025-03-18</p>
<p><b>Priority: </b>4
</p>
<p><b>View all other</b> <a href="lwg-index.html#util.smartptr.shared.dest">issues</a> in [util.smartptr.shared.dest].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#New">New</a> status.</p>
<p><b>Discussion:</b></p>
<p>
The C++14 standard contains no language that guarantees the deleter run by a
<code>shared_ptr</code> will see all associated <code>weak_ptr</code> instances as expired. For example,
the standard doesn't appear to guarantee that the assertion in the following
snippet won't fire:
</p>
<blockquote><pre>
std::weak_ptr&lt;Foo&gt; weak;
std::shared_ptr&lt;Foo&gt; strong{
  new Foo,
  [&amp;weak] (Foo* f) {
    assert(weak.expired());
    delete f;
  },
};

weak = strong;
strong.reset();
</pre></blockquote>
<p>
It seems clear that the intent is that associated <code>weak_ptr</code>s are expired,
because otherwise <code>shared_ptr</code> deleters could resurrect a reference to an object
that is being deleted.
<p/>
Suggested fix: 20.3.2.2.3 <a href="https://wg21.link/util.smartptr.shared.dest">[util.smartptr.shared.dest]</a> should specify that the decrease in
<code>use_count()</code> caused by the destructor is sequenced before the call to the
deleter or the call to <code>delete p</code>.
</p>

<p><i>[2016-11-08, Jonathan and STL suggest NAD]</i></p>

<p>
STL and Jonathan feel that the example has unspecified behaviour, and the
assertion is allowed to fire, and that's OK (the program's expectation
is not reasonable). Otherwise it's necessary to move-construct a copy
of the deleter and use that copy to destroy the owned pointer. We do
not want to be required to do that.
</p>
<p>See also <a href="lwg-active.html#2262" title="Requirement for unique_ptr&lt;T&gt;::get_deleter()(p) to be able to destroy the unique_ptr (Status: Open)">2262</a><sup><a href="https://cplusplus.github.io/LWG/issue2262" title="Latest snapshot">(i)</a></sup>.</p>

<p><i>[2017-09-20, Jonathan comments]</i></p>

<p>
I'd like to withdraw my NAD suggestion. The value of <code>use_count()</code> is already observable during the destructor via 
<code>shared_ptr</code> and <code>weak_ptr</code> objects that share ownership, so specifying when it changes ensures correct 
behaviour.
</p>

<p><i>[2025-03-18, Jonathan comments]</i></p>

<p>See also <a href="lwg-closed.html#2907" title="Semantics for destroying the deleter and the control-block of a shared_ptr are unclear (Status: NAD)">2907</a><sup><a href="https://cplusplus.github.io/LWG/issue2907" title="Latest snapshot">(i)</a></sup>.</p>



<p id="res-2751"><b>Proposed resolution:</b></p>





</body>
</html>
