Skip to content

← References, Pointers, Ownership step 2 of 4

Medium Primitives

A raw pointer owns nothing

A raw pointer such as Node* stores an address. Its type does not tell you who must destroy the object or how long the pointer remains valid.

A useful convention in modern C++ is to use raw pointers as non-owning observers: they provide access to an object managed elsewhere. This is a design convention, not a language restriction. Older interfaces and C APIs may transfer ownership through raw pointers, so read their contracts.

Pointer or reference?

Use T& when a function requires an existing object. Use T* when the interface needs a pointer, for example to represent an optional result with nullptr. A non-null pointer can still dangle, so checking for null does not prove that it is safe to dereference.

Property T& T*
Represents no object with a null value No valid null reference Yes, with nullptr
Can be changed to refer to another object No Yes, if the pointer variable is assignable
Automatically manages the object's lifetime No No

For ownership, prefer objects and containers with automatic cleanup: std::vector<T> manages its elements, std::unique_ptr<T> expresses exclusive ownership, and std::shared_ptr<T> expresses shared ownership. An observing pointer does not keep its target alive and must not delete it.

When a pointer becomes invalid

A pointer to a vector element becomes invalid when that element is destroyed or an operation invalidates its address. For example, push_back reallocates storage when the new size exceeds the vector's capacity. Reallocation invalidates every pointer, reference and iterator to its elements.

If push_back does not reallocate, pointers and references to existing elements remain valid. Other operations have their own rules: erasing an element invalidates references and iterators at and after the erased position. Check the operation's invalidation rules before keeping an observer across it.

Your task

Implement:

Node* find(std::vector<Node>& nodes, int id);

Return a pointer to the first node whose id matches, or nullptr if none matches. Return the address of the existing element, not a newly allocated copy. Do not change the vector's size or order.

The supplied apply function searches for each target ID and adds delta to a matching node's value. Leave apply unchanged. It does not resize the vector, so it can safely use each returned pointer immediately.

For nodes [(1, 10), (2, 20)], targets [1, 1, 3] and delta 5, the hit flags are [1, 1, 0] and the final values are [20, 20]. Each pair above is (id, value).

The starter allocates a copy of each matching node. Its hit flags look correct, but its writes change those copies instead of the vector elements, and the copies are never freed.