C++ 类似向量的容器,其实例的存储是相互连续的?
我需要一个容器类,其API尽可能接近std::vector(除了不重新分配),但其元素的存储(而不是其成员变量,如大小)可以指定为从现有缓冲区分配,这样我就可以在连续缓冲区中保留所有vector的元素。也就是说,一个向量的.end()指向缓冲区中与下一个向量的.front()相同的元素 我不知道是否可以简单地将自定义分配器与std::vector一起使用,因为我找不到关于该分配器是为整个类分配存储的信息,包括大小和指针数据成员(在这种情况下,我不能使用这种方法),还是只为它所持有的数据元素(在这种情况下,我可以使用它) 我只需要一个实例的存储分配一次,所以重新分配没有问题。我在这里发帖是想看看是否已经发布了这样一个容器,而不是从头开始用迭代器等重新实现大多数std向量接口C++ 类似向量的容器,其实例的存储是相互连续的?,c++,c++11,memory-management,vector,stl,C++,C++11,Memory Management,Vector,Stl,我需要一个容器类,其API尽可能接近std::vector(除了不重新分配),但其元素的存储(而不是其成员变量,如大小)可以指定为从现有缓冲区分配,这样我就可以在连续缓冲区中保留所有vector的元素。也就是说,一个向量的.end()指向缓冲区中与下一个向量的.front()相同的元素 我不知道是否可以简单地将自定义分配器与std::vector一起使用,因为我找不到关于该分配器是为整个类分配存储的信息,包括大小和指针数据成员(在这种情况下,我不能使用这种方法),还是只为它所持有的数据元素(在这
更新:我取消了发布的答案,因为它在VisualC++ 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));
}
调试生成的结果不正确:
在对
allocate()
的第一次调用中,分配器仅用于为元素分配存储。为此,可以使用自定义分配器
乔恩在下面的评论中纠正了我的错误
我认为可以实现一个一致的向量
,这样它就可以存储堆中除了指针以外的所有内容。堆上的内容可能是3个指针加上分配器(如果不是分配器,则未优化掉),或者是1个指针、大小和容量(以及可能优化掉的分配器)
实际上,std::vector
的每一个单独实现都以任何形式发布,包括:
- 惠普
- SGI
- libstdc++(gcc)
- libc++(llvm)
- 纯粹的器皿
- 微软
- 流氓波
- 代码战士
- STLPort
- 我肯定我忘了其他人
string
在概念上具有相同的布局,因此不能做出相同的声明。string
的C++11实现通常使用“短字符串”优化,其中分配器根本不用于“短”字符串,而是将值嵌入到string类中。23.2.1一般集装箱要求[container.requirements.General]/10:
(除非另有规定)任何swap()函数都不会使任何
引用的元素的引用、指针或迭代器
正在交换的容器
如果我正确理解你的问题,你使用的是固定大小的向量。 如果这些大小和向量的数量是编译时常量,我建议使用
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++) << ",";
}
}
struct内存{
std::数组a1;
std::数组a2;
}记忆;
int main(){
std::array&a1=memory.a1;
std::array&a2=memory.a2;
a1[0]=10;
a1[1]=11;
a2[0]=20;
a2[1]=21;
int*it=&(a1[0]);
对于(尺寸i=0;i<4;++i){
STD:CUT我把它放在GCC和Visual C++ 2012中,所以我发布了,以防其他人碰到这个问题。我必须在我的分配器类中添加以下内容:
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>();
}
模板
结构重新绑定
{
typedef typename std::conditional::type other;
}
模板
内联运算符std::分配器(void)常量
{
返回std::allocator();
}
对于Visual C++2012,在调试构建中,似乎需要条件typedef和转换运算符
这只有在默认的std::分配器是无状态的情况下才起作用,我认为标准中没有指定这一点。所以您需要一些类似于向量的接口来查看现有的缓冲区?这与Java的ByteBuffer差不多。但是,我需要它具有std::vector的大多数类型特征,因为这个容器将由当前使用std::vector并使用其迭代器等的类使用。@DisplayName:?正如您提到的ByteBuffer。这正是vector
具有分配器
模板参数的原因。请阅读分配器:@EduardoLeón,C++14将不具有std::dynarray
。未来的数组扩展将支持bably有std::experimental::dynarray
,但没有C++14(您链接到的页面上甚至有这样的说明)我正在查看该标准,以找到对该标准的引用,但我不能。我能做的最好是间接的,例如,shared\u ptr
的某些构造函数特别声明其分配器将用于分配内部状态,而vector
上的任何内容都没有这样的说明。但这足以保证吗?你能透露一些信息吗t请?“我认为可以实现一个一致性向量,这样它就可以在堆上存储除指针以外的所有内容。”如果值类型是UDT,则需要重新绑定分配器,以便在空闲存储上分配和构造大小等(23.2.1/7)“此分配器的副本用于在每个容器对象的生存期内或替换分配器之前,由这些构造函数和所有成员函数执行的任何内存分配。”)据我所知,非反弹分配器将仅用于元素。@dyp:容器不是必需的(但允许使用)要存储非回弹分配
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
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++) << ",";
}
}
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>();
}