我有这个载体:
list.push_back("one");
list.push_back("two");
list.push_back("three");
我使用list.erase(list.begin() + 1)
删除“两个”并且它有效。但是当我尝试再次输出列表时:
cout<<list[0]<<endl;
cout<<list[1]<<endl;
cout<<list[2]<<endl;
产生
one
three
three
我尝试使用list.erase(list.begin()+ 2)来定位最后一个要删除的元素,但是仍然存在重复的三个元素。我想象索引2应该被移位,列表[2]应该没有输出任何东西。 list [3]没有输出任何东西,应该如此。
我正在尝试删除“两个”并仅将列表输出:
one
three
答案 0 :(得分:3)
使用cout<<list[2]<<endl;
时,你认为你还有三个元素。但事实上,您正在访问不再使用的内存部分中的剩余数据。
您应该使用list.size ()
来获取元素的数量。所以,像:
for ( size_t i = 0; i < list.size (); i++ )
{
cout<<list[i]<<endl;
}
答案 1 :(得分:0)
但是你删除了元素,因此容器的大小减少了一个,即从3减少到2个。
因此,擦除后,你不应该这样做:
cout<<list[0]<<endl;
cout<<list[1]<<endl;
cout<<list[2]<<endl; // Undefined Behaviour!!
但是这个:
cout<<list[0]<<endl;
cout<<list[1]<<endl;
答案 2 :(得分:0)
在你的情况下,&#34;三&#34;只是复制到索引1,这是预期的。你现在是vector.size()== 2。
这是因为vector会进行预分配,这有助于提高性能。
答案 3 :(得分:0)
为了防止每次更改都需要调整大小,矢量会抓住一块比你需要的更大的内存块,并保持它直到被迫变大或指示变小。
粗暴地简化,将其视为
string * array = new string[100];
int capacity = 100
int size = 0;
在这种情况下,您可以通过该100个元素数组编写所有内容而不会导致程序崩溃,因为它是良好且有效的内存,但只有size
下的值已经初始化且有意义。当您阅读上述size
时,会发生什么是未定义的。因为读取界限是一个坏主意并且防止它具有不应该通过正确使用支付的性能成本,所以C ++标准并没有浪费任何时间来定义这样做的惩罚。一些调试或安全关键版本将测试并抛出异常或使用canary value标记未使用的部分以帮助检测故障,但大多数实现都旨在实现最大速度并且不执行任何操作。
现在你推送&#34;一个&#34;,&#34;两个&#34;和&#34;三个&#34;。该数组仍为100个元素,capacity
仍为100,但size
现为3。
你擦除array[1]
并且1到1之后的每个元素都会被复制到一个元素(注意这里潜在的巨大性能成本。如果要添加和删除,vector
不是正确的数据结构选择来自随机位置的项目)和size
将减少一个,结果是&#34;一个&#34;,&#34;三个&#34;和&#34;三个&#34;。该数组仍为100个元素,capacity
仍为100,但size
现为2。
假设您添加另外99个字符串。每次添加字符串时都会推送size
,当size
超过capacity
时,将生成一个新数组,旧数组将被复制到新数组,旧数组将被复制释放。有点像:
capacity *= 1.5;
string * temp = new string[capacity];
for (int index = 0; index < size; index ++)
{
temp[index] = array[index];
}
delete array;
array = temp;
数组现在是150个元素,capacity
现在是150,size
现在是101。
结果:
在向量的末尾通常会有一点绒毛,这样可以在没有程序崩溃的情况下读取越界,但不要将其与程序工作混淆。