12

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?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
kvanbere
  • 3,289
  • 3
  • 27
  • 52
  • What operations do you want to use from `std::vector`? – David Brown Feb 11 '13 at 07:14
  • Just .push_back() to add vertices, the ability to remove them would be great but isn't necessary, and .size() to know the number of vertices in the container. – kvanbere Feb 11 '13 at 07:30
  • `push_back` will cause the vector to allocate a new memory block at a different memory location that has room for the additional elements. – David Brown Feb 11 '13 at 07:38
  • 1
    Looks like the easiest way is probably just to write my own structure then, std::vector seems too hard to wrap around for this purpose. – kvanbere Feb 11 '13 at 07:40
  • 1
    @kvanberendonck You could possibly use a `std::vector` with a custom allocator that continuously returns the same buffer space but it would have to throw if the vector requested more space than the buffer has and there is no easy way to ask the vector to allocate precisely the size of the buffer. – John5342 Feb 11 '13 at 14:16
  • You might want to check [`std::scoped_ptr< T[] >`](http://stackoverflow.com/questions/8624146/c11-standard-scoped-array-wrappers) – MSalters Feb 11 '13 at 14:36
  • Use `array_view` from GSL ( https://github.com/Microsoft/GSL ) or `boost::multi_array_ref`. – sbabbi Jan 15 '16 at 09:09

2 Answers2

11

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;

}
Community
  • 1
  • 1
Yousf
  • 3,957
  • 3
  • 27
  • 37
  • Hello, I copied it into a test project to debug it and see how it works. I used malloc to make a simple constant sized buffer to simulate the vbo buffer (and set DIRECT_X_MEMORY_PTR as void* pointing to it) and set the size appropriately to what I was allocating (and set DIRECT_X_MEMORY_SIZE_IN_BYTES to this as size_t). On compile using msvc 2012 I'm getting `error C2664: 'placement_memory_allocator::placement_memory_allocator(void *) throw()' : cannot convert parameter 1 from 'std::_Wrap_alloc<_Alloc>' to 'void *'`. Any ideas? [Code here: http://pastie.org/6121725 ] – kvanbere Feb 12 '13 at 00:55
  • 1
    It is something changed in Visual Studio 2012. Microsoft changed some allocator-related header files. See this for some info http://bit.ly/UacbcT – Yousf Feb 12 '13 at 15:14
0

The elements of std::vector are allocated dynamically on the heap (with new by std::vector itself) in such a way that they are always contiguous in memory. So if your structure is vertex, using std::vector<vertex> is not what you want as the elements of the vector will not be located in your large buffer.

You could use std::vector<vertex*> however, like for example:

vertex* bigBuffer;     // provided by DirectX
size_t bigBufferLen;   // provided by DirectX

std::vector<vertex*> array;
for (size_t i = 0; i < bigBufferLen; ++i)
{
    array.push_back(bigBuffer + i * sizeof(vertex));
}
Aurélien
  • 1,742
  • 1
  • 19
  • 30
  • I think I may have understood the question in the wrong way. If it's the case, tell me and I will remove my answer. – Aurélien Feb 11 '13 at 07:04
  • I actually want to manage the memory using a vector, as if it were an array with the ability to add/remove. So, if the buffer given by DX is a long and continuous buffer I was hoping that to "add" vectors into the VBO I could use push_back and then pass vector.size() as the number of vectors to draw to DX. Other possible structures/options/framework suggestions are welcome! – kvanbere Feb 11 '13 at 07:27
  • I'd _prefer_ not to memcpy from .data() into the actual buffer all the time, as it just means alot of copying each time a new vector is added. I was hoping a cool way of managing them straight in the buffer. – kvanbere Feb 11 '13 at 07:28
  • 1
    OK, I understand now. You can prevent std::vector to allocate on the heap by "telling" him how/where to allocate, i.e. by giving him an ["Allocator"](http://www.cplusplus.com/reference/vector/vector/). I admit, I have never tried that, but according to the description it seems like you can achieve the wanted result if the implementation of your allocator returns a pointer to your buffer instead of calling "new". – Aurélien Feb 11 '13 at 07:57
  • If you manage to do it, please post your solution, I'm also interested. Thanks. – Aurélien Feb 11 '13 at 08:22