我需要一个API尽可能接近std :: vector的容器类(除了没有重新分配),但是其元素是'可以指定存储(而不是其成员变量,如大小)从现有缓冲区分配,以便我可以拥有所有向量'将元素保存在连续的缓冲区中。也就是说,一个向量的.end()指向缓冲区中与下一个向量相同的元素。
我不知道我是否可以简单地使用带有std :: vector的自定义分配器,因为我无法找到有关是否为整个类分配存储的信息,包括大小和指针数据成员(在这种情况下,我不能使用这种方法),或只是它拥有的数据元素(在这种情况下我可以使用它)。
我只需要分配一次实例存储,因此重新分配没有问题。我在这里发帖,看看是否已经发布了这样的容器,而不是从头开始重新实现大多数带有迭代器的std向量接口。
更新:我取消选中已发布的答案,因为它在Visual C ++ 2012中无法在调试模式下运行。T
= float
的示例:
template<class T>
inline typename ContigAlloc<T>::pointer ContigAlloc<T>::allocate(std::size_t n)
{
std::cout << "Alloc " << n << "; type match: " << std::boolalpha << std::is_same<T, float>::value << std::endl;
return reinterpret_cast<T *>(_buff.alloc(T * sizeof(n)));
}
template<class T>
inline void ContigAlloc<T>::deallocate(T *p, std::size_t n) // TODO: noexcept when VC++2013
{
std::cout << "Deall " << n << "; type match: " << std::boolalpha << std::is_same<T, float>::value << std::endl;
_buff.dealloc(p, T * sizeof(n));
}
测试:
std::vector<float, ContigAlloc<float>> vec;
vec.push_back(1.1f);
vec.push_back(1.9f);
发布版本的结果很好:
Alloc 1; type match: true
Alloc 2; type match: true
Deall 1; type match: true
Deall 2; type match: true
调试版本的结果不正常:
Alloc 1; type match: false
Alloc 1; type match: true
Alloc 2; type match: true
Deall 1; type match: true
Deall 2; type match: true
Deall 1; type match: false
在第一次致电allocate()
时,T
= _Container_proxy
答案 0 :(得分:7)
分配器仅用于为元素分配存储空间。您可以为此目的使用自定义分配器。
我在下面的评论中由Jon纠正。
我认为可以实现符合vector
,以便它将所有内容存储在堆上,除了指针。堆上的东西可以是3个指针,加上分配器(如果没有分配器没有被优化掉),或1个指针,大小和容量(以及可能优化的远离分配器)。
在实践中,std::vector
的每一个实现都以任何形式发布,包括:
将所有支持成员放在vector类本身中,并仅使用allocator来分配数据。除此之外似乎没什么动力。
所以这是事实上的标准,而不是官方标准。根据上述历史,这是一个非常安全的。
请注意,我们无法对string
提出相同的声明,string
在概念上具有相同的布局。 vector
的C ++ 11实现通常会使用&#34;短字符串&#34;优化,其中分配器根本不用于&#34;短&#34;字符串,而是值嵌入在字符串类中。这种优化有效地禁止{{1}}通过23.2.1一般容器要求[container.requirements.general] / 10:
(除非另有说明)否则swap()函数无效 引用,指针或迭代器引用的元素 容器被交换。
答案 1 :(得分:2)
如果我正确理解您的问题,您使用的是固定大小的矢量。
如果这些大小和向量的数量是编译时常数,我建议使用std::array
。
编辑: 只是为了澄清我的意思,这里有一个例子:
struct Memory {
std::array<int, 2> a1;
std::array<int, 2> a2;
} memory;
int main() {
std::array<int, 2>& a1 = memory.a1;
std::array<int, 2>& a2 = memory.a2;
a1[0] = 10;
a1[1] = 11;
a2[0] = 20;
a2[1] = 21;
int *it=&(a1[0]);
for (size_t i = 0; i < 4; ++i){
std::cout << *(it++) << ",";
}
}
输出:10,11,20,21,
根据您的要求,您还可以将Memory
实现为单身人士。
当然,这只是我的猜测,这是否符合您当前的使用模式。
答案 2 :(得分:0)
好吧,我让它在gcc和Visual C ++ 2012中工作,所以我发帖以防其他人遇到这个问题。我必须在我的allocator类中添加以下内容:
template<class U>
struct rebind
{
typedef typename std::conditional<std::is_same<T, U>::value, ContigAlloc<U>, std::allocator<U>>::type other;
}
template<class U>
inline operator std::allocator<U>(void) const
{
return std::allocator<U>();
}
对于Visual C ++ 2012,在Debug构建中似乎需要条件typedef和转换运算符。
这只适用于默认的std :: allocator是无状态的,我不认为是在标准中指定的。