Concise way of acquiring and releasing lists of resources

I’m looking for suggestions on a concise way of acquiring (creating, allocating, opening, etc.) a number of resources one by one, and then using defer to release (destroy, free, close, etc.) them one by one in the reverse order when leaving the scope.

And if something fails mid-initialization, the work thus far should of course get undone; e.g. if I need 8 resources in total, but the 5th acquisition fails, I want the previous 4 to be released properly.

For example, if I have the two functions acquireResource and releaseResource, I could write something like this:

const r1 = try acquireResource();
defer releaseResource(r1);

const r2 = try acquireResource();
defer releaseResource(r2);

const r3 = try acquireResource();
defer releaseResource(r3);

const r4 = try acquireResource();
defer releaseResource(r4);

const r5 = try acquireResource();
defer releaseResource(r5);

But this is obvious only practical if I need a very small number of resources. What if I need 10 or 100?

The method I’ve come up with that I like the most is the following:

const n = 10;

var resources: std.BoundedArray(*anyopaque, n) = .{};
defer while (resources.popOrNull()) |resource| {
    releaseResource(resource);
};
while (resources.len < n) {
    resources.appendAssumeCapacity(try acquireResource());
}

But I’m curious if anyone has any better suggestions.