Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否有STL容器在运行时指定元素大小的连续内存中存储元素数组?_C++_Stl_Iterator - Fatal编程技术网

C++ 是否有STL容器在运行时指定元素大小的连续内存中存储元素数组?

C++ 是否有STL容器在运行时指定元素大小的连续内存中存储元素数组?,c++,stl,iterator,C++,Stl,Iterator,我正在尝试创建一个容器,它看起来很接近我的文件规范的工作方式。它类似于向量,但元素的类型由哈希表定义 如果我在编译时知道类型,我可以这样写: struct foo { float a,b,c; int d; byte e,f; }; std::vector<foo> foovector; foovector.push_back(foo f); 我在编译时没有结构。我只有一个从

我正在尝试创建一个容器,它看起来很接近我的文件规范的工作方式。它类似于向量,但元素的类型由哈希表定义

如果我在编译时知道类型,我可以这样写:

struct foo {
              float a,b,c;
              int d;
              byte e,f;
           };

std::vector<foo> foovector;
foovector.push_back(foo f);
我在编译时没有结构。我只有一个从文件头获得的模式。所有图元的大小相同,且图元内的每个项目都具有相同的偏移量。容器在添加任何元素之前定义了哈希表

typedef Toffset uint; //byte offset;
typedef Ttype   uint; //enum of types

std::unordered_map<std::string, std::pair<Toffset,Ttype>> itemKey; 
itemKey["a"] = 0;
itemKey["b"] = 4;
itemKey["c"] = 8;
itemKey["d"] = 12;
itemKey["e"] = 16;
itemKey["f"] = 17;

nstd::interleaved_vector superfoo(itemKey, 10); //hashtable, pre-allocation size

nstd::interleaved_vector::iterator myIterator;

myIteratorGlobal = superfoo.begin;
myIteratorA = superfoo["a"].begin;
myIteratorB = superfoo["b"].begin;

*myIteratorB = 2.0f;
*myIteratorGlobal["d"] = 512;
我的想法是我可以快速记忆文件中的原始数据。迭代器偏移很容易。 我的问题是:

有什么东西已经做到了吗

这是个坏主意吗?我是否应该创建一个向量,然后对每个元素进行新的排序?我希望有数百万个元素。foo的大小范围为20到200字节

这是个坏主意?我应该创建耦合向量,每个项目一个

或者这个交错的_向量是解决我问题的好方法吗

是否有一个STL容器,在其中存储元素数组 在运行时指定元素大小的连续内存

没有

您所要求的看起来像是内存池的特定实现。也许Boost.Pool库或其他实现对您有用?如果您习惯于使用原始内存和特定于C++的对象创建/销毁,那么编写自己的对象应该不难

回答您的问题:

有什么东西已经做到了吗

在我看来,这个想法就像一个记忆池。内存池有很多种,所以您想要的实现完全取决于您的具体需求

这是个坏主意吗?我是否应该创建一个向量,并在每个向量上新建一个向量 要素我希望有数百万个元素。尺寸范围 foo将是20到200个字节

如果你想限制内存碎片,这不是个坏主意。池通常用于修复此问题和其他与内存组织相关的问题

例如,在视频游戏中经常会这样做,主要是在控制台上,如果您需要高性能或大量内存,也可以在PC上这样做


如果您正在制作一个原型,或者如果您没有大量的数据要分配,我不建议您费心。如果您这样做了,那么可能首先使用向量实现最简单的分配,并在工厂后面隐藏新的变量,这会很好,并允许您使用池替换工厂实现。通过这种方式,您首先检查所有内容是否正常工作,然后进行优化。

您可以编写自己的类,但这将是一件非常痛苦的事情。最好只使用vector或boost::ptr_vector,它不需要您的努力,而且每个程序员都可以轻松阅读。

给出以下代码:

typedef Toffset uint; //byte offset;
typedef Ttype   uint; //enum of types
typedef std::pair<Toffset,Ttype> member;
typedef std::unordered_map<std::string, member> memberdefs;

