C++ STL实现中是否存在中心分配deque或vector?

C++ STL实现中是否存在中心分配deque或vector?,c++,c++11,vector,stl,deque,C++,C++11,Vector,Stl,Deque,我在读关于deques vsvectors的文章时,遇到了its,它说使用动态数组的deque的三种可能实现之一是: 从基础数组的中心分配deque内容,以及 到达任意一端时调整基础数组的大小。这 这种方法可能需要更频繁地调整尺寸并浪费更多空间, 尤其是当图元仅插入一端时 我想知道是否有任何STL(或STL样式)实现实际使用这种中心分配策略 我这样问是因为这种策略看起来相当吸引人,因为它只涉及一个底层数组,因此消除了内存不连续性问题,这可能是与vector相比deque唯一的主要问题。如果我理解

我在读关于
deque
s vs
vector
s的文章时,遇到了its,它说使用动态数组的
deque
的三种可能实现之一是:

从基础数组的中心分配deque内容,以及 到达任意一端时调整基础数组的大小。这 这种方法可能需要更频繁地调整尺寸并浪费更多空间, 尤其是当图元仅插入一端时

我想知道是否有任何STL(或STL样式)实现实际使用这种中心分配策略

我这样问是因为这种策略看起来相当吸引人,因为它只涉及一个底层数组,因此消除了内存不连续性问题,这可能是与
vector
相比
deque
唯一的主要问题。如果我理解正确的话,这很可能是对允许O(1)
pop\u front
(摊销)的
std::vector
的替代,或者是对具有内存连续性保证的
deque
的替代。我假设这是以将
std::vector
的缓冲空间增加一倍为代价的,这对于我的用例来说不是一个主要问题

也就是说,在这样的容器中间插入/删除的时间是<>代码> STD的一半::向量平均?


更新:

正如@Lightness Races in Orbit所指出的,在当前的标准下不会使用这种实现,因为没有人能从STL的每份合同中受益,每个人都会遭受不利影响。关于缺点,我还有一个问题:

是否可以实现一个新的
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();
    }
  }
};
模板
类bi_vec{
std::唯一的ptr原始数据;
std::size\u t first=0;
std::size\u t last=0;
标准::容量=0;
字符*原始获取(标准::大小索引){
返回和原始[指数*sizeof(T)];
}
字符常量*原始获取(标准::大小索引)常量{
返回和原始[指数*sizeof(T)];
}
T&get(标准::大小索引){
return*reinterpret_cast(原始获取(索引));
}
常量和get(标准::大小索引)常量{
return*reinterpret_cast(原始获取(索引));
}
字符*raw_在()之前{
如果(第一个<1)
增长();
--第一,;
返回原始数据(第一个);
}
字符*raw_后(){
如果(上一次+1>=容量)
增长();
++最后;
返回原始获取(最后一个-1);
}
void grow(){
标准::矢量新容量=(容量+1)*2;
std::size\u t new\u first=(新容量-(last first))/2;
std::size\u t new\u last=新容量-新容量优先;
std::unique_ptr new_buff(新字符[新容量*大小(T)]);
T*b=&get(0);
T*e=&get(最后一个优先);
标准:移动(b、e、重新解释演员阵容和新的buff[新的第一个*尺寸(T)]);
标准::交换(buff,raw);
标准::交换(新容量、容量);
标准::交换(新的,第一);
标准::交换(新的,最后的);
对于(T*it=b;it!=e;++it){
它->~T();
}
}
公众:
运算符[](std::size_T index){return get(index);}
常量和运算符[](std::size_T index)常量{return get(index);}
模板
空位后置(美国&…美国){
char*a=raw_after();
新的(a)T(标准:远期(美国));
}
模板
空位阵地前方(美国和…美国){
char*a=raw_before();
新的(a)T(标准:远期(美国));
}
~bi_vec(){
对于(std::size\u t i=0;i!=last first;++i){
得到(我)~T();
}
}
};

并添加迭代器(我倾向于使用
boost
iterator助手,或原始指针来启动)和您需要的任何接口。请注意,上面的操作需要确保其保持异常安全。

一旦到达数组的末端,是否仍需要移动内容以保持连续性?也许我们可以像到达其右端时那样重新分配内存。我认为,与
vector
一样,使用非违约插入平均时,重新分配的成本摊销为O(1)。我想我们可以做
vector
技巧“两端”。谢谢。我将尝试一下。以下是我到目前为止所做的:可以作为
bi_-vec
完全实例化,尽管没有其他编译,更不用说测试了。事实上,我保持它相当简单,所以任何错误都应该很少(不要说严重性)@moingduck,非常感谢!你花了多长时间把这些都编好了。您的代码在我的计算机上编译正常,在TDM-MinGW64上使用gcc-4.8.1。然而,当我实例化像
bi_vec a大约3小时。显然,显式实例化没有我预期的那么多。它现在应该可以实例化为一个变量:还添加了miss