Coding
C++ Internals

RAII Resource Wrapper

Difficulty

Asked at Squarepoint Capital, Jump Trading

Theory: C++ Internals

Read the problem, hints and solution here. The editor needs a bigger screen: open this page on a laptop to write and run your code.

Half of C++ interviewing at systems-minded funds is one question asked many ways: do you actually understand object lifetime? The cleanest probe is wrapping a C-style resource API in an owning handle, because every mistake (leak, double release, broken move) is observable and every fix is a rule-of-five decision.

The scaffold provides a fake C API, fake_api, which you must not modify: acquire_resource() returns a fresh positive id and release_resource(id) returns it. The API is instrumented: acquired_count(), released_count(), live_count() and double_release_count() (releases of an id that was not live) let the tests watch your handle's behaviour from outside. That instrumentation stands in for the malloc/free, fd open/close or exchange-session handles a real wrapper would manage.

Implement ResourceHandle, a move-only owning wrapper:

  • ResourceHandle(): acquires a resource from fake_api and owns it (resource acquisition is initialization).
  • Destructor: releases the owned resource exactly once. A handle that owns nothing releases nothing.
  • Copy constructor and copy assignment: deleted. Two owners of one id would mean a double release.
  • Move constructor: steals the source's resource; the source is left empty (valid() == false, id() == 0).
  • Move assignment: releases whatever the destination currently owns, then steals from the source, leaving it empty. Self-move assignment must be safe: the handle keeps its resource and nothing is released twice.
  • long long id() const (0 when empty) and bool valid() const are provided in the scaffold.

Mark the move operations noexcept: one hidden test stores handles in a std::vector and pushes through several reallocations, which is exactly where a missing or throwing move turns into copies or double releases.

Examples

[]{ fake_api::reset_instrumentation(); { ResourceHandle a; ResourceHandle b; } return std::tuple<long long, long long, long long, long long>{fake_api::acquired_count(), fake_api::released_count(), fake_api::double_release_count(), fake_api::live_count()}; }()
// (2, 2, 0, 0)  (two acquired, two released, no double release, nothing live)

[]{ fake_api::reset_instrumentation(); std::vector<long long> out; { ResourceHandle a; long long ida = a.id(); ResourceHandle b(std::move(a)); out.push_back(a.valid() ? 1 : 0); out.push_back(b.id() == ida ? 1 : 0); out.push_back(fake_api::acquired_count()); out.push_back(fake_api::live_count()); } out.push_back(fake_api::released_count()); out.push_back(fake_api::double_release_count()); return out; }()
// [0, 1, 1, 1, 1, 0]  (move transfers the id; only one acquire, one release)

Constraints

  • Do not modify the fake_api namespace; the tests call reset_instrumentation() themselves.
  • No dynamic allocation is needed; the handle is a single long long plus discipline.
  • The hidden tests check the counter balance after moves, self-move, vector reallocation, and verify via type traits that copying is deleted while moving exists.
Rate this problem
Language: C++ResourceHandle
Sample tests

Run your code to check it against the sample tests. Results appear here.

Rate this problem
Next in Quant Dev 50Smart Pointer From Scratch