We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← References, Pointers, Ownership step 3 of 4
The gap between new and the smart pointer
Sometimes an object genuinely must outlive the scope that made it, or must be referred to through a base class. Then it goes on the heap, and the question is who deletes it.
std::unique_ptr<T>is the answer unless you can prove you need another one. Exactly one owner, destroyed when that owner goes out of scope.
It is not a compromise you accept for safety. A unique_ptr is the size of a
pointer, and its operator-> compiles to the same instruction a raw pointer
does. There is no reference count, no allocation, no indirection. You are
giving up nothing.
What it gives you is a signature that cannot be misread:
std::unique_ptr<Shape> make_shape(...); // caller now owns this
void consume(std::unique_ptr<Shape> s); // callee takes it
void inspect(const Shape& s); // borrowed, definitely there
Shape* find(...); // borrowed, maybe not there
Four different intentions, four different types, none of them a comment.
Use make_unique. Always.
auto a = std::unique_ptr<Rect>(new Rect(w, h)); // don't
auto b = std::make_unique<Rect>(w, h); // do
It is shorter, it says the type once instead of twice, and — the reason this problem exists — there is no moment where the object is owned by nobody.
In the first line, new Rect(w, h) returns a raw pointer, and then the
unique_ptr is constructed from it. Between those two events the object is
live and unowned. Anything that goes wrong in that window leaks it: an
exception thrown while evaluating another argument, an early return added
by someone six months later, or simply a branch that decides the object was
not wanted after all.
That last one is not exotic. It is the most common leak in code that has already adopted smart pointers, because the author thinks the smart pointer is protecting them and the raw pointer above it is not covered yet.
The rest of the interface, briefly
p.get() |
the raw pointer, as a non-owning observer — never delete it |
p.reset() |
destroy what is held, hold nothing |
p.release() |
give up ownership and return the raw pointer — you now owe a delete |
std::move(p) |
transfer ownership; p is guaranteed null afterwards |
release() is the one to be suspicious of. It exists for handing a pointer
to a C API, and almost every other use is a leak with extra steps.
Your task
std::unique_ptr<Shape> make_shape(int kind, int a, int b);
Kind 1 is a Rect(a, b), kind 2 is a Square(a), and anything else is
nullptr. A shape whose area is zero or negative is also rejected: return
nullptr rather than the shape.
audit is given and calls it; do not change it. Shape counts how many
instances are alive, and the harness reads that count after audit has
returned and every kept shape has been destroyed. It must be zero.
The starter allocates first and decides second.
Stuck?
C++ reference solution
Sign in to attempt this problem and reveal the reference solution.