首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有一个STL容器在连续内存中存储元素数组,其中在运行时指定元素大小?

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

Stack Overflow用户
提问于 2011-08-30 23:43:51
回答 3查看 711关注 0票数 2

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

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

代码语言:javascript
复制
struct foo {
              float a,b,c;
              int d;
              byte e,f;
           };

std::vector<foo> foovector;
foovector.push_back(foo f);

编译时我没有这个结构。我只有从文件头获得的架构。所有元素都是相同大小的,对元素中的每个项都有相同的偏移量。容器在添加任何元素之前都定义了哈希表。

代码语言:javascript
复制
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;

我的想法是,我可以快速记录文件中的原始数据。迭代补偿很容易。我的问题是:

  1. 已经做了什么吗?
  2. 这是个坏主意吗?我应该只创建一个向量并更新每个元素吗?我希望有数以百万计的元素。foo的大小范围是20到200个字节。
  3. ,这是个坏主意吗?我应该创建耦合向量,每个项目一个?
  4. 还是这个"interleaved_vector“是解决我的问题的好方法?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-08-31 17:39:21

鉴于这一守则:

代码语言:javascript
复制
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*缓冲区,并使用简单的包装类。仍然容易出错而且非常令人困惑。这个演示程序没有迭代器(尽管这很简单),并且需要一个外部缓冲区来保持作用域,至少只要类这样做。

代码语言:javascript
复制
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;
    }
};

这将允许代码,例如:

代码语言:javascript
复制
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';
    }
}

这个演示代码假设所有的成员都是ints (get),但希望您能够看到它的意图。

票数 1
EN

Stack Overflow用户

发布于 2011-08-30 23:50:18

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

不是的。

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

回答你的问题:

已经做了什么吗?

在我看来,这个想法就像一个记忆池。有大量的内存池,所以您想要的实现完全取决于您的特定需求。

,这是个坏主意吗?我应该只创建一个向量并更新每个元素吗?我希望有数以百万计的元素。foo的大小范围将是20到200个字节。

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

例如,在电子游戏中这样做是非常频繁的,主要是在控制台上,但如果您需要高性能或大量内存的话,在PC上也是如此。

如果您正在制作一个原型,或者您没有大量的数据可供分配,我就不会再担心了。如果您这样做了,那么可能首先实现隐藏在工厂后面的最简单的分配(带向量和新的)将是很好的,并且允许您使用一个池来替换工厂实现。这样,您首先检查一切是否正常,然后再进行优化。

票数 4
EN

Stack Overflow用户

发布于 2011-08-31 00:08:51

你可以写你自己的课,但这会很痛苦。最好是使用向量(或boost::ptr_vector),它不需要您的任何努力,并且对所有的程序员来说都很容易阅读。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7251015

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档