【问题标题】:Can I use an std::vector as a facade for a pre-allocated (raw) array?我可以使用 std::vector 作为预分配(原始)数组的外观吗?
【发布时间】:2013-01-26 06:18:07
【问题描述】:

我从 DirectX 获取了存储我的顶点信息的内存位置。处理顶点信息的一种极其方便的方法是使用包含顶点信息的结构的 std::vector。

鉴于我有一个指向大缓冲区的指针,我可以使用 std::vector 来管理缓冲区中的元素吗?构造一个 std::vector 经常会导致它有自己的地址,这不是我真正想要的。我可以以某种方式使用 operator Placement new 吗?

【问题讨论】:

  • 你想从std::vector使用什么操作?
  • 只需 .push_back() 添加顶点,删除它们的能力会很棒但不是必需的,并且 .size() 可以知道容器中的顶点数。
  • push_back 将导致向量在不同的内存位置分配一个新的内存块,以便为其他元素留出空间。
  • 看起来最简单的方法可能只是编写我自己的结构然后,std::vector 似乎很难为此目的环绕。
  • @kvanberendonck 您可以将std::vector 与自定义分配器一起使用,该分配器不断返回相同的缓冲区空间,但如果向量请求的空间比缓冲区的空间多,并且没有简单的要求向量精确分配缓冲区大小的方法。

标签: c++ vector memory-address facade


【解决方案1】:

std::vector 的元素在堆上动态分配(newstd::vector 本身分配),它们在内存中始终是连续的。因此,如果您的结构是 vertex,则使用 std::vector<vertex> 不是您想要的,因为向量的元素不会位于您的大缓冲区中。

您可以使用std::vector<vertex*>,例如:

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));
}

【讨论】:

  • 我想我可能以错误的方式理解了这个问题。如果是这种情况,请告诉我,我将删除我的答案。
  • 我实际上想使用向量来管理内存,就好像它是一个具有添加/删除能力的数组一样。因此,如果 DX 给出的缓冲区是一个长且连续的缓冲区,我希望将向量“添加”到 VBO 中,我可以使用 push_back 然后将 vector.size() 作为要绘制到 DX 的向量的数量传递。欢迎其他可能的结构/选项/框架建议!
  • 宁愿不要一直从 .data() memcpy 到实际缓冲区中,因为这意味着每次添加新向量时都会进行大量复制。我希望有一种很酷的方法可以直接在缓冲区中管理它们。
  • 好的,我现在明白了。您可以通过“告诉”他如何/在哪里分配来防止 std::vector 在堆上分配,即给他一个"Allocator"。我承认,我从未尝试过,但根据描述,如果分配器的实现返回指向缓冲区的指针而不是调用“new”,那么您似乎可以获得想要的结果。
  • 啊!这就是我要找的,谢谢!我试试看。
【解决方案2】:

是的,你可以。使用custom allocator。在这个分配器中你的 DirectX 内存的返回地址。

这是基于Compelling examples of custom C++ STL allocators? 的回答的完整示例。此解决方案在分配器中使用放置 new。

#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;

}

【讨论】:

  • 你好,我把它复制到一个测试项目中调试它,看看它是如何工作的。我使用 malloc 制作了一个简单的常量大小的缓冲区来模拟 vbo 缓冲区(并将 DIRECT_X_MEMORY_PTR 设置为指向它的 void*)并将大小适当地设置为我分配的大小(并将 DIRECT_X_MEMORY_SIZE_IN_BYTES 设置为此作为 size_t)。在使用 msvc 2012 编译时,我得到error C2664: 'placement_memory_allocator&lt;T&gt;::placement_memory_allocator(void *) throw()' : cannot convert parameter 1 from 'std::_Wrap_alloc&lt;_Alloc&gt;' to 'void *'。有任何想法吗? [此处代码:pastie.org/6121725]
  • 在 Visual Studio 2012 中有所改变。微软改变了一些与分配器相关的头文件。请参阅此以获取一些信息bit.ly/UacbcT
猜你喜欢
  • 2014-04-18
  • 2023-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-19
  • 2013-05-31
  • 1970-01-01
相关资源
最近更新 更多