我从TopCoder STL教程和其他一些标准教程中读到,如果我resize()
向量的值低于原始值,那么最后的差异就是'元素数量将被删除。但是,
#include <iostream>
#include<vector>
using namespace std;
int main() {
vector<int> v(20);
for(int i = 0; i < 20; i++) {
v[i] = i;
}
v.resize(10);
for(int i=0;i<20;i++)
cout<<v[i]<<" ";
return 0;
}
返回我初始化为V [20]的相同元素。从V [10]到V [19]的元素应该初始化为零或垃圾值对吗?或者,如果我理解错了,有人会抛出一些光吗?
答案 0 :(得分:3)
resize()
将调整向量的大小并使最后一个元素无效,但不是你想象的那样。您可以通过检查向量中有多少元素来清楚地看到它有10个。但是,不意味着分配的内存将被丢弃或者删除的元素在某些元素中无效感觉,尤其是整数。
如果选择,向量可以重新分配内存。然后最后的元素将无法访问。
基本上,您通过访问超出其限制的向量来调用未定义的行为。任何事情都可能发生。在这种情况下,实现选择不重新分配内存(这很聪明,因为差异很小),因此您可以指向超出范围的元素。
如果元素是对象,它们将被删除,并且通过取消引用已删除的对象,您将有更多未定义的行为。
答案 1 :(得分:2)
这是技术上未定义的行为,正如其他人所指出的那样。
发生的事情是将矢量调整到较小的大小并不能保证内存将被释放并在较小的块中重新分配(所谓的“缩小到适合”操作)。这是出于性能原因。
因此,如果您尝试访问从向量中删除的元素,但是这些对象 被销毁,并且如果您删除了具有非平凡的对象,则可能不会获得访问冲突析构函数而不是整数,每个被擦除的对象都会执行析构函数。
你没有看到无效值的原因是 - 再次 - 性能:那些int
对象已经被破坏,所以它们不应该被访问。为什么要浪费时间来重置他们用一些默认(甚至垃圾)内容占用的内存区域?
答案 2 :(得分:0)
在resize
上调用std::vector
会更改向量的大小,默认插入(或复制插入)或删除其他或多余的元素。 [reference]。
在您的情况下,删除多余的元素是重要的。
这对你的例子意味着什么?
这意味着int
对象被正式销毁,但析构函数什么都不做。存储在内存中的位模式和vector
的保留大小不会更改(resize
没有指定,尽管它并没有严格禁止实现执行此操作),因此访问已删除的元素似乎&#34;工作&#34;,没有出现分段错误或类似错误,并且值似乎仍然存在。
已被删除的整数 - 无论如何 - 仍然有效,除非它最终被覆盖,因为它只是存储单元中的一个位模式。然而,就语言来说,它还远没有明确定义(这样做也不明智)。
这个&#34;工作的事实&#34;是纯粹的巧合,没有什么可以依靠的。对于许多非平凡类型,删除对象将使其无效。此外,访问向量的元素超出范围,或在其生命周期结束后访问对象是严格未定义的行为。这又意味着不多也不少,虽然它可以工作&#34;,它只能在你的情况下巧合(你可能确实触发了调试版本中的范围检查,以及一个检测你的优化编译器)调用UB可能会以非显而易见的方式优化您的程序。)
答案 3 :(得分:0)
内存未重新初始化,因此如果内存未重新分配,您可以使用随机迭代器访问它,但如果您执行了yourVector.size(),则返回的值应该不同
答案 4 :(得分:0)
查看resize()的VC12实现:
if (_Newsize < size())
_Pop_back_n(size() - _Newsize);
else if (size() < _Newsize)
{ // pad as needed
...
}
有2个分支,如果调整大小小于当前大小,则为1,如果大于,则为1。要将矢量调整为小于当前值,请使用_Pop_back_n()
,其定义为:
pointer _Ptr = this->_Mylast - _Count;
_Destroy(_Ptr, this->_Mylast);
this->_Mylast = _Ptr;
因此,这只是将指针向下移动要删除的元素数量,并从向量中释放多余的内存。它不会清除已释放的内存,因此在覆盖之前值仍将保持不变。