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

Bar*_*rry 14 c++ vector allocator language-lawyer c++11

作为这个问题的后续,默认的allocator(std::allocator<T>)需要construct按如下方式实现(根据[default.allocator]):

template <class U, class... Args>
void construct(U* p, Args&&... args);
Run Code Online (Sandbox Code Playgroud)

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

也就是说,始终是值初始化.结果是std::vector<POD> v(num),对于任何pod类型,将值初始化num元素 - 这比默认初始化num元素更昂贵.

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

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

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


我认为这样的改变是不可能的,因为目前std::vector<int> v(100)会给你100 0秒,但我想知道为什么会这样......因为人们可以很容易地std::vector<int> v2(100, 0)以同样的方式要求有差异之间new int[100]new int[100]{}.

Rev*_*lot 3

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

\n
\n

20.1.6 表 34

\n

a.construct(p,t)

\n

效果:
\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0::new((void*)p) T(t)

\n
\n

construct采用两个参数可以追溯到 1994 年(第 18 页)。正如您所看到的,在最初的 Stepanov 概念中,它不是分配器接口的一部分(它不应该是可配置的),而是作为新放置的包装器存在。

\n

唯一确定的方法是问 Stepanov 本人,但我认为原因如下:如果你想构造一些东西,你想用特定的值初始化它。如果您希望整数未初始化,则可以省略construct调用,因为 POD 类型不需要它。之后construct,其他相关函数被捆绑到分配器中,并且容器在它们上进行了参数化,从而为最终用户带来了一些初始化控制的损失。

\n

因此,缺乏默认初始化似乎是出于历史原因:当 C++ 标准化并且标准的更高版本不会引入重大更改时,没有人考虑过它的重要性。

\n