std::vector (ab) 使用自动存储

std::vector (ab)uses automatic storage

考虑以下片段:

#include <array>
int main() {
  using huge_type = std::array<char, 20*1024*1024>;
  huge_type t;
}

显然它会在大多数平台上崩溃,因为默认堆栈大小通常小于 20MB。

现在考虑以下代码:

#include <array>
#include <vector>

int main() {
  using huge_type = std::array<char, 20*1024*1024>;
  std::vector<huge_type> v(1);
}

令人惊讶的是它也崩溃了!追溯(最近的 libstdc++ 版本之一)导致 include/bits/stl_uninitialized.h 文件,我们可以在其中看到以下行:

typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
std::fill(__first, __last, _ValueType());

调整大小 vector 构造函数必须默认初始化元素,这就是它的实现方式。显然,_ValueType() 暂时使堆栈崩溃。

问题是它是否是一个符合规范的实现。如果是,那实际上意味着巨大类型的向量的使用是相当有限的,不是吗?

任何标准 API 使用的自动存储量没有限制。

他们可能都需要 12 TB 的堆栈 space。

但是,API 只需要 Cpp17DefaultInsertable,并且您的实现会在构造函数所需的基础上创建一个额外的实例。除非它在检测对象背后是可控制和可复制的,否则该实现看起来是非法的。

huge_type t;

Obviously it would crash on most of platforms ...

我对“最多”的假设提出异议。由于巨大对象的内存从未被使用,编译器可以完全忽略它并且永远不会分配内存,在这种情况下不会发生崩溃。

The question is whether it's a conforming implementation.

C++ 标准不限制堆栈的使用,甚至不承认堆栈的存在。所以,是的,它符合标准。但可以认为这是实施质量问题。

it actually means that the use of a vector of huge types is quite limited, isn't it?

libstdc++ 似乎就是这种情况。崩溃没有用 libc++ 重现(使用 clang),所以这似乎不是语言的限制,而只是在特定的实现中。

我不是语言律师也不是 C++ 标准专家,但是 cppreference.com 说:

explicit vector( size_type count, const Allocator& alloc = Allocator() );

Constructs the container with count default-inserted instances of T. No copies are made.

也许我误解了 "default-inserted," 但我希望:

std::vector<huge_type> v(1);

相当于

std::vector<huge_type> v;
v.emplace_back();

后一个版本不应该创建堆栈副本,而是直接在向量的动态内存中构造一个huge_type。

我不能权威地说您所看到的是不合规的,但这肯定不是我期望的高质量实施。