{"id":108361,"date":"2023-06-21T07:00:00","date_gmt":"2023-06-21T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108361"},"modified":"2024-11-25T17:38:49","modified_gmt":"2024-11-26T01:38:49","slug":"20230621-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230621-00\/?p=108361","title":{"rendered":"The case of the <CODE>make_shared<\/CODE> on a C++\/WinRT type"},"content":{"rendered":"<p>A customer asked for some debugging assistance with their C++\/WinRT object. It seemed that the code was crashing in an assignment statement. They were able to capture a Time Travel Trace, so let&#8217;s join our investigation already in progress.<\/p>\n<pre>(819c.6e48): Access violation - code c0000005 (first\/second chance not available)\r\nFirst chance exceptions are reported before any exception handling.\r\nThis exception may be expected and handled.\r\nTime Travel Position: 1010F3:0\r\nContoso!winrt::Windows::Foundation::IUnknown::unconditional_release_ref+0x31:\r\n00007ffc`08e03b15 mov     rax,qword ptr [rax+10h] ds:00000000`0000029d=????????????????\r\n<\/pre>\n<p>We are crashing on a garbage pointer. (The effective address is given as <code>00000000`0000029d<\/code>, which implies that the current value in <code>rax<\/code> is <code>00000000`0000028d<\/code>, which is not a valid pointer.)<\/p>\n<p>Let&#8217;s see where that pointer came from.<\/p>\n<pre>0:013&gt; u .-31 .\r\nContoso!winrt::Windows::Foundation::IUnknown::unconditional_release_ref:\r\n00007ffc`08e03ae4 mov     qword ptr [rsp+8],rcx\r\n00007ffc`08e03ae9 sub     rsp,48h\r\n00007ffc`08e03aed mov     qword ptr [rsp+28h],0\r\n00007ffc`08e03af6 mov     rax,qword ptr [rsp+50h]\r\n00007ffc`08e03afb lea     rdx,[rsp+28h]\r\n00007ffc`08e03b00 mov     rcx,rax\r\n00007ffc`08e03b03 call    Contoso!std::exchange (00007ffc`08d0c8dc)\r\n00007ffc`08e03b08 mov     qword ptr [rsp+20h],rax\r\n00007ffc`08e03b0d mov     rax,qword ptr [rsp+20h]\r\n00007ffc`08e03b12 mov     rax,qword ptr [rax]\r\n00007ffc`08e03b15 mov     rax,qword ptr [rax+10h]\r\n<\/pre>\n<p>We see that <code>rsp+20h<\/code> holds the exchanged-out <code>IUnknown<\/code> pointer, which means that the <code>mov rax, [rax]<\/code> loads the vtable, and the <code>mov rax, [rax+10h]<\/code> is trying to load a function from the vtable.<\/p>\n<p>Let&#8217;s see how we got here.<\/p>\n<pre>0:013&gt; g- 00007ffc`08e03ae4\r\nTime Travel Position: 1010C3:DB\r\nContoso!winrt::Windows::Foundation::IUnknown::unconditional_release_ref:\r\n00007ffc`08e03ae4 mov     qword ptr [rsp+8],rcx ss:000000d5`fa05e500=00007ffc00000000\r\n0:013&gt; t-\r\nTime Travel Position: 1010C3:DA\r\nContoso!winrt::Windows::Foundation::IUnknown::release_ref+0x19:\r\n00007ffc`08e01819 call Contoso!winrt::...::unconditional_release_ref (00007ffc`08e03ae4)\r\n0:013&gt; k\r\nRetAddr               Call Site\r\n00007ffc`092314b0     Contoso!winrt::Windows::Foundation::IUnknown::release_ref+0x19\r\n00007ffc`09231459     Contoso!winrt::Windows::Foundation::IUnknown::operator=+0x24\r\n00007ffc`09231569     Contoso!winrt::Windows::Foundation::IInspectable::operator=+0x1d\r\n00007ffc`092315e1     Contoso!winrt::Contoso::IGadget::operator=+0x1d\r\n00007ffc`0924d31b     Contoso!winrt::Contoso::Gadget::operator=+0x1d\r\n00007ffc`0925b1f2     Contoso!WidgetManager::SetPrimaryGadgetAsync$_ResumeCoro$1+0x103b\r\n00007ffc`09250273     Contoso!std::experimental::coroutine_handle&lt;void&gt;::resume+0x4a\r\n00007ffc`09223039     Contoso!winrt::impl::await_adapter&lt;...&gt;::await_suspend+0xdb\r\n00007ffc`0924cfdb     Contoso!winrt::impl::notify_awaiter&lt;...&gt;::await_suspend+0x31\r\n00007ffc`0925b1f2     Contoso!WidgetManager::SetPrimaryGadgetAsync$_ResumeCoro$1+0xcfb\r\n00007ffc`092326b7     Contoso!std::experimental::coroutine_handle&lt;void&gt;::resume+0x4a\r\n00007ffc`0925b2aa     Contoso!std::experimental::coroutine_handle&lt;void&gt;::operator()+0x13\r\n00007ffc`0923515f     Contoso!winrt::impl::resume_apartment+0xb2\r\n00007ffc`092215ad     Contoso!winrt::impl::disconnect_aware_handler&lt;...&gt;::Complete+0x9f\r\n00007ffc`09246c9e     Contoso!winrt::impl::disconnect_aware_handler&lt;...&gt;::operator()+0x2d\r\n00007ffc`8c7493fd     Contoso!winrt::impl::delegate&lt;...&gt;::Invoke+0x3e\r\n<\/pre>\n<p>We are running due to the completion of an asynchronous operation.<\/p>\n<pre>0:013&gt; u 00007ffc`0924d31b-80 00007ffc`0924d31b\r\nContoso!WidgetManager::SetPrimaryGadgetAsync$_ResumeCoro$1+0xfbb:\r\n...\r\n00007ffc`0924d2f8 mov     rax,qword ptr [rsp+600h]\r\n00007ffc`0924d300 mov     rax,qword ptr [rax+281h]\r\n00007ffc`0924d307 add     rax,58h\r\n00007ffc`0924d30b mov     rdx,qword ptr [rsp+470h]\r\n00007ffc`0924d313 mov     rcx,rax\r\n00007ffc`0924d316 call    Contoso!winrt::Contoso::Gadget::operator= (00007ffc`092315c4)\r\n00007ffc`0924d31b mov     eax,118h\r\n<\/pre>\n<p>We&#8217;re at this assignment statement:<\/p>\n<pre>IAsyncAction WidgetManager::SetPrimaryGadgetAsync()\r\n{\r\n    auto strongThis = get_strong();\r\n    co_await winrt::resume_background();\r\n\r\n    try\r\n    {\r\n        auto result = co_await GadgetFinder::GetGadgetAsync(GadgetKind::Primary);\r\n        if (result.Status() == GadgetFinderStatus::Success)\r\n        {\r\n            <span style=\"border: solid 1px currentcolor;\">m_primaryGadget = result.Gadget();<\/span> \/\/ \u21d0 here\r\n        }\r\n    }\r\n    catch(...)\r\n    {\r\n        LOG(\"Error finding primary gadget\", winrt::to_hresult());\r\n    }\r\n}\r\n<\/pre>\n<p>Let&#8217;s look at the state of our object just before calling the assignment operator.<\/p>\n<pre>0:013&gt; g- 00007ffc`0924d316\r\nTime Travel Position: 1010C3:B9\r\nContoso!WidgetManager::SetPrimaryGadgetAsync$_ResumeCoro$1+0x1036:\r\n00007ffc`0924d316 call    Contoso!winrt::Contoso::Gadget::operator= (00007ffc`092315c4)\r\n0:013&gt; dv\r\n                result = struct winrt::Contoso::FindGadgetResult\r\n            strongThis = struct winrt::com_ptr&lt;WidgetManager&gt;\r\n      __coro_frame_ptr = 0x00007ffc`0924c2e0\r\n0:013&gt; ?? strongThis\r\nstruct winrt::com_ptr&lt;WidgetManager&gt;\r\n   +0x000 m_ptr            : 0x0000028d`1207f0c0 WidgetManager\r\n0:013&gt; ?? strongThis.m_ptr\r\nclass WidgetManager * 0x0000028d`1207f0c0\r\n   +0x000 __VFN_table : ????\r\n   +0x018 vtable           : winrt::impl::produce&lt;WidgetManager,...&gt;\r\n   +0x008 __VFN_table : ????\r\n   +0x010 m_references     : std::atomic&lt;unsigned __int64&gt;\r\n   +0x020 m_widgetList     : winrt::IVectorView&lt;winrt::Contoso::Gadget&gt;\r\n   +0x028 m_initCompletedEvent : winrt::handle_type&lt;winrt::handle_traits&gt;\r\n   +0x030 m_mainWidgetName : std::wstring\r\n   +0x050 m_primaryGadget  : winrt::Contoso::Gadget\r\n<\/pre>\n<p>Those question marks look suspicious. What does this object look like?<\/p>\n<pre>0:013&gt; dps 0x0000028d`1207f0c0\r\n0000028d`1207f0c0  00000000`00000000\r\n0000028d`1207f0c8  00000000`00000000\r\n0000028d`1207f0d0  00700041`005c0001\r\n0000028d`1207f0d8  00000000`00000000\r\n0000028d`1207f0e0  00000000`00000000\r\n0000028d`1207f0e8  00000000`00000000\r\n0000028d`1207f0f0  0000028d`10ddb880\r\n0000028d`1207f0f8  0000028d`10ddd4e8\r\n0000028d`1207f100  0000028d`10ddd4e8\r\n0000028d`1207f108  0000028d`06f81940\r\n0000028d`1207f110  0000028d`06f81c34\r\n0000028d`1207f118  0000028d`06f81c34\r\n0000028d`1207f120  00000000`00000000\r\n0000028d`1207f128  00000000`00000000\r\n0000028d`1207f130  00000000`00000000\r\n0000028d`1207f138  00000000`00000000\r\n<\/pre>\n<p>Yeah, that doesn&#8217;t look good. The object is corrupted.<\/p>\n<p>Let&#8217;s see if it was corrupted when the coroutine began.<\/p>\n<pre>0:000&gt; bp Contoso!WidgetManager::SetPrimaryGadgetAsync\r\n0:000&gt; g-\r\nBreakpoint 0 hit\r\nTime Travel Position: 6EAA3:50\r\nContoso!WidgetManager::SetPrimaryGadgetAsync:\r\n00007ffc`0924d838 mov     qword ptr [rsp+10h],rdx ss:000000d5`f95fc838=0000028d0f8ab990\r\n0:002&gt; ?? ((Contoso!WidgetManager*)@rcx)\r\nclass WidgetManager * 0x0000028d`1207f0c0\r\n   +0x000 __VFN_table : 0x00007ffc`09c2c048\r\n   +0x018 vtable           : winrt::impl::produce&lt;WidgetManager,...&gt;\r\n   +0x008 __VFN_table : 0x00007ffc`09c2c098\r\n   +0x010 m_references     : std::atomic&lt;unsigned __int64&gt;\r\n   +0x020 m_widgetList     : winrt::IVectorView&lt;winrt::Contoso::Gadget&gt;\r\n   +0x028 m_initCompletedEvent : winrt::handle_type&lt;winrt::handle_traits&gt;\r\n   +0x030 m_mainWidgetName : std::wstring\r\n   +0x050 m_primaryGadget  : winrt::Contoso::Gadget\r\n0:002&gt; ?? ((Contoso!WidgetManager*)@rcx)-&gt;m_primaryGadget\r\nstruct winrt::Contoso::Gadget\r\n   +0x000 m_ptr            : (null)\r\n<\/pre>\n<p>Looks good. Let&#8217;s see when it gets corrupted.<\/p>\n<pre>0:013&gt; ba w4 @rcx\r\n0:002&gt; g\r\nBreakpoint 1 hit\r\nTime Travel Position: F253A:BC\r\nucrtbase!memcpy+0x2b1:\r\n00007ffc`aa2914a1 vmovdqu ymm1,ymmword ptr [rdx+r9-0A0h] ds:0000028d`119673c0=61\r\n0:013&gt; k\r\nRetAddr               Call Site\r\n00007ffc`8c72ab79     ucrtbase!memcpy+0x2b1\r\n(Inline Function)     Contoso!std::_Char_traits&lt;unsigned short,unsigned short&gt;::copy+0x11\r\n(Inline Function)     Contoso!std::wstring::assign::__l2::&lt;lambda_...&gt;::operator()+0x11\r\n(Inline Function)     Contoso!std::wstring::_Reallocate_for+0x6c\r\n(Inline Function)     Contoso!std::wstring::assign+0x72\r\n(Inline Function)     Contoso!std::wstring::assign+0xa8\r\n(Inline Function)     Contoso!std::wstring::{ctor}+0xc1\r\n00007ffc`8c72a9af     Contoso!winrt::Contoso::implementation::\r\n                                                     GadgetFinder::BuildGadgetQuery+0x179\r\n...\r\n00007ffc`0924ccf1     Contoso!winrt::Contoso::GadgetFinder::GetGadgetAsync+0x3c\r\n00007ffc`0925b1f2     Contoso!WidgetManager::SetPrimaryGadgetAsync$_ResumeCoro$1+0xa11\r\n00007ffc`092326b7     Contoso!std::experimental::coroutine_handle&lt;void&gt;::resume+0x4a\r\n00007ffc`0925b2aa     Contoso!std::experimental::coroutine_handle&lt;void&gt;::operator()+0x13\r\n00007ffc`0923515f     Contoso!winrt::impl::resume_apartment+0xb2\r\n00007ffc`092215ad     Contoso!winrt::impl::disconnect_aware_handler&lt;...&gt;::Complete+0x9f\r\n00007ffc`09246c9e     Contoso!winrt::impl::disconnect_aware_handler&lt;...&gt;::operator()+0x2d\r\n00007ffc`8c7493fd     Contoso!winrt::impl::delegate&lt;...&gt;::Invoke+0x3e\r\n<\/pre>\n<p>That&#8217;s strange. It&#8217;s being overwritten by a <code>std::wstring<\/code>.<\/p>\n<p>Wait a second, is the object already destroyed, and we&#8217;re operating on an a dead object? Let&#8217;s execute backward and see if the destructor gets hit.<\/p>\n<pre>0:008&gt; bd1\r\n0:008&gt; x Contoso!WidgetManager::~WidgetManager\r\n00007ffc`08d1d678 Contoso!WidgetManager::~WidgetManager (void)\r\n0:008&gt; g- 00007ffc`08d1d678\r\nTime Travel Position: F21CF:46\r\nContoso!WidgetManager::~WidgetManager:\r\n00007ffc`08d1d678 mov     qword ptr [rsp+8],rcx ss:000000d5`f95fe660=0000028d0f9fd0f0\r\n0:002&gt; r\r\nrax=00007ffc08d22ea0 rbx=0000000000000000 rcx=<span style=\"border: solid 1px currentcolor;\">0000028d1207f0c0<\/span> \u21d0 destructing our object\r\nrdx=0000000000000000 rsi=0000028d11950b48 rdi=0000028d11950b70\r\nrip=00007ffc08d1d678 rsp=000000d5f95fe658 rbp=0000028d11950b40\r\n r8=000000d5f95fe8d0  r9=0000000000000000 r10=00000fff811a45d5\r\nr11=0202020202222000 r12=0000028d0f876af0 r13=0000000000000000\r\nr14=0000028d11dfaa20 r15=0000000000000000\r\niopl=0         nv up ei pl nz na po nc\r\ncs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206\r\nContoso!WidgetManager::~WidgetManager:\r\n00007ffc`08d1d678 mov     qword ptr [rsp+8],rcx ss:000000d5`f95fe660=0000028d0f9fd0f0\r\n0:002&gt;\r\n<\/pre>\n<p>How about that, the breakpoint on the destructor was hit before we reached the start of the <code>WidgetManager::<wbr \/>Set\u00adPrimary\u00adGadget\u00adAsync<\/code> method. Since we are executing backward, this means that the <code>WidgetManager::<wbr \/>Set\u00adPrimary\u00adGadget\u00adAsync<\/code> method started, and then the <code>WidgetManager<\/code> was destroyed. Who is destroying the <code>WidgetManager<\/code>? I thought we had a strong reference to it. That strong reference should prevent the <code>WidgetManager<\/code> from destructing.<\/p>\n<pre>0:002&gt; k\r\nCall Site\r\nContoso!WidgetManager::~WidgetManager\r\nContoso!WidgetManager::`scalar deleting destructor'+0x17\r\nContoso!std::_Destroy_in_place&lt;WidgetManager&gt;+0x4f\r\nContoso!std::_Ref_count_obj2&lt;WidgetManager&gt;::_Destroy+0x1a\r\nContoso!std::_Ref_count_base::_Decref+0x4d\r\nContoso!std::_Ptr_base&lt;WidgetManager&gt;::_Decref+0x23\r\nContoso!std::shared_ptr&lt;WidgetManager&gt;::~shared_ptr+0x13\r\nContoso!winrt::Contoso::implementation::DoodadPageViewModel::~DoodadPageViewModel+0x71\r\n<span style=\"font-size: 80%;\">Contoso!winrt::impl::heap_implements&lt;implementation::DoodadPageViewModel&gt;::~heap_implements+0x13\r\nContoso!winrt::impl::heap_implements&lt;implementation::DoodadPageViewModel&gt;::`scalar deleting destructor'+0x17\r\nContoso!winrt::impl::root_implements&lt;implementation::DoodadPageViewModel&gt;::NonDelegatingRelease+0x6a\r\nContoso!winrt::impl::root_implements&lt;implementation::DoodadPageViewModel&gt;::Release+0x54<\/span>\r\nWindows_UI_Xaml!DirectUI::TrackerTargetReference::Clear+0x1ee\r\n...\r\n<\/pre>\n<p>You might notice something unusual about the stack trace that leads to the destructor. If you don&#8217;t, we can go back to the constructor:<\/p>\n<pre>0:002&gt; x Contoso!WidgetManager::WidgetManager\r\n00007ffc`08d167f8 Contoso!WidgetManager::WidgetManager (void)\r\n0:002&gt; g- 00007ffc`08d167f8\r\nTime Travel Position: 6EA29:114\r\nContoso!WidgetManager::WidgetManager:\r\n00007ffc`08d167f8 mov     qword ptr [rsp+18h],r8 ss:000000d5`f95fd7a0=00007ffc09c67028\r\n0:002&gt; r\r\nrax=00007ffc09c66fa0 rbx=0000000000000000 rcx=<span style=\"border: solid 1px currentcolor;\">0000028d1207f0c0<\/span> \u21d0 constructing our object\r\nrdx=00007ffc09c66fa0 rsi=0000028d0f89b4b0 rdi=0000028d1207f0c0\r\nrip=00007ffc08d167f8 rsp=000000d5f95fd788 rbp=0000000000000000\r\n r8=000000d5f95fd7d8  r9=00000000ffffffff r10=00007ffcaa240000\r\nr11=0000000000000000 r12=0000000000000000 r13=000000d5f95fe2b0\r\nr14=000000d5f95fe090 r15=0000000000000000\r\niopl=0         nv up ei pl nz na po nc\r\ncs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206\r\nContoso!WidgetManager::WidgetManager:\r\n00007ffc`08d167f8 mov     qword ptr [rsp+18h],r8 ss:000000d5`f95fd7a0=00007ffc09c67028\r\n0:002&gt; k\r\nCall Site\r\nContoso!WidgetManager::WidgetManager\r\nContoso!std::_Construct_in_place&lt;WidgetManager;&gt;+0x93\r\nContoso!std::_Ref_count_obj2&lt;WidgetManager&gt;::_Ref_count_obj2&lt;WidgetManager&gt;+0x7e\r\nContoso!std::make_shared&lt;WidgetManager&gt;+0x85\r\nContoso!Contoso::implementation::DoodadPageViewModel::DoodadPageViewModel+0x2b8\r\n<\/pre>\n<p>From the stack, we see that the <code>Widget\u00adManager<\/code> is being constructed via <code>std::<wbr \/>make_<wbr \/>shared<\/code>.<\/p>\n<p>Too bad C++\/WinRT objects aren&#8217;t supposed to be constructed via <code>std::<wbr \/>make_<wbr \/>shared<\/code>.<\/p>\n<p>C++\/WinRT objects are reference-counted and manage their reference count internally. Putting them inside a <code>shared_<wbr \/>ptr<\/code> creates a conflict between two reference counts: There&#8217;s a reference count in the C++\/WinRT object, and another reference count in the <code>shared_<wbr \/>ptr<\/code>.<\/p>\n<p>When the <code>Widget\u00adManager::<wbr \/>Set\u00adPrimary\u00adGadget\u00adAsync<\/code> method performs a <code>auto strongThis = get_strong();<\/code>, it is getting a <code>com_ptr&lt;Widget\u00adManager&gt;<\/code> whose lifetime is tracked in the reference count embedded in the <code>Widget\u00adManager<\/code>.<\/p>\n<p>Too bad the <code>shared_ptr<\/code> doesn&#8217;t know about that reference count.<\/p>\n<p>When the last <code>shared_ptr<\/code> reference goes away, the strong reference count in the <code>shared_ptr<\/code> control block goes to zero, and the <code>Widget\u00adManager<\/code> destructs. The reference count hiding inside the <code>Widget\u00adManager<\/code> does not participate in this decision.<\/p>\n<p>This explains why the <code>get_<wbr \/>strong()<\/code> call in the coroutine is ineffective in extending the lifetime of the <code>Widget\u00adManager<\/code>.<\/p>\n<p>At this point, you have to decide whether you want <code>Widget\u00adManager<\/code> to be a plain C++ object managed by <code>shared_ptr<\/code> or a fancy C++\/WinRT object managed by <code>winrt::implements<\/code>.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>\u00a0<\/th>\n<td><tt>std::shared_ptr<\/tt><\/td>\n<td><tt>winrt::implements<\/tt><\/td>\n<\/tr>\n<tr>\n<th>Base class<\/th>\n<td><tt>std::enable_shared_from_this<\/tt><\/td>\n<td><tt>winrt::implements<\/tt><\/td>\n<\/tr>\n<tr>\n<th>Create with<\/th>\n<td><tt>std::make_shared<\/tt><\/td>\n<td><tt>winrt::make<\/tt><\/td>\n<\/tr>\n<tr>\n<th>Get strong reference<\/th>\n<td><tt>shared_from_this()<\/tt><\/td>\n<td><tt>get_strong()<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In this particular case, the <code>Widget\u00adManager<\/code> implements some COM interfaces, so it needs to use <code>winrt::<wbr \/>implements<\/code> as its base class, and the correct function for creating the object is <code>winrt::make&lt;WidgetManager&gt;()<\/code>.<\/p>\n<p><b>Bonus chatter<\/b>: If the <code>_DEBUG<\/code> symbol is defined, then C++\/WinRT will trigger a build break\u00b9 if you construct a <code>winrt::implements<\/code>-derived object by some means other than <code>winrt::make<\/code>:<\/p>\n<pre style=\"white-space: pre-wrap;\">xmemory(1893,9): error C2259: 'WidgetManager': cannot instantiate abstract class\r\nsample.cpp(601): message : see declaration of 'WidgetManager'\r\nxmemory(1893,9): message : due to following members:\r\nxmemory(1893,9): message : 'void winrt::impl::root_<wbr \/>implements&lt;D,<wbr \/>winrt::Windows::Foundation::IInspectable&gt;::<wbr \/><span style=\"border: solid 1px currentcolor;\">use_<wbr \/>make_<wbr \/>function_<wbr \/>to_<wbr \/>create_<wbr \/>this_<wbr \/>object<\/span>(void)': is abstract\r\n        with\r\n        [\r\n            D=WidgetManager\r\n        ]\r\nbase.h(7308): message : see declaration of 'winrt::impl::root_<wbr \/>implements&lt;D,<wbr \/>winrt::Windows::Foundation::IInspectable&gt;::<wbr \/><span style=\"border: solid 1px currentcolor;\">use_<wbr \/>make_<wbr \/>function_<wbr \/>to_<wbr \/>create_<wbr \/>this_<wbr \/>object<\/span>'\r\n        with\r\n        [\r\n            D=WidgetManager\r\n        ]\r\nmemory(2027): message : see reference to class template instantiation 'std::_Wrap&lt;_Ty&gt;' being compiled\r\n        with\r\n        [\r\n            _Ty=WidgetManager\r\n        ]\r\nmemory(2725): message : see reference to class template instantiation 'std::_Ref_count_obj2&lt;_Ty&gt;' being compiled\r\n        with\r\n        [\r\n            _Ty=WidgetManager\r\n        ]\r\nsample.cpp(643): message : see reference to function template instantiation 'std::shared_ptr&lt;WidgetManager&gt; std::make_shared&lt;WidgetManager,&gt;(void)' being compiled\r\n<\/pre>\n<p>If the customer had turned on the <code>_DEBUG<\/code> symbol in their debug build, they would have found this problem much sooner.<\/p>\n<p>\u00b9 This is another example of compiler error meta-programming: structuring the code to influence the nature of the compiler error, in the hopes that the error will be more self-explanatory.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Now you can&#8217;t tell who&#8217;s in charge.<\/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-108361","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Now you can&#8217;t tell who&#8217;s in charge.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108361","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=108361"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108361\/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=108361"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108361"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108361"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}