{"id":111490,"date":"2025-08-20T07:00:00","date_gmt":"2025-08-20T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111490"},"modified":"2025-08-15T16:11:52","modified_gmt":"2025-08-15T23:11:52","slug":"20250820-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250820-00\/?p=111490","title":{"rendered":"Thoughts on creating a tracking pointer class, part 8: Tracking const objects"},"content":{"rendered":"<p>Last time, we <a class=\"\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250819-00\/?p=111488'\n  TITLE=\"> added the ability to create non-modifying tracking pointers<\/a>, but it required that you start with a non-const trackable object. But what if you want to create a non-modifying tracking pointer to an object to which you have only a const reference?<\/p>\n<p>It took me a few tries before I hit upon the simple solution.\u00b9<\/p>\n<p>We just need to make the trackable object&#8217;s <code>m_trackers<\/code> mutable, and then patch up the consequences.<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct trackable_object\r\n{\r\n    \u27e6 ... \u27e7\r\n\r\n    tracking_ptr&lt;T&gt; track() noexcept {\r\n        return { owner() };\r\n    }\r\n\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">tracking_ptr&lt;const T&gt; track() const noexcept {<\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    return { owner() };                       <\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">}                                             <\/span>\r\n\r\n    tracking_ptr&lt;const T&gt; ctrack() <span style=\"border: solid 1px currentcolor;\">const<\/span> noexcept {\r\n        return { owner() };\r\n    }\r\n\r\nprivate:\r\n    friend struct tracking_ptr_base&lt;T&gt;;\r\n\r\n    T* owner() <span style=\"border: solid 1px currentcolor;\">const<\/span> noexcept {\r\n        return <span style=\"border: solid 1px currentcolor;\">const_cast&lt;T*&gt;<\/span>(static_cast&lt;<span style=\"border: solid 1px currentcolor;\">const<\/span> T*&gt;(this));\r\n    }\r\n\r\n    tracking_node <span style=\"border: solid 1px currentcolor;\">mutable<\/span> m_trackers;\r\n\r\n    \u27e6 ... \u27e7\r\n};\r\n<\/pre>\n<p>After making the <code>m_trackers<\/code> mutable, we can make the <code>ctrack()<\/code> method <code>const<\/code>. We may as well also add a <code>track() const<\/code> that produces a read-only tracker from a const object. This is analogous to how C++ standard library container <code>begin()<\/code> and and <code>end()<\/code> methods produce read-only iterators if obtained from const containers.<\/p>\n<p>Casting away const when creating and updating the <code>tracking_ptr&lt;const T&gt;<\/code> is okay because the <code>tracking_ptr&lt;const T&gt;<\/code>&#8216;s <code>get()<\/code> method will reapply const before giving it to the client, and the only other use of the pointer is to access the <code>m_trackers<\/code>, which is now mutable.<\/p>\n<p>There&#8217;s still a problem: Although you can convert a <code>T*<\/code> to a <code>const T*<\/code>, a <code>std::<wbr \/>unique_ptr&lt;T&gt;<\/code> to a <code>std::<wbr \/>unique_ptr&lt;const T&gt;<\/code>, and a <code>std::<wbr \/>shared_ptr&lt;T&gt;<\/code> to a <code>std::<wbr \/>shared_ptr&lt;const T&gt;<\/code>, you cannot convert a <code>tracking_ptr&lt;T&gt;<\/code> to a <code>tracking_ptr&lt;const T&gt;<\/code>. We&#8217;ll fix that next time.<\/p>\n<p><b>Bonus chatter<\/b>: I considered whether I should also support <code>tracking_ptr&lt;volatile T&gt;<\/code> and <code>tracking_ptr&lt;const volatile T&gt;<\/code>. It wouldn&#8217;t be hard, but it would be extra typing. I decided not to, on the grounds that the C++ standard library typically doesn&#8217;t bother with <code>volatile<\/code> either: Standard containers have <code>begin()<\/code> and <code>cbegin()<\/code> but not <code>vbegin()<\/code> or <code>cvbegin()<\/code>.<\/p>\n<p>\u00b9 As Blaise Pascal is reported to have written, &#8220;If I had more time, I would have written a shorter letter.&#8221; Sometimes it takes a lot of work to come up with what ends up looking easy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Making tracking pointers to const objects.<\/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-111490","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Making tracking pointers to const objects.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111490","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=111490"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111490\/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=111490"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111490"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111490"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}