Better wrapper for `float*` using `std::vector<float>`

There's this old C API that could use a saner, safer wrapper around it. The API allocates a block of memory by itself and returns the pointer to it (the float* mentioned in the title) and the size. It also takes in float* const and size (though it never reallocates, thankfully)

The usage was quite similar to std::vector and indeed the first thing we did was copying the memory into a vector, freeing the original memory and returning the vector. The option to use std::unique_ptr wasn't considered since we don't get dynamic resizing among other niceties from std::vector.

Is there a way to use the original block of memory and hand it to a vector like class (not necessarily std::vector) without incurring the double memory usage penalty? A custom vector class is a solution, but not that I'd prefer to use.

9 comments · 76% upvoted · other discussions

comments

biliwald

Consider gsl::span (GSL) or std::span once C++20 hits.

A span is basically a wrapper for a pointer and a size, but won't take ownership of the data.

codingate [OP]

Sadly, I'd prefer a owning resource, something about RAII is really nice

biliwald

I misunderstood your post. I thought you didn't own the resource.

codingate [OP]

Solved!

Almost the correct answer and the one I should have seen at the very beginning.

Use a unique ptr (or not), add a few functions, inherit from span. Sure, it's one extra pointer with unique ptr and some dirt without, but it's a working solution.

Ilyps

It's unlikely that you can have any standard C++ container (with standard allocator) take possession of the data, since it (presumably) was allocated with malloc. That means that any resizing/freeing operation with delete will be UB.

Copying likely is the most reasonable choice. If you really can't afford the copy, you can probably hack the functionality into std::vector, but it would be horrible.

codingate [OP]

That means that any resizing/freeing operation with delete will be UB

Not necessarily. I don't know how legal the following code is godbolt link, but a custom allocator can manage the deallocation just fine. The issue is making std::vector (or any other implementation) accept the ownership of a foreign pointer.

My impl is bad, but only because I can't send a malloc pointer into the vector

Ilyps

but a custom allocator can manage the deallocation just fine.

That's why I said "with standard allocator". :)

My impl is bad, but only because I can't send a malloc pointer into the vector

There is direct data access which should allow you to mess with the data pointer, but you still wouldn't be able to set things like size and capacity. That's why you'd really need to hack the functionality into std::vector, probably via public inheritance. But since there is no standard implementation for std::vector, that would get messy fast.

Xeverous

You basically want a vector-like API but non-owning said memory. This is exactly what is std::span in C++20. You can use it now from boost::range library.

codingate [OP]

span is almost the right thing. It doesn't allow increasing the size and it is not owning. I realized that I can create a class derived from span which has a unique ptr to the memory as well as the resize functionality.

Much better interface than mucking around with allocators.