[C/C++ -STL]list使用及vector和list迭代器失效问题比较

9 篇文章 4 订阅

一、List认识介绍
什么是list

template < class T, class Alloc = allocator<T> > class list;

这是文档给出的定义
所以什么是List?

List是序列容器,允许在序列中的任意位置执行固定时间的插入和擦除操作,并在两个方向上进行迭代。
它们与forward_list非常相似:主要区别在于forward_list对象是单链表,因此它们只能向前迭代,以换取更小和更高效
与其他基本标准序列容器(array、vector和deque)相比,链表在容器内任何位置插入、提取和移动元素(已获得迭代器)以及在大量使用这些元素的算法(如排序算法)中通常表现得更好
与其他序列容器相比,list和 forward_list的主要缺点是,它们无法通过位置直接访问元素;例如,要访问列表中的第六个元素,必须从已知位置(如开始或结束)迭代到该位置,这需要在这些位置之间的距离上花费线性时间。它们还消耗一些额外的内存来保持与每个元素相关联的链接信息(这可能是小型元素的大型列表的一个重要因素)。
List文档介绍
在这里插入图片描述
二、List结构介绍
在这里插入图片描述
List容器实现为双链接链表;双链接链表可以将它们包含的每个元素存储在不同的、不相关的存储位置。在内部,顺序是通过与每个元素的关联来保持的,这些元素是指向它前面的元素的链接和指向它后面的元素的链接。
在这里插入图片描述
三、List的使用
3.1 list的构造

list() 构造空的list
list (size_type n, const value_type& val = value_type()) 构造的list中包含n个值为val的元素
list (const list& x) 拷贝构造函数
list (InputIterator first, InputIterator last) 用[first, last)区间中的元素构造list

	list<int> l;
	list<int> li(7,0);
	list<int> v(li);
	list<int>v1(li.begin(), li.end());
	for (auto o : v) {
		cout << 0 << " ";
	}
	cout << endl;
	for (auto o : li) {
		cout << 0 << " ";
	}
	cout << endl;

l调用无参构造new一个空对象,
li调用有参构造new一个初始化n个var参数的有参对象,
v通过拷贝构造函数将里中的数据拷贝到自己内存中,
v1用li的[begin(), end())左闭右开的区间构初始化自己。

3.2 list的迭代器

begin +end
返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin +rend
返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的reverse_iterator,即begin位置

在这里插入图片描述

因为list的内存空间不是连续的,但是每个节点都保存了上一个节点和下一个节点的地址所以list在使用迭代器时first指向第一个节点的位置,因为保存了上一个节点和下一个节点的地址所以++和–都是取这个节点所指向的下一个或上一个节点的地址就行了

  1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
  2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

在这里插入图片描述

3.4 list capacity

empty 检测list是否为空,是返回true,否则返回false
size 返回list中有效节点的个数

在这里插入图片描述

	list<int> l;
	list<int> li(7);


	std::cout << l.empty() << endl;
	std::cout << li.empty() << endl;

	std::cout << l.size() << endl;
	std::cout << li.size() << endl;

因为l是调用无参构造new一个空对象所以empty为1,size()为1
li用7个var是初始化的有参构造所以empty为0,size()为7

3.5 list element access

front 返回list的第一个节点中值的引用
back 返回list的最后一个节点中值的引用
	list<int> l;
	list<int> li(7);


	std::cout << li.front() << endl;
	std::cout << li.back() << endl;

front就是双链表第一个节点的地址,
back就是双链表最后一个节点的地址

3.6 list modifiers

push_front 在list首元素前插入值为val的元素
pop_front 删除list中第一个元素
push_back在list尾部插入值为val的元素
pop_back 删除list中最后一个元素
insert 在list position 位置中插入值为val的元素
erase 删除list position位置的元素
swap 交换两个list中的元素
clear清空list中的有效元素

在这里插入图片描述

list<int> l(4,2);
	list<int> li(6,1);
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.push_front(5);

	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.pop_front();
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.push_back(2);
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.pop_back();
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.insert(li.begin(), 3);
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.erase(li.begin());
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	l.swap(li);
	for (auto o : l) {
		std::cout << o << " ";
	}std::cout << endl;
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.clear();
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;

