为什么std::VECTOR要初始化其内容?
假设我想创建一个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
是这样设计的?我知道,斯捷潘诺夫和他的合作者非常仔细地制定了STL,几乎没有缺陷。但在我看来,从某种意义上说,它似乎与你不用的东西不付钱相冲突。这种设计的动机是什么?
有没有一个共识,那就是回想起来,不应该这样做?(例如,无符号size_t
用于size()
的情况,人们似乎同意它应该与difference_type
属于同一类型,因为我们经常比较指数和size()
)。
详细信息
性能
关于生成的代码的一些比较。编译器会优化0-init away吗?使用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或铿锵-O3
不同,与std::fill
比较长,一般表示指令已实际下达。
因此,除非我误解了,否则确实重要。
历史
原始STL的代码可以找到here。在版本2中,向量的内容已经默认初始化。委员会似乎验证了已经存在的内容。
与std::array
评论中的一些人认为,您绝对必须初始化向量的内容。但这确实是一个设计决策的证据是,std::array
相反,不是默认初始化它的内存。因此,按原样实现vector
和array
可能更容易,或者更有意义,但对于两者来说,反过来也是可能的。
解决方案
实际上,您可以避免这种情况。引用cppreference中的内容,例如resize
:
附加默认插入的其他元素
和讨论C++ named requirements: DefaultInsertable的页面说(重点是我的):
如果不希望进行值初始化,例如如果对象是非类类型且不需要清零,则可以通过提供自定义分配器::Construct
来避免这种情况
最后,一个link back to Stack Overflow(!)显示如何完成此操作(我尚未详细分析此代码)。
当然,对于非POD类型,您确实希望默认构造新元素。否则,访问它们(甚至尝试分配给它们)将导致UB。
相关文章