我正在尝试创建与我的文件规范的工作方式非常接近的容器。它就像一个向量,但元素的类型由哈希表定义。
如果我在编译时知道类型,我可以写下这样的东西:
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个字节。
这是一个坏主意?我应该创建耦合向量,每个项目一个?
或者这个“interleaved_vector”是解决我问题的好方法吗?
答案 0 :(得分:4)
是否存在一个存储元素数组的STL容器 在运行时指定元素大小的连续内存?
没有
您要求的内容看起来像是内存池的特定实现。也许Boost.Pool库或其他实现对您有用?如果您习惯使用原始内存和C ++特定的对象创建/销毁,那么编写自己的编写应该不会很难。
回答你的问题:
有没有做到这一点?
对我而言,这个想法看起来像一个内存池。有很多类型的内存池,因此您需要的实现完全取决于您的特定需求。
这是个坏主意吗?我应该只是创建一个向量并且每个都是新的 元件?我希望有数百万个元素。尺寸范围 foo将是20到200个字节。
如果你想限制内存碎片,这不是一个坏主意。池通常用于修复此和其他与内存组织相关的问题。
例如,在视频游戏中,这种情况非常频繁,主要是在控制台上,但如果您需要高性能或大量内存,还可以在PC上使用。
如果您正在制作原型或者您没有大量数据要分配,我不会建议您打扰。如果你这样做,那么可能首先实现隐藏在工厂后面的最简单的分配(使用向量和新)将很好,并允许您使用池替换工厂实现。这样你首先检查一切是否正常,然后进行优化。
答案 1 :(得分:1)
鉴于此代码:
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 *缓冲区,并使用简单的包装类。仍然容易出错并且非常容易混淆。这个演示没有迭代器(尽管这很简单),并且需要一个外部缓冲区至少与类一样长。
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),但希望你能看到它的目的。
答案 2 :(得分:0)
你可以写自己的课,但这是一个严重的痛苦。最好只使用vector(或boost :: ptr_vector),它不需要你的工作,并且每个程序员都可以轻松阅读。