提问人:Igor R. 提问时间:1/7/2020 最后编辑:Igor R. 更新时间:1/21/2020 访问量:3169
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()
问题是它是否符合要求。如果是,这实际上意味着使用大类型的向量是相当有限的,不是吗?
答:
任何 std API 使用的自动存储量没有限制。
它们都可能需要 12 TB 的堆栈空间。
但是,该 API 只需要 ,并且您的实现会在构造函数所需的内容上创建一个额外的实例。除非它被门禁在检测对象是微不足道的可复制和可复制的之后,否则该实现看起来是非法的。Cpp17DefaultInsertable
评论
std::allocator
std::fill
memcpy
huge_type t;
显然,它会在大多数平台上崩溃......
我对“大多数”的假设提出异议。由于从未使用过巨大对象的内存,因此编译器可以完全忽略它并且从不分配内存,在这种情况下不会崩溃。
问题是它是否符合要求。
C++ 标准不限制堆栈的使用,甚至不承认堆栈的存在。所以,是的,它符合标准。但人们可以认为这是一个执行质量问题。
这实际上意味着使用大类型的向量是相当有限的,不是吗?
libstdc++ 似乎就是这种情况。libc++(使用 clang)没有重现崩溃,因此这似乎不是语言的限制,而只是该特定实现的限制。
评论
我不是语言律师,也不是C++标准专家,但 cppreference.com 说:
explicit vector( size_type count, const Allocator& alloc = Allocator() );
使用 T 的默认插入实例计数构造容器。
也许我误解了“默认插入”,但我希望:
std::vector<huge_type> v(1);
等同于
std::vector<huge_type> v;
v.emplace_back();
后一个版本不应该创建堆栈副本,而是直接在向量的动态内存中构造一个huge_type。
我不能权威地说你所看到的是不合规的,但这肯定不是我对高质量实施的期望。
评论
std::allocator
emplace_back
vector<mutex> v(1)
vector<mutex> v; v.emplace_back();
huge_type
vector::vector(size_type, Allocator const&)
上一个:自动计算百分比并存储到变量中
评论
std::allocator