Is it possible to initialize std :: vector from already allocated memory?

My question is quite simple, and I am very surprised that I can not find anything related. This is probably just or stupid (or I can’t search).

As the name says, is it possible to use std::vector in the already allocated memory, so it does not select new elements from the beginning, but uses what is given. I would think this is something like:

 T1 *buffer = new T1[some_size]; std::vector<T2> v(buffer, some_size); // <- ofc doesn't work 

The opposite is quite simple and (maybe not very, but) works:

 std::vector<T2> v(some_size); T1 *buffer = &v[0]; 

It is guaranteed that the repository will be continuous, therefore it is safe as an iterator.

My motivation is pretty simple. I am transferring some raw memory data, i.e. Bytes, and since I know their interpretation in some other places, I would like to convert them into something meaningful. I could do reinterpret_cast and use a regular c-style array, but I prefer C ++ objects.

I feel that this should be safe, given that we are abandoning the ownership of buffer on the vector, because it should be able to redistribute.

+7
c ++ arrays vector c ++ 11
source share
3 answers

Like this ... The containers in the standard usually take a dispenser. Using the allocator attributes of C ++ 11, it is very simple to create a distributor, since you do not need to have all the members in the distributor. However, if you are using an older version of C ++, you will need to implement each element and transcode!

For Pre-C ++ 11, you can use the following:

 #include <iterator> #include <vector> #include <iostream> template<typename T> class PreAllocator { private: T* memory_ptr; std::size_t memory_size; public: typedef std::size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; PreAllocator(T* memory_ptr, std::size_t memory_size) throw() : memory_ptr(memory_ptr), memory_size(memory_size) {}; PreAllocator (const PreAllocator& other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size) {}; template<typename U> PreAllocator (const PreAllocator<U>& other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size) {}; template<typename U> PreAllocator& operator = (const PreAllocator<U>& other) {return *this;} PreAllocator<T>& operator = (const PreAllocator& other) {return *this;} ~PreAllocator() {} pointer address (reference value) const {return &value;} const_pointer address (const_reference value) const {return &value;} pointer allocate (size_type n, const void* hint = 0) {return memory_ptr;} void deallocate (T* ptr, size_type n) {} void construct (pointer ptr, const T& val) {new (ptr) T (val);} template<typename U> void destroy (U* ptr) {ptr->~U();} void destroy (pointer ptr) {ptr->~T();} size_type max_size() const {return memory_size;} template<typename U> struct rebind { typedef PreAllocator<U> other; }; }; int main() { int my_arr[100] = {0}; std::vector<int, PreAllocator<int> > my_vec(PreAllocator<int>(&my_arr[0], 100)); my_vec.push_back(1024); std::cout<<"My_Vec[0]: "<<my_vec[0]<<"\n"; std::cout<<"My_Arr[0]: "<<my_arr[0]<<"\n"; int* my_heap_ptr = new int[100](); std::vector<int, PreAllocator<int> > my_heap_vec(PreAllocator<int>(&my_heap_ptr[0], 100)); my_heap_vec.push_back(1024); std::cout<<"My_Heap_Vec[0]: "<<my_heap_vec[0]<<"\n"; std::cout<<"My_Heap_Ptr[0]: "<<my_heap_ptr[0]<<"\n"; delete[] my_heap_ptr; my_heap_ptr = NULL; } 

For C ++ 11, you can use the following:

 #include <cstdint> #include <iterator> #include <vector> #include <iostream> template <typename T> class PreAllocator { private: T* memory_ptr; std::size_t memory_size; public: typedef std::size_t size_type; typedef T* pointer; typedef T value_type; PreAllocator(T* memory_ptr, std::size_t memory_size) : memory_ptr(memory_ptr), memory_size(memory_size) {} PreAllocator(const PreAllocator& other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size) {}; template<typename U> PreAllocator(const PreAllocator<U>& other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size) {}; template<typename U> PreAllocator& operator = (const PreAllocator<U>& other) { return *this; } PreAllocator<T>& operator = (const PreAllocator& other) { return *this; } ~PreAllocator() {} pointer allocate(size_type n, const void* hint = 0) {return memory_ptr;} void deallocate(T* ptr, size_type n) {} size_type max_size() const {return memory_size;} }; int main() { int my_arr[100] = {0}; std::vector<int, PreAllocator<int>> my_vec(0, PreAllocator<int>(&my_arr[0], 100)); my_vec.push_back(1024); std::cout<<"My_Vec[0]: "<<my_vec[0]<<"\n"; std::cout<<"My_Arr[0]: "<<my_arr[0]<<"\n"; int* my_heap_ptr = new int[100](); std::vector<int, PreAllocator<int>> my_heap_vec(0, PreAllocator<int>(&my_heap_ptr[0], 100)); my_heap_vec.push_back(1024); std::cout<<"My_Heap_Vec[0]: "<<my_heap_vec[0]<<"\n"; std::cout<<"My_Heap_Ptr[0]: "<<my_heap_ptr[0]<<"\n"; delete[] my_heap_ptr; my_heap_ptr = nullptr; } 

Pay attention to the difference between the two valves! This will work with both heap buffers / arrays and stack buffer / arrays. It will also work with most containers. It is safer to use the version of Pre-C ++ 11 because it will be backward compatible and work with a large number of containers (for example: std::List ).

You can simply place the dispenser in the header and use it as much as you want in any projects. Well, if you want to use SharedMemory or any buffer already allocated.

Caution: DO NOT use the same buffer for multiple containers at the same time! The buffer can be reused, but just make sure the two containers are not using it at the same time .

Example:

 int my_arr[100] = {0}; std::vector<int, PreAllocator<int> > my_vec(PreAllocator<int>(&my_arr[0], 100)); std::vector<int, PreAllocator<int> > my_vec2(PreAllocator<int>(&my_arr[0], 100)); my_vec.push_back(1024); my_vec2.push_back(2048); std::cout<<"My_Vec[0]: "<<my_vec[0]<<"\n"; std::cout<<"My_Arr[0]: "<<my_arr[0]<<"\n"; 

Exit above 2048! What for? Since the last vector was rewriting the values ​​of the first vector, since they have the same buffer.

+7
source share

Yes, std::vector accepts a custom dispenser as a template parameter that can achieve what you want.

+3
source share

If you look at the docs for std :: vector , you will see that the second parameter of the template is a custom allocator:

 template < class T, class Alloc = allocator<T> > class vector; 

You can define your own std :: allocator , which returns all the necessary memory. It can be a lot more work than is worth your goals.

However, you cannot just pass a pointer to random memory. You would have problems like: what if the vector needs to grow outside of your original buffer?

If you just want to sometimes work with raw bytes and vectors at other times, I would write helper functions to convert between them and just convert between them when necessary. If this causes performance issues (which you should measure), then your custom allocator is your next course of action.

+1
source share

All Articles