初始化li为6个1,l为4个2push_front 在list首元素前插入值为val的元素 pop_front 删除list中第一个元素 push_back在list尾部插入值为val的元素 pop_back 删除list中最后一个元素insert 在list begin() 位置中插入值为val的元素 erase 删除list position位置的元素 swap 交换两个list中的元素clear清空list中的有效元素
3.7 list的迭代器失效

list<int> l(4,2);
	list<int> li(6,1);
	li.push_back(10);
	li.push_back(30);
	li.push_back(40);
	li.push_back(50);
	
	auto it = find(li.begin(), li.end(), 10);
	li.erase(it);
	cout << *it << endl;

在这里插入图片描述
在输出*it为什么会报错?
在这里插入图片描述
因为在把pos删除后这个节点会释放pos会变成野指针,所以在输出pos会报错为无效参数。
那么在insert()插入数据时会迭代器会失效吗?
答案是不会的因为在list不像vector内存空间是连续的在insert()时如果空间不够时会开辟新空间,释放老空间,因为pos指向在这里插入图片描述
老空间所以pos就会失效。而list的能存空间不是连续的在nsert()时不会开辟新空间,只会为新节点开辟新空间让他指向pos的前一个节点和pos节点,所以没有空间的释放就没有迭代器的失效

vector底层是物理连续数组。可能扩容。导致野指针问题。不扩容,挪动数据,也导致pos 意义变了。
list是一个个独立节点,在pos前边新增一个节点pos还是指向这个节点。不会变成一个,意义没变。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
这些都是 Android NDK 内部的 `Android.mk` 文件。其中,`./android-ndk-r25c/sources/android/native_app_glue/Android.mk` 是用于编译 Native Activity 示例应用程序的 `Android.mk` 文件;`./android-ndk-r25c/sources/android/support/Android.mk` 是包含一些 Android 支持库的 `Android.mk` 文件;`./android-ndk-r25c/sources/android/ndk_helper/Android.mk` 是包含一些辅助函数和类的 `Android.mk` 文件;`./android-ndk-r25c/sources/android/cpufeatures/Android.mk` 是用于编译 `cpufeatures` 库的 `Android.mk` 文件,该库提供了一些 CPU 相关的信息和功能;`./android-ndk-r25c/sources/cxx-stl/llvm-libc++abi/Android.mk` 和 `./android-ndk-r25c/sources/cxx-stl/llvm-libc++/Android.mk` 是用于编译 C++ STL 库的 `Android.mk` 文件,分别对应 libc++abi 和 libc++ 两个 STL 库;`./android-ndk-r25c/sources/third_party/googletest/Android.mk` 是用于编译 Google Test 测试框架的 `Android.mk` 文件;`./android-ndk-r25c/sources/third_party/shaderc/Android.mk` 是用于编译 Shaderc 编译的 `Android.mk` 文件,该编译可以将 GLSL 代码编译成 SPIR-V 代码;`./android-ndk-r25c/sources/third_party/shaderc/libshaderc/Android.mk` 是用于编译 Shaderc 库的 `Android.mk` 文件;`./android-ndk-r25c/sources/third_party/shaderc/libshaderc_util/Android.mk` 是用于编译 Shaderc Util 库的 `Android.mk` 文件,该库提供了一些辅助函数和类;`./android-ndk-r25c/sources/third_party/shaderc/third_party/Android.mk` 是用于编译 Shaderc 编译依赖的第三方库的 `Android.mk` 文件,包括 glslang 和 spirv-tools 两个库;`./android-ndk-r25c/sources/third_party/shaderc/third_party/glslang/Android.mk` 是用于编译 glslang 库的 `Android.mk` 文件;`./android-ndk-r25c/sources/third_party/shaderc/third_party/spirv-tools/Android.mk` 是用于编译 spirv-tools 库的 `Android.mk` 文件;`./android-ndk-r25c/sources/third_party/vulkan/src/build-android/jni/Android.mk` 是用于编译 Vulkan 库的 `Android.mk` 文件。 如果您要在 Android NDK 中编写自己的 `Android.mk` 文件,可以参考这些示例文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自首的小偷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值