{"id":111486,"date":"2025-08-18T07:00:00","date_gmt":"2025-08-18T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111486"},"modified":"2025-08-15T16:06:22","modified_gmt":"2025-08-15T23:06:22","slug":"20250818-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250818-00\/?p=111486","title":{"rendered":"Thoughts on creating a tracking pointer class, part 6: Non-modifying trackers"},"content":{"rendered":"<p>Let&#8217;s add non-modifying trackers to <a title=\"Thoughts on creating a tracking pointer class, part 5\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250815-00\/?p=111484\">our tracking pointers implementation<\/a>. That is, a tracking pointer that gives you only read-only access to the tracked object.<\/p>\n<p>The idea is that tracking pointers and non-modifying tracking pointers all share the same circular doubly linked list. The only difference is what kind of pointer comes out of <code>get<\/code>.<\/p>\n<p>First, we&#8217;ll introduce a nickname <code>MT<\/code> meaning &#8220;mutable (non-const) version of <code>T<\/code>&#8221; and have <code>tracking_ptr<\/code> use it instead of <code>T<\/code>, with the exception of the <code>get()<\/code> method, which returns the (possibly-const) original type <code>T<\/code>. (Actually, we may as well also remove volatility while we&#8217;re at it. Completing volatility support will be left as a pointless exercise.)<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct tracking_ptr : private tracking_node\r\n{\r\n<span style=\"border: solid 1px currentcolor; border-bottom: none;\">private:                           <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    using MT = std::remove_cv_t&lt;T&gt;;<\/span>\r\n                                   \r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">public:                            <\/span>\r\n\r\n    T* get() const { return tracked; }\r\n\r\n    \u27e6 ... other public members as before ... \u27e7\r\n\r\nprivate:\r\n    friend struct trackable_object&lt;<span style=\"border: solid 1px currentcolor;\">MT<\/span>&gt;;\r\n\r\n    static tracking_node&amp; trackers(<span style=\"border: solid 1px currentcolor;\">MT<\/span>* p) noexcept {\r\n        return p-&gt;trackable_object&lt;<span style=\"border: solid 1px currentcolor;\">MT<\/span>&gt;::m_trackers;\r\n    }\r\n\r\n    tracking_ptr(<span style=\"border: solid 1px currentcolor;\">MT<\/span>* p) noexcept :\r\n        tracking_node(as_join{}, trackers(p)),\r\n        tracked(p) {\r\n    }\r\n\r\n    \u27e6 ... \u27e7\r\n\r\n    <span style=\"border: solid 1px currentcolor;\">MT<\/span>* tracked;\r\n};\r\n<\/pre>\n<p>Next, we add a <code>ctrack()<\/code> method to the <code>trackable_object<\/code> to produce a non-modifying tracking pointer.<\/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; ctrack() 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\nprivate:\r\n    friend struct tracking_ptr&lt;T&gt;;\r\n    <span style=\"border: solid 1px currentcolor;\">friend struct tracking_ptr&lt;const T&gt;;<\/span>\r\n\r\n    \u27e6 ... \u27e7\r\n};\r\n<\/pre>\n<p>Okay, now we can have an object give away a non-modifying tracking pointer to itself by using <code>ctrack()<\/code> instead of <code>track()<\/code>.<\/p>\n<p>But wait, this code is wrong.<\/p>\n<p>We&#8217;ll continue our investigation next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Making tracking pointers to objects that you can&#8217;t modify.<\/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-111486","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Making tracking pointers to objects that you can&#8217;t modify.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111486","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=111486"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111486\/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=111486"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111486"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111486"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}