【发布时间】:2021-10-26 00:33:02
【问题描述】:
假设我想创建一个vector 并在其上调用iota:
std::vector<int> v(1000);
std::iota(begin(v),end(v),0);
向量实际上在构造函数中初始化为 0。问题与以下内容相同:
std::vector<int> v;
v.resize(1000);
我可以使用reserve,但我无法拨打iota。而且我没有看到不进行零初始化的优雅方法(也许使用自定义分配器......?)。
为什么vector 是这样设计的?我知道 Stepanov 和合作者非常仔细地制作了 STL,并且几乎没有缺陷。但对我来说,它似乎与“你不为你不使用的东西付费”相冲突。这种设计的动机是什么?
是否有共识认为不应该那样做? (例如,用于size() 的无符号size_t 就是这种情况,人们似乎同意它应该与difference_type 是同一类型,因为我们经常比较索引和size())。
更多信息
性能
关于生成的代码的一些比较。编译器会优化 0-init 吗?使用vector 时很难查看汇编程序,因为它做了很多事情,所以我尝试了这段代码:
int main() {
int* v = new int[1000]; // clearer for reading assembly
fill(v,v+1000,0);
iota(v,v+1000,0);
return v[999]; // do not optimize away!
}
Result here。然后with std::fill removed
够简单了吧?嗯,汇编不和gcc或者clang-O3一样,和std::fill比较长,一般说明是真的发出指令了。
所以除非我误解了,否则它确实很重要。
历史
原始STL的代码可以在here找到。在版本 2 中,向量的内容已经被默认初始化。委员会似乎验证了已经存在的内容。
与std::array的比较
评论中有些人认为你绝对必须初始化向量的内容。但证明这确实是一个设计决定的证据是 std::array 相反,不默认初始化其内存。所以也许更容易或更有意义地实现vector 和array,但对于两者来说,反过来也是可能的。
【问题讨论】:
-
我删除了
stl标记,因为它看起来像您使用的是 C++ 标准库。请参阅 What's the difference between “STL” and “C++ Standard Library”? 和stl标记说明。 -
谢谢,但我再说一遍,因为 AFAIK 的设计选择是在标准化之前由 STL 做出的,所以我认为拥有历史视角也是有意义的
-
这不是我的问题。我问的是为什么,而不是如何。其他问题没有说明为什么要这样做。是否可以重新开放?
-
希望有一天我们会看到 Stroustrup(可能还有其他一些人)的The Continuing Evolution of C++,它解释了这些决定背后的理性,但它可能源于只是
malloced 的内存块中的基本类型或 POD 类型是否真的是真实的,而不是“总是有效”的 UB。 -
我认为缺少的是
std::iota_n,因为这样您就可以传递一个指向您保留的向量的std::back_inserter