Igo*_* R. 44 c++ libstdc++ stdvector language-lawyer automatic-storage
考虑以下片段:
#include <array>
int main() {
using huge_type = std::array<char, 20*1024*1024>;
huge_type t;
}
Run Code Online (Sandbox Code Playgroud)
显然它会在大多数平台上崩溃,因为默认堆栈大小通常小于 20MB。
现在考虑以下代码:
#include <array>
#include <vector>
int main() {
using huge_type = std::array<char, 20*1024*1024>;
std::vector<huge_type> v(1);
}
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是它也崩溃了!回溯(使用最近的 libstdc++ 版本之一)指向include/bits/stl_uninitialized.h文件,我们可以在其中看到以下几行:
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
std::fill(__first, __last, _ValueType());
Run Code Online (Sandbox Code Playgroud)
调整大小vector构造函数必须默认初始化元素,这就是它的实现方式。显然,_ValueType()临时会导致堆栈崩溃。
问题是它是否是一个符合要求的实现。如果是,那实际上意味着大类型向量的使用非常有限,不是吗?
Yak*_*ont 19
任何标准 API 使用的自动存储量没有限制。
它们都可能需要 12 TB 的堆栈空间。
但是,该 API 只需要Cpp17DefaultInsertable,并且您的实现会在构造函数所需的内容上创建一个额外的实例。除非它在检测对象之后进行门控是微不足道的可操作和可复制的,否则该实现看起来是非法的。
Run Code Online (Sandbox Code Playgroud)huge_type t;显然它会在大多数平台上崩溃......
我对“大多数”的假设提出异议。由于巨大对象的内存从来没有被使用过,编译器可以完全忽略它,从不分配内存,这样就不会发生崩溃。
问题是它是否是一个符合要求的实现。
C++ 标准不限制堆栈的使用,甚至不承认堆栈的存在。所以,是的,它符合标准。但人们可以认为这是一个实施质量问题。
它实际上意味着使用巨大类型的向量非常有限,不是吗?
libstdc++ 似乎就是这种情况。崩溃不是用 libc++(使用 clang)重现的,所以这似乎不是语言的限制,而只是在那个特定的实现中。
我不是语言律师,也不是 C++ 标准专家,但 cppreference.com 说:
explicit vector( size_type count, const Allocator& alloc = Allocator() );使用 count 个默认插入的 T 实例构造容器。不制作副本。
也许我误解了“默认插入”,但我希望:
std::vector<huge_type> v(1);
Run Code Online (Sandbox Code Playgroud)
相当于
std::vector<huge_type> v;
v.emplace_back();
Run Code Online (Sandbox Code Playgroud)
后一个版本不应该创建堆栈副本,而是直接在向量的动态内存中构造一个巨大的类型。
我不能权威地说你所看到的是不合规的,但这肯定不是我对高质量实施的期望。
| 归档时间: |
|
| 查看次数: |
3049 次 |
| 最近记录: |