memberdefs itemKey; 
itemKey["a"] = member(0, 0);
itemKey["b"] = member(4, 1);
itemKey["c"] = member(8, 2);
itemKey["d"] = member(12,1);
itemKey["e"] = member(16,3);
itemKey["f"] = member(17,2);
您可以读入char*缓冲区,并使用一个简单的包装器类。仍然容易出现bug并且非常容易混淆。这个演示没有迭代器,虽然这很简单,但它需要一个外部缓冲区来保持作用域中的时间,至少和类保持的时间一样长

class interleaved_vector {
    const char* buffer;
    size_t count;
    size_t size;
    std::shared_ptr<memberdefs> members;
public: 
    class dynamic_object {
        const char* buffer;
        std::shared_ptr<memberdefs> members;
        friend interleaved_vector;
        dynamic_object(const char* buffer_, std::shared_ptr<memberdefs> members_)
        :buffer(buffer_), members(members_)
        {}
        dynamic_object& operator=(const dynamic_object& b) = delete;
    public:
        dynamic_object(const dynamic_object& b) 
        :buffer(b.buffer), members(b.members)
        {}
        template <class T>
        T get(const std::string& member) const {
            assert((*members)[member].second > 0); //no new members, requires pos sizes
            assert((*members)[member].second == sizeof(T));
            return *reinterpret_cast<T*>(buffer+(*members)[member].first); //technically undefined I think
        };
        template <>
        T* get<T*>(const std::string& member) const {
            assert((*members)[member].second > 0); //no new members, requires pos sizes
            assert((*members)[member].second == sizeof(T));
            return reinterpret_cast<T*>(buffer+(*members)[member].first); //technically undefined I think
        };
        void* operator[](const std::string& member) const {
            assert((*members)[member].second > 0); //no new members, requires pos sizes
            assert((*members)[member].second == sizeof(T));
            return reinterpret_cast<void*>(buffer+(*members)[member].first); //technically undefined I think
        };
    };
    interleaved_vector(const char* buffer_, size_t count_, size_t size_, const memberdefs& members_)
    :buffer(buffer_), count(count_), size(size_), members(members_) 
    {}
    dynamic_object get(size_t index) const { 
        assert(index<count);
        return dynamic_object(buffer + size*index, members);
    }
    dynamic_object operator[](size_t index) const { 
        assert(index<count);
        return dynamic_object(buffer + size*index, members);
    }
    size_t size() {
        return count;
    }
};
这将允许以下代码:

size_t element_size = 32;
size_t num_elements = 1000000
char * buffer = new char[num_elements*element_size];
/*read into buffer*/
interleaved_vector iv(buffer, num_elements, element_size , members);
/*interleaved_vector DOES NOT COPY BUFFER. BUFFER MUST REMAIN IN SCOPE*/
for(int i=0; i<iv.size(); ++i) {
    for(memberdefs::const_iterator j=members.begin(); j!=members.end(); ++j) {
        dynamic_object ob = iv[i];
        std::cout << "data[" << i << "]." << j.first << " = ";
        std::cout << ob.get<int>(j.first) << '\n';
    }
}

此演示代码假定所有成员都是INT get,但希望您能看到其意图。

itemKey[a]结果为一对,您正在分配一个整数?代码的其余部分并没有真正澄清任何事情。我不知道你的意图。同意,那部分不清楚,可能不正确。我正在为一个动态结构创建一个替身。有一个整数键入的类型表,用于强制转换getter/setter的数据。因此,每个类型都有一个id,每个成员都需要一个字节偏移量。这可能与指针解引用的成本相同,但数据可以保持连续。我还将数据容器描述为2D数组,但第二个维度是成员数组。e、 g.void*FooContainer::GetDataint元素,int成员;我正在研究vector类上的自定义分配器。这可能会让我减少malloc被呼叫的次数。另外,可变模板和元组可以让我描述动态结构。有什么想法吗?我打算分配几GB,这样我就可以对元素进行排序并执行其他操作。我关心的是最小化迭代器间接寻址、缓存未命中的访问开销,并让类处理接口,而不需要过多的查找来重新计算偏移量和迭代器。做指针向量。如果我做指针向量,如何避免为数组中的每个实例检索对象中的一个项的开销?我不能只是增加一个迭代器。事实上,事后看来,即使你做了一个指针向量,你也需要一个像我的getMember函数这样的函数。我认为这个答案实际上可能是最好的主意,如果它被包装在一个类中。我会编辑它来结束它。