Exercises¶
1. Exclusive Ownership With std::unique_ptr¶
Manage a dynamically allocated buffer with exclusive ownership and demonstrate move-only behavior.
Tasks:
Define
struct Buffer { std::size_t n; int* data; };and wrap it instd::unique_ptr<Buffer>usingstd::make_unique.Write a function
std::unique_ptr<Buffer> make_buffer(std::size_t n)that allocates and initializes.Show that copy construction fails to compile, but
auto b2 = std::move(b1);transfers ownership.Use
get()only for non-owning observation; print the address before and after the move.
2. unique_ptr With a Custom Deleter¶
Some resources require special destruction (e.g., FILE*, sockets, or malloc-allocated memory).
Tasks:
Write
struct FreeDeleter { void operator()(int* p) const noexcept { std::free(p); } };.Create
std::unique_ptr<int, FreeDeleter> p{ static_cast<int*>(std::malloc(4*sizeof(int))) };and initialize the array.Verify the custom deleter runs by printing in the deleter (optional).
Explain why
std::make_uniquecannot be used with a custom deleter.
3. unique_ptr in Containers (No Copies)¶
Store multiple move-only tasks in a vector.
Tasks:
Define
struct Task { int id; };.Create
std::vector<std::unique_ptr<Task>> v;and insert withemplace_back(std::make_unique<Task>(i))fori = 0..4.Iterate and print IDs; then move one element out:
auto t = std::move(v[2]);and showv[2] == nullptr.Try to copy an element and confirm the compiler error documents move-only semantics.
5. Breaking Cycles With weak_ptr¶
Prevent a leak-like cycle in a doubly linked pair.
Tasks:
Define:
struct Node { int v; std::shared_ptr<Node> next; std::weak_ptr<Node> prev; };
Link two nodes A↔B with
next(strong) forward andprev(weak) back.Exit scope; confirm both destructors run (print messages in destructors).
Explain why making
prevashared_ptrwould keep the objects alive.
6. weak_ptr::lock() Usage Pattern¶
Safely access an optionally alive object.
Tasks:
Create
auto s = std::make_shared<int>(100); std::weak_ptr<int> w{s};.Write
void print_if_alive(std::weak_ptr<int> w)that does:if (auto sp = w.lock()) { std::cout << *sp << '\n'; } else { std::cout << "expired\n"; }
Call it before and after
s.reset();to demonstrate both paths.
9. get_deleter and owner_before¶
Explore control-block features used in associative containers.
Tasks:
Create a
std::shared_ptr<int> s = std::make_shared<int>(7);with a custom deleter type (e.g., a struct that prints).Retrieve it via
auto* d = std::get_deleter<YourDeleter>(s);and confirm it is non-null.Put several
shared_ptr<int>intostd::setusing a comparator based onowner_before; demonstrate that the ordering is by ownership, not by raw pointer value.