百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

C++中STL常见问题汇总,越来越熟悉STL底层原理和应用(2)

liebian365 2024-10-25 15:40 25 浏览 0 评论

STL中迭代器什么时候会失效?

  • 对于序列容器vector,deque来说,使用erase后,后边的每个元素的迭代器都会失效,后边每个元素都往前移动一位,erase返回下一个有效的迭代器

说明

当删除一个元素后,内存中的数据会发生移动以保证数据的紧凑。所以删除一个元素后,其他数据的地址发生了变化,之前获取的迭代器根据原有信息就访问不到正确的数据。

//迭代器失效
void vectorTest()
{
    vector<int> container;
    for (int i = 0; i < 10; i++)
    {
        container.push_back(i);
    }
 
    vector<int>::iterator iter;
     for (iter = container.begin(); iter != container.end(); iter++)
    {
            if (*iter > 3)
              container.erase(iter);
    }
 
     for (iter = container.begin(); iter != container.end(); iter++)
    {
            cout<<*iter<<endl;
    }
}

//代码修改,ok
	void vectorTest()
{
    vector<int> container;
    for (int i = 0; i < 10; i++)
    {
        container.push_back(i);
    }
 
    vector<int>::iterator iter;
     for (iter = container.begin(); iter != container.end();)
    {
            if (*iter > 3) {
				iter = container.erase(iter);
			}
			else {
				iter ++;
			}
    }
 
     for (iter = container.begin(); iter != container.end(); iter++)
    {
            cout<<*iter<<endl;
    }
}
  • 对于关联容器map,set来说,使用了erase后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素,不会影响下一个元素的迭代器,所以在调用erase之前,记录下一个元素的迭代器即可。

说明:

虽然删除了一个元素,整棵树也会调整,以符合红黑树规范,但是单个节点在内存中的地址没有变化,变化的是各节点之间的指向关系。删除一个结点不会对其他结点造成影响。 erase迭代器只是被删元素的迭代器失效。

#include<iostream>
#include<string>
#include<map>
using namespace std;

int main()
{
    map<string, int> mapData;
    mapData["a"] = 1;
    mapData["b"] = 2;
    mapData["c"] = 3;

    map<string, int>::iterator itMap = mapData.begin();
    while (itMap != mapData.end())
    {
        if (strcmp(itMap->first.c_str(), "a") == 0)
        {
            mapData.erase(itMap++);
        }
        else
        {
            itMap++;
        }

        /* 迭代器失效
        if (strcmp(itMap->first.c_str(), "a") == 0)
        {
            mapData.erase(itMap);
        }
        itMap++;
        */
    }
}
  • list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的迭代器

上面两种方法都可以使用。

STL中迭代器的作用,有指针为何还要迭代器?

  • 迭代器作用

(1)用于指向顺序容器和关联容器中的元素。

(2)通过迭代器可以读取它指向的元素。

(3)通过非const迭代器可以修改其指向的元素。

  • 迭代器和指针的区别

迭代器不是指针,是类模板,表现得像指针。迭代器模拟了指针的一些功能,重载了指针的一些操作符。迭代器本质是封装了原生指针,是指针概念的一种提升,提供了比指针更高级的行为,可以看成一种智能指针,他可以根据不同类型的数据结构来实现不同的++,--等操作。

  • 迭代器产生的原因

Iterator类的访问方式就是把不同集合类的访问逻辑抽象出来,使得不用暴露集合内部的结构而达到循环遍历集合的效果。

STL 迭代器是怎么删除元素的

这主要考察迭代器失效的问题,上面已经总结。

STL 中 resize 和 reserve 的区别

  • 两个概念

(1)capacity:该值在容器初始化时赋值,指的是容器能够容纳的最大的元素的个数。还不能通过下标等访问,因为此时容器中还没有创建任何对象。

(2)size:指的是此时容器中实际的元素个数。可以通过下标访问0-(size-1)范围内的对象。

  • resize和reserve区别

(1)resize既分配了空间,也创建了对象reserve表示容器预留空间,但并不是真正的创建对象,需要通过insert()或push_back()等创建对象。

(2)resize既修改capacity大小,也修改size大小;reserve只修改capacity大小,不修改size大小

(3)两者的形参个数不一样。 resize带两个参数,一个表示容器大小,一个表示初始值(默认为0);reserve只带一个参数,表示容器预留的大小。

STL 容器动态链接可能产生的问题?

  • 可能会产生什么问题

容器是一种动态分配内存空间的一个集合类型的变量。在一般的程序函数里,局部容器,参数传递容器,参数传递容器的引用,参数传递容器指针都是可以正常运行的,而在动态链接库函数内部使用容器也是没有问题的,但是给动态库函数传递容器的对象本身,则会出现内存堆栈破坏的问题。

  • 产生问题原因

容器和动态链接库相互支持不够好,动态链接库函数中使用容器时,参数中只能传递容器的引用,并且要保证容器的大小不能超出初始大小,否则导致容器自动重新分配,就会出现内存堆栈破坏问题

map 和 unordered_map 的区别?底层实现

  • map实现机理

map内部实现了一个红黑树红黑树有自动排序的功能,因此map内部所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。对于map进行的查找、删除、添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉查找树存储的(左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值)。中序遍历可将键值按照从小到大遍历出来

  • unordered_map实现机理

unordered_map内部实现了一个哈希表,通过把关键码值映射到Hash表中一个位置来访问记录,查找时间复杂度可达O(1),在海量数据处理中有着广泛应用。因此,元素的排列顺序是无序的。

push_back 和 emplace_back 的区别

要将一个临时变量push到容器的末尾,push_back()需要先构造临时对象,再将这个对象拷贝到容器的末尾,而emplace_back()则直接在容器的末尾构造对象,这样就省去了拷贝的过程。

#include<iostream>
using namespace std;
#include<string>
#include<vector>

class TestA
{
public:
	string str;
	TestA(int i)
	{
		str = to_string(i);
		cout << "构造函数的调用" << endl;
	}

	~TestA()
	{
		//cout << "析构函数的调用" << endl;
	}

	TestA(const TestA& other) :str(other.str)
	{
		cout << "拷贝函数构造" << endl;
	}

};

int main()
{
	vector< TestA> vec;
	vec.reserve(10);
	for (int i = 0; i < 10; i++)
	{
		//调用了10次构造函数和10次拷贝构造函数
		vec.push_back(i);

		//调用了10次构造函数,没有调用拷贝构造函数
		//vec.emplace_back(i);
	}
	return 0;
}

push_back()运行结果:


emplece_back()运行结果:


相关推荐

“版本末期”了?下周平衡补丁!国服最强5套牌!上分首选

明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...

VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符&quot;

首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...

东营交警实名曝光一批酒驾人员名单 88人受处罚

齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...

Qt界面——搭配QCustomPlot(qt platform)

这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...

大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写

老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...

测试谷歌VS Code AI 编程插件 Gemini Code Assist

用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...

顾爷想知道第4.5期 国服便利性到底需优化啥?

前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...

掌握Visual Studio项目配置【基础篇】

1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...

还嫌LED驱动设计套路深?那就来看看这篇文章吧

随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...

Visual Studio Community 2022(VS2022)安装图文方法

直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...

Qt添加MSVC构建套件的方法(qt添加c++11)

前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...

Qt为什么站稳c++GUI的top1(qt c)

为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...

qt开发IDE应该选择VS还是qt creator

如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...

Qt 5.14.2超详细安装教程,不会来打我

Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...

Cygwin配置与使用(四)——VI字体和颜色的配置

简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...

取消回复欢迎 发表评论: