Search code examples
c++vectormemory-addressfacade

Can I use an std::vector as a facade for a pre-allocated (raw) array?


I have acquired a memory location from DirectX where my vertex information is stored. An extremely convenient way to deal with vertex information is to use a std::vector<> of a struct containing vertex info.

Given that I have a pointer to a large buffer, could I use a std::vector to manage the elements in the buffer? Constructing a std::vector regularly causes it to have its own address, which isn't really what I want. Could I use operator placement new somehow?


Solution

  • Yes you can. Use custom allocator. In this allocator return address of your DirectX memory.

    Here is a complete examlpe based on an answer from Compelling examples of custom C++ STL allocators?. This solution uses placement new in the allocator.

    #include <memory>
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    template <typename T>
    class placement_memory_allocator: public std::allocator<T>
    {
        void* pre_allocated_memory;
    public:
        typedef size_t size_type;
        typedef T* pointer;
        typedef const T* const_pointer;
    
        template<typename _Tp1>
        struct rebind
        {
                typedef placement_memory_allocator<_Tp1> other;
        };
    
        pointer allocate(size_type n, const void *hint=0)
        {
                char* p = new(pre_allocated_memory)char[n * sizeof(T)];
                cout << "Alloc " << n * sizeof(T) << " bytes @" << hex << (void*)p <<endl;
                return (T*)p;
        }
    
        void deallocate(pointer p, size_type n)
        {
                cout << "Dealloc " << n << " bytes @" << hex << p << endl;
                //delete p;
        }
    
        placement_memory_allocator(void* p = 0) throw(): std::allocator<T>(), pre_allocated_memory(p) { cout << "Hello allocator!" << endl; }
        placement_memory_allocator(const placement_memory_allocator &a) throw(): std::allocator<T>(a) {pre_allocated_memory = a.pre_allocated_memory;}
        ~placement_memory_allocator() throw() { }
    };
    
    class MyClass
    {   
        char empty[10];
        char* name;
    public:
        MyClass(char* n) : name(n){ cout << "MyClass: " << name << " @" << hex << (void*)this << endl; }
        MyClass(const MyClass& s){ name = s.name; cout << "=MyClass: " << s.name << " @" << hex << (void*)this << endl; }
        ~MyClass(){ cout << "~MyClass: " << name << " @" << hex << (void*)this <<  endl; }
    };
    
    int main()
    {
        // create allocator object, intialized with DirectX memory ptr.
        placement_memory_allocator<MyClass> pl(DIRECT_X_MEMORY_PTR);
        //Create vector object, which use the created allocator object.
        vector<MyClass, placement_memory_allocator<MyClass>> v(pl);
        // !important! reserve all the memory of directx buffer.
        // try to comment this line and rerun to see the difference
        v.reserve( DIRECT_X_MEMORY_SIZE_IN_BYTES / sizeof(MyClass));
    
        //some push backs.
        v.push_back(MyClass("first"));
        cout << "Done1" << endl;
        v.push_back(MyClass("second"));
        cout << "Done1" << endl;
        v.push_back(MyClass("third"));
        cout << "Done1" << endl;
    
    }