18.vector越界访问下标,map越界访问下标?vector删除元素时会不会释放空间?
18.vector越界访问下标,map越界访问下标?vector删除元素时会不会释放空间?
1.vector越界访问下标
std::vector
是C++标准库中的一种动态数组,其大小可以根据需要进行调整。当你试图访问一个不存在的元素,即访问超出其当前大小范围的索引时,将会发生越界访问。
在C++中,如果你使用operator[]
来访问std::vector
的元素,当下标越界时,编译器不会抛出任何错误或异常,而且它通常会返回一个未定义的值,这可能导致程序行为异常或崩溃。这种情况下,错误可能很难被检测到,因为程序可能会在某些情况下正常运行,但在其他情况下出现错误。
为了避免这种情况,C++提供了std::vector::at()
成员函数,这个函数在访问超出std::vector
范围的索引时会抛出std::out_of_range
异常。这可以帮助你立即发现并处理错误。
下面是一个例子:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5 };
try
{
// 正常访问
std::cout << v.at(2) << std::endl; // 输出:3
// 越界访问
std::cout << v.at(10) << std::endl;
}
catch (const std::out_of_range& e)
{
std::cerr << "Caught an out_of_range exception: " << e.what() << std::endl;
}
return 0;
}
输出:
3
Caught an out_of_range exception: invalid vector subscript
在这个例子中,当我们试图通过v.at(10)
访问不存在的元素时,程序会抛出std::out_of_range
异常,并输出异常信息。
总的来说,为了避免越界访问,你应该始终确保你访问的索引在0到vector.size() - 1
的范围内。在需要的情况下,使用std::vector::at()
而不是operator[]
可以提供额外的越界检查。
2.map越界访问下标
在C++的std::map
中,使用operator[]
访问一个不存在的键会创建一个具有该键和默认值(通常为0或等效初始化值)的新元素。
这是一个例子:
#include <iostream>
#include <map>
int main()
{
std::map<std::string, int> m;
m["Alice"] = 20;
std::cout << m["Alice"] << std::endl; // 输出:20
// 访问一个不存在的键
std::cout << m["Bob"] << std::endl; // 输出:0
return 0;
}
输出:
20
0
在这个例子中,尝试访问m["Bob"]
会在std::map
中创建一个新的键值对"Bob": 0
。
如果你只想查找std::map
中的元素,而不想在找不到元素时创建新元素,你可以使用std::map::find()
函数。这个函数在找到键时返回一个指向该键值对的迭代器,否则返回std::map::end()
。
auto it = m.find("Bob");
if (it != m.end())
{
std::cout << it->second << std::endl;
}
else
{
std::cout << "Key not found" << std::endl;
}
总的来说,对于std::map
的访问,你需要注意operator[]
的这种特殊行为。如果你不希望在键不存在时创建新元素,你应该使用std::map::find()
。
3.vector删除元素时会不会释放空间?
在C++的std::vector
中,当你使用erase
函数删除元素时,被删除元素占用的空间会被立即释放,而且其他元素可能会进行移动以填补空出来的空间。这是因为std::vector
要保证元素在内存中的连续存储。
然而,虽然erase
函数会删除元素并减小std::vector
的大小(可以通过size
函数获取),但它不会减小std::vector
的容量(可以通过capacity
函数获取)。容量是std::vector
预分配的内存空间,它可能大于或等于std::vector
的当前大小。
如果你删除了大量元素并希望减小std::vector
的容量以节省内存,你可以使用shrink_to_fit
函数,或者使用下面的"swap trick"技巧:
std::vector<int>(v).swap(v);
这个技巧创建了一个新的临时std::vector
(其大小等于原std::vector
的大小,但容量等于或接近其大小),然后与原std::vector
进行交换,从而使原std::vector
的容量减小。
但是请注意,缩小std::vector
的容量可能需要额外的内存分配和元素复制,所以如果你知道你将再次需要这些空间,那么可能不值得缩小容量。
Vector如何释放空间?
由于vector的内存占用空间只增不减,比如你首先分配了10000个字节,然后erase掉后面9999个,留下一个有效元素,但是内存占用仍为10000个。所有内存空间是在vector析构时候才能被系统回收。empty()用来检测容器是否为空的,clear()可以清空所有元素。但是即使clear(),vector所占用的内存空间依然如故,无法保证内存的回收。
如果需要空间动态缩小,可以考虑使用deque。
如果使用vector,可以用swap()来帮助你释放多余内存或者清空全部内存。
vector(Vec).swap(Vec); //将Vec中多余内存清除;
vector().swap(Vec); //清空Vec的全部内存;
当使用vector(Vec).swap(Vec)
这样的语句时,它实际上执行了以下步骤:
-
创建临时
vector
对象:vector(Vec)
会创建一个临时的vector
对象,其中的元素是拷贝自Vec
的元素,但临时vector
并不会预留多余的内存空间。也就是说,临时vector
的容量(capacity)与实际存储的元素个数(size)相同,没有多余的内存空间。 -
swap
函数交换内容:Vec
和临时vector
的内容进行了交换,也就是它们的指针和容量等信息进行了交换。这个交换是非常高效的,因为swap
只交换了指针,而没有真正移动元素。 -
临时
vector
析构:在整个语句执行完毕后,临时vector
对象会被立即析构,因为它是在这个语句的作用域中创建的。在析构时,临时vector
会释放它所持有的内存空间。由于临时vector
的容量和实际存储的元素个数相同,所以这里释放的就是Vec
之前的多余内存。
让我们通过一个例子来说明这个过程:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> Vec;
for (int i = 1; i <= 10; ++i)
{
Vec.push_back(i); // 添加元素1-10到Vec
}
std::cout << "Vec Size: " << Vec.size() << ", Capacity: " << Vec.capacity() << std::endl; // 输出 Size: 10, Capacity: 16
// 使用 vector(Vec).swap(Vec) 释放多余内存
std::vector<int>(Vec).swap(Vec);
std::cout << "Vec Size: " << Vec.size() << ", Capacity: " << Vec.capacity() << std::endl; // 输出 Size: 10, Capacity: 10
return 0;
}
在这个例子中,一开始Vec
的容量是16(这是一个比实际存储元素个数大的值,用于提高效率)。通过vector(Vec).swap(Vec)
语句后,Vec
的容量变为10,说明多余的内存被成功释放了。
在vector().swap(Vec);
语句中,vector()
创建了一个空的临时vector
对象,然后通过swap
函数将Vec
和这个临时vector
的内容进行交换。结果Vec
变为空,同时释放了所有之前的内存。
需要注意的是,这两种方法只能释放vector
多余的内存,而不能释放vector
中元素本身可能占用的动态分配的内存。例如,如果vector
中存储的是指向动态分配对象的指针,那么这些动态分配的对象的内存需要单独释放。
实例
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
vector<int> vec (100,100); // three ints with a value of 100
vec.push_back(1);
vec.push_back(2);
cout <<"vec.size(): " << vec.size() << endl;
cout <<"vec.capacity(): " << vec.capacity() << endl;
vector<int>(vec).swap(vec); //清空vec中多余的空间,相当于vec.shrink_to_fit();
cout <<"vec.size(): " << vec.size() << endl;
cout <<"vec.capacity(): " << vec.capacity() << endl;
vector<int>().swap(vec); //清空vec的全部空间
cout <<"vec.size(): " << vec.size() << endl;
cout <<"vec.capacity(): " << vec.capacity() << endl;
return 0;
}
输出:
运行结果:
vec.size(): 102
vec.capasity(): 200
vec.size(): 102
vec.capasity(): 102
vec.size(): 0
vec.capasity(): 0