在STL实现中有中心分配队列或向量吗?
are there center-allocation deque or vector in STL implementations?
我正在阅读关于deque
s vs vector
s的文章,并遇到了它的维基百科条目,其中说deque
使用动态数组的三种可能实现之一是:
从底层数组的中心分配deque内容,并且当到达任意一端时,重新调整基础数组的大小。这方法可能需要更频繁地调整大小并浪费更多空间,特别是当元素只在一端插入时。
我想知道是否有任何STL(或STL风格)的实现,实际上使用这种中心分配策略?
我问这个问题是因为这个策略看起来相当吸引人,因为它只涉及一个底层数组,从而消除了内存不连续问题,这可能是deque
与vector
相比唯一的主要问题。如果我理解正确的话,这很可能是std::vector
的替代品,允许0 (1)pop_front
(平摊)或替换具有内存连续性保证的deque
。我假设这是以将std::vector
的缓冲空间增加一倍为代价的,这不是我用例的主要关注点。
另外,在这样的容器中间插入/删除是否平均花费std::vector
的一半时间?
更新:
正如@Lightness Races in Orbit所指出的那样,在当前的标准下不会使用这种实现,因为没有人可以从STL的每个合同中受益,每个人都将遭受其缺点。关于缺点,我还有一个问题:
是否有可能实现一个新的类似vector
或deque
的容器(比如bivector
),这样除了std::vector
的功能/操作符之外,
1)提供(平摊)常数时间push_front()
和pop_front()
操作,
2)保证内存的连续性,但不能保证迭代器的有效性。
我想在后台有一个数组,deque
上的许多间接/性能问题将会消失。
没有标准库(不是"STL")实现会为此烦恼,因为它有您提到的缺点,而优点不是std::deque
要求的一部分。
这些需求是精心构建的,从各种操作的算法复杂性,到迭代器无效规则。以这样一种方式实现容器是没有好处的,没有人可以依赖该实现的优点。
c++委员会能否在未来的标准中引入一个新的容器,它有不同的名字和不同的约束,供应商可以像你描述的那样实现?是的,他们可以。
你的问题是你缺少这样的容器。像这样开始:
template<typename T>
class bi_vec {
std::unique_ptr<char[]> raw;
std::size_t first = 0;
std::size_t last = 0;
std::size_t capacity = 0;
char* raw_get( std::size_t index ) {
return &raw[index*sizeof(T)];
}
char const* raw_get( std::size_t index ) const {
return &raw[index*sizeof(T)];
}
T& get( std::size_t index ) {
return *reinterpret_cast<T*>(raw_get(index));
}
T const& get( std::size_t index ) const {
return *reinterpret_cast<T const *>(raw_get(index));
}
char* raw_before() {
if (first < 1)
grow();
--first;
return raw_get(first);
}
char* raw_after() {
if (last+1 >= capacity)
grow();
++last;
return raw_get(last-1);
}
void grow() {
std::vector new_capacity = (capacity+1)*2;
std::size_t new_first = (new_capacity - (last-first)) / 2;
std::size_t new_last = new_capacity - new_first;
std::unique_ptr<char[]> new_buff( new char[new_capacity*sizeof(T)] );
T* b = &get(0);
T* e = &get(last-first);
std::move( b, e, reinterpret_cast<T*>( &new_buff[new_first*sizeof(T)] ) );
std::swap( buff, raw );
std::swap( new_capacity, capacity );
std::swap( new_first, first );
std::swap( new_last, last );
for (T* it = b; it != e; ++it) {
it->~T();
}
}
public:
T& operator[]( std::size_t index ) { return get(index); }
T const& operator[]( std::size_t index ) const { return get(index); }
template<class... Us>
void emplace_back( Us&&...us ) {
char* a = raw_after();
new (a) T( std::forward<Us>(us) );
}
template<class... Us>
void emplace_front( Us&&...us ) {
char* a = raw_before();
new (a) T( std::forward<Us>(us) );
}
~bi_vec() {
for( std::size_t i = 0; i != last-first; ++i ) {
get(i).~T();
}
}
};
和添加迭代器(我倾向于使用boost
迭代器帮助器,或原始指针来启动)以及您需要的任何接口。请注意,上面的代码需要做一些工作来确保异常安全。
- 向量成员在管理类指针C++队列时丢失
- C++ Poco - 如何创建通知队列的向量?
- 为什么我们需要在优先级队列声明中添加一个向量作为参数?
- C++:自定义数据类型向量错误的队列
- C++ 如何将unique_ptr队列添加到向量
- 为什么优先级队列是使用堆实现的,而我们可以更有效地使用向量来实现它
- 我有一个问题,创建了C 中阻塞队列的向量
- 在C++中使用队列和堆栈对 2 个向量进行加减
- 如何以相反的顺序将整个向量复制到队列中
- 如何获得向量队列的前部或顶部元素
- 使用优先级队列初始化向量
- 在队列中插入向量元素
- 使用更大值和向量声明优先级队列
- 如何构造队列向量
- 创建固定大小队列的向量(提升循环队列)
- 将向量、队列和指向函数的指针传递给函数
- 从队列中弹出向量
- 向量和队列C++
- 用户定义的"队列"类的向量
- 使用向量C++的双精度的优先级队列