𝗖𝗮𝗰𝗵𝗶𝗻𝗴 𝘄𝗶𝘁𝗵 𝘀𝘁𝗱::𝘄𝗲𝗮𝗸_𝗽𝘁𝗿 𝗶𝗻 𝐂++
🎯𝗖𝗮𝗰𝗵𝗶𝗻𝗴 𝘄𝗶𝘁𝗵 𝘀𝘁𝗱::𝘄𝗲𝗮𝗸_𝗽𝘁𝗿 𝗶𝗻 𝐂++
There are a few potential use cases for std::weak_ptr:
✅Caching
✅Observer lists
✅Breaking std::shared_ptr ownership cycles
This post focuses on the first one: caching
🔍𝐖𝐡𝐚𝐭 𝐢𝐬 𝐬𝐭𝐝::𝐰𝐞𝐚𝐤_𝐩𝐭𝐫?
1️⃣It is a smart pointer that observes an object managed by std::shared_ptr without participating in its shared ownership. In other words, it neither affects the strong reference count nor 𝗸𝗲𝗲𝗽𝘀 𝘁𝗵𝗲 𝗺𝗮𝗻𝗮𝗴𝗲𝗱 𝗼𝗯𝗷𝗲𝗰𝘁 𝗮𝗹𝗶𝘃𝗲.
2️⃣This means a std::weak_ptr has to deal with the possibility that what it points to 𝗵𝗮𝘀 𝗮𝗹𝗿𝗲𝗮𝗱𝘆 𝗯𝗲𝗲𝗻 𝗱𝗲𝘀𝘁𝗿𝗼𝘆𝗲𝗱.
3️⃣The relationship between std::weak_ptr and std::shared_ptr can begin at birth. std::weak_ptrs are typically initialized from std::shared_ptrs and point to the same object as those shared_ptrs. They can also start empty.
4️⃣A std::weak_ptr 𝗲𝘅𝗽𝗶𝗿𝗲𝘀 when the last std::shared_ptr owning the managed object releases ownership. Since a std::weak_ptr can 𝗼𝘂𝘁𝗹𝗶𝘃𝗲 the object it observes, it provides no API to dereference that object directly. Instead, call lock() to get a shared_ptr that keeps the managed object alive while you use it. If the weak_ptr has expired, lock() returns an empty shared_ptr. Checking expiration and getting shared ownership happen in 𝗼𝗻𝗲 𝗮𝘁𝗼𝗺𝗶𝗰 𝘀𝘁𝗲𝗽.
🤔𝗬𝗼𝘂 𝗺𝗮𝘆 𝗯𝗲 𝘄𝗼𝗻𝗱𝗲𝗿𝗶𝗻𝗴 𝗵𝗼𝘄 𝗮 𝘀𝘁𝗱::𝘄𝗲𝗮𝗸_𝗽𝘁𝗿 𝗰𝗼𝘂𝗹𝗱 𝗯𝗲 𝘂𝘀𝗲𝗳𝘂𝗹.
Imagine a factory function, 𝘭𝘰𝘢𝘥𝘞𝘪𝘥𝘨𝘦𝘵, that accepts an ID and returns a std::unique_ptr to a read-only Widget holding that ID and its text. Loading that Widget involves 𝗲𝘅𝗽𝗲𝗻𝘀𝗶𝘃𝗲 𝗼𝗽𝗲𝗿𝗮𝘁𝗶𝗼𝗻𝘀 such as reading the data for that ID from a file or database.
E.g., loadWidget(3) could use 3 to find a database record, read its text and pass both the ID and text to the Widget constructor.
Get Samira’s stories in your inbox
Join Medium for free to get updates from this writer.
💡If callers keep requesting the same ID and its data doesn’t change, why repeat the expensive work while the Widget is alive? We can 𝗰𝗮𝗰𝗵𝗲 results without keeping every Widget alive. 𝘧𝘢𝘴𝘵𝘓𝘰𝘢𝘥𝘞𝘪𝘥𝘨𝘦𝘵 caches std::weak_ptrs and returns std::shared_ptrs:
🔹ID found? Return lock()’s shared_ptr if non-empty.
🔹Missing or expired? Call 𝘭𝘰𝘢𝘥𝘞𝘪𝘥𝘨𝘦𝘵, move its unique_ptr into a shared_ptr, cache a weak_ptr and return the shared_ptr.
⚠️This only helps while a shared owner still holds the Widget between requests. Otherwise, each call reloads it.
💡loadWidget uses make_unique. fastLoadWidget transfers ownership through the shared_ptr constructor. make_shared can’t be used here because the Widget already exists. With separate allocations, releasing the last shared owner destroys the Widget and frees its storage. Only the control block stays until the last weak reference is released.
📝Demo is simplified. Real caches may need thread safety, clearing expired entries and data refresh.
🔗𝗗𝗲𝗺𝗼: godbolt.org/z/zWc4W95b8
➡️Source: Effective Modern C++ by Scott Meyers, Item 20





