{"id":106877,"date":"2022-07-20T07:00:00","date_gmt":"2022-07-20T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106877"},"modified":"2022-07-20T07:13:39","modified_gmt":"2022-07-20T14:13:39","slug":"20220720-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220720-00\/?p=106877","title":{"rendered":"My class derives from <CODE>std::enable_<WBR>shared_<WBR>from_<WBR>this<\/CODE>, but <CODE>shared_<WBR>from_<WBR>this()<\/CODE> doesn&#8217;t work"},"content":{"rendered":"<p>If you make a class <code>T<\/code> that derives from <code>std::enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this&lt;T&gt;<\/code>, then the creation of a <code>std::shared_ptr<\/code> to that class will activate the <code>shared_<wbr \/>from_<wbr \/>this()<\/code> method to return a <code>shared_ptr<\/code> that shares ownership with the originally-created <code>std::shared_ptr<\/code>.<\/p>\n<p>The catch is that the <code>shared_ptr<\/code> constructor and <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code> are in cahoots, and the <code>shared_ptr<\/code> must be able to access the <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code> in order to finish the job. This requires that you <i>publicly<\/i> derive from <code>std::enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code>:<\/p>\n<pre>class MyClass : <span style=\"color: blue;\">public<\/span> std::enable_shared_from_this&lt;MyClass&gt;\r\n{\r\n    ...\r\n};\r\n<\/pre>\n<p>If you forget the <code>public<\/code> keyword, then the base class defaults to <code>private<\/code>, and the secret signal between <code>shared_ptr<\/code> and <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code> does not get through.<\/p>\n<p>Here&#8217;s how <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code> and <code>shared_ptr<\/code> work together. Note that I&#8217;ve ignored edge cases; the idea here is to give the basic idea so you can diagnose <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code> issues yourself.<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct enable_shared_from_this\r\n{\r\n    shared_ptr&lt;T&gt; shared_from_this()\r\n    { return shared_ptr&lt;T&gt;(weak_this); }\r\n\r\n    weak_ptr&lt;T&gt; weak_this;\r\n};\r\n\r\ntemplate&lt;typename T&gt;\r\nstruct shared_ptr\r\n{\r\n    shared_ptr(T* p) : ptr(p)\r\n    {\r\n        if (T derives from enable_shared_from_this) {\r\n            ptr-&gt;weak_ptr = *this;\r\n        }\r\n    }\r\n\r\n    T* ptr;\r\n    \/* other stuff *\/\r\n};\r\n<\/pre>\n<p>When a <code>shared_ptr<\/code> is created, it snoops at the managed object to see if it derives from <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code>. If so, then it sets the <code>weak_ptr<\/code> to hold a weak pointer to the shared object. When you later ask for a <code>shared_<wbr \/>from_<wbr \/>this()<\/code>, it promotes this weak pointer to a shared pointer and returns it.<\/p>\n<p>Okay, so we already see some consequences and pitfalls:<\/p>\n<p>First of all, if you fail to derive <i>publicly<\/i> from <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code>, the feature simply fails silently. There is no diagnostic that says, &#8220;Hey, like, you&#8217;re deriving from <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code>, but you did it privately, so it&#8217;s not going to work.&#8221;\u00b9<\/p>\n<p>Second, notice that the weak pointer is set only when the object is placed inside a <code>shared_ptr<\/code>, which happens <i>after<\/i> the shared object has been constructed. This means that you cannot use <code>shared_<wbr \/>from_<wbr \/>this()<\/code> in your constructor.<\/p>\n<p>Third, if the object is not wrapped inside a <code>shared_<wbr \/>ptr<\/code> at all, then <code>shared_<wbr \/>from_<wbr \/>this()<\/code> will always fail. For example, if somebody constructs the object on the stack, or via <code>new<\/code> or <code>make_unique<\/code>, it will not be controlled by a <code>shared_<wbr \/>ptr<\/code>.<\/p>\n<p>There are so many ways <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code> can go wrong. Next time, we&#8217;ll see what we can do to guard against them.<\/p>\n<p>\u00b9 Maybe it&#8217;s possible to add a diagnostic to <code>shared_<wbr \/>from_<wbr \/>this()<\/code>. I wonder if the shared type is required to be complete by that point.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Various cases where your enabled <CODE>shared_<WBR>from_<WBR>this<\/cODE> doesn&#8217;t work.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-106877","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Various cases where your enabled <CODE>shared_<WBR>from_<WBR>this<\/cODE> doesn&#8217;t work.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106877","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=106877"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106877\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=106877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}