allocator construct()默认初始化而不是值初始化吗?

时间:2016-03-09 21:26:55

标签: c++ c++11 vector language-lawyer allocator

作为this question的后续,默认分配器(std::allocator<T>)需要按如下方式实现construct(根据[default.allocator]):

template <class U, class... Args>
void construct(U* p, Args&&... args);
     

效果::new((void *)p) U(std::forward<Args>(args)...)

也就是说,始终是值初始化。结果是,对于任何广告连播类型,std::vector<POD> v(num)都会对num元素进行值初始化 - 这比默认初始化num元素更昂贵。

为什么 std::allocator没有提供默认初始化的额外重载?就是这样的(借用Casey):

template <class U>
void construct(U* p) noexcept(std::is_nothrow_default_constructible<U>::value)
{
    ::new(static_cast<void*>(p)) U;
}

是否有理由在呼叫案例中更喜欢值初始化?对我来说这似乎令人惊讶,这打破了通常的C ++规则,我们只支付我们想要使用的内容。

我认为这样的改变是不可能的,因为目前std::vector<int> v(100)会给你100 0 s,但我想知道为什么会这样。 ......考虑到std::vector<int> v2(100, 0)new int[100]之间存在差异的方式可以很容易地需要new int[100]{}

1 个答案:

答案 0 :(得分:2)

在C ++ 03中,分配器construct成员接受了两个参数:指针和值,用于执行复制初始化:

  

20.1.6表34

     

a.construct(p,t)

     

效果:
  ::new((void*)p) T(t)

采用两个参数的

construct可以是traced back to 1994(第18页)。正如你所看到的,在原始的Stepanov概念中,它不是分配器接口的一部分(它不应该是可配置的),而是作为新的放置包装。

只有这样才能确定地问Stepanov本人,但我认为原因如下:如果你想构建一些东西,你想用特定的值初始化它。如果你想要你的整数未被初始化,你可以省略construct调用,因为POD类型不需要它。后来construct和其他相关函数被捆绑到分配器中,容器被参数化,导致最终用户初始化失去控制权。

因此,缺乏默认初始化似乎是出于历史原因:没有人知道C ++标准化时的重要性以及标准的后续版本不会引入重大变化。