It’s well stablished that having raw pointers as part of a C++ API is not a good practice since it’s not clear who (The user or the API internals) manages the resource. Consider:
Let’s say you have an API that operates on
int buffers. The first function,
factory(), returns a new buffer ready to play with. The latter
have_fun() does something with a buffer.
When reading such declarations, I have no idea if when requesting a new buffer via a
factory() call if I’m in charge of deallocating it, or the return value from
factory() is just a handle to an internal resource managed by the library.
So, what’s the solution? Documentation? That’s what C has been doing for years: “RTFM, you shouldn’t call
memcpy() with negative numbers, so never use
int for sizes please.” Then we have heartbleed and similar bugs. Docs don’t prevent your code to compile. [begin rant] That’s why I prefer a language with a static type system, instead of
void* and cast-land [end rant].
Instead, using C++ resource handlers, owning semantics are clear:
“Oh, the library owns the buffer but it’s being shared with me.” That makes sense. But what about
have_fun()? Passing it as a
std::shared_ptr<int> has no much sense. Adding potential mutex lock for something that will not change the handle in any way.
std::shared_ptr<int>&? Too much syntactic nosise to just say “Hey, you don’t own the ptr ok? It’s RAII-managed by others”. So I will continue with the naked
C++ classes = RAII + properties
In general, I’m agree with the rule “RAII-ed resources for the API, naked ones for internals” not just because the (neigible?) performance gains but to reduce noise. But there’s something I like of owning resources trough objects: Properties. We usually wrap resources into objects to do RAII avoiding leaks thanks to our friend
}. But objects (classes) also provide member functions, which can be used to ask for the state and other properties of the resource with a simple and concise syntax: I’m the only one that feels
array.size() is far more readable than
Is there any intermediate solution? Raw resources with properties?
Raw resources, C++ version
std::vector. It manages a dynamic array.
vector has three kind of member functions: Special member functions (Constructors, destructor, etc to manage array lifetime), mutable functions (
reserve(), etc), and finally member functions that do not mutate the array itself but may change its data:
front(), back()`, etc.
What I propose is to split the implementation of resource handlers like
vector into two different classes: The one which contains the resource and non-mutating methods, and the one which does RAII and guarantees proper management of the resource (So mutating members belong here):
raw_vector does not own the dynamic array. It can be seen as a C++ view of a raw C dynamic array, with its same memory and performance footprint plus some C++ syntactic sugar. You can actually use this class directly as vector view (See bellow).
raw_vector provides the non-mutable facilities, and on top of that
vector owns the resource through RAII and implements all the operations that need to mutate the array:
vector has two deleted constructors, those that accept a raw vector as parameter. Constructing a vector from a raw one should be discouraged since we don’t know who owns that buffer.
Now we are able to avoid RAII overhead in contexts where we know we are not owning nor changing a resource, like API internals, while having a RAII interface: