为什么std::VECTOR要初始化其内容?

2022-08-23 00:00:00 c++ stdvector stl std

假设我想创建一个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相反,不是默认初始化它的内存。因此,按原样实现vectorarray可能更容易,或者更有意义,但对于两者来说,反过来也是可能的。


解决方案

实际上,您可以避免这种情况。引用cppreference中的内容,例如resize

附加默认插入的其他元素

和讨论C++ named requirements: DefaultInsertable的页面说(重点是我的):

如果不希望进行值初始化,例如如果对象是非类类型且不需要清零,则可以通过提供自定义分配器::Construct

来避免这种情况

最后,一个link back to Stack Overflow(!)显示如何完成此操作(我尚未详细分析此代码)。

当然,对于非POD类型,您确实希望默认构造新元素。否则,访问它们(甚至尝试分配给它们)将导致UB。

相关文章