详解C++STL容器系列(一)—— vector的详细用法和底层原理

2023-05-16

目录

  • 一、介绍
  • 二、vector的创建和方法
    • 创建vector
    • 方法
  • 三、vector的具体用法
    • 3.1 遍历vector
      • 3.1.1 迭代器访问
      • 3.1.2 下标访问
      • 3.1.3 范围for循环
    • 3.2 vector 容量和大小
    • 3.3 vector 常用算法
      • 3.3.1 push_back、pop_back 和 emplace_back
      • 3.3.2 insert 和 emplace
      • 3.3.3 erase
      • 3.3.4 assign
      • 3.3.5 swap 和 clear
    • 3.4 vector二维操作
      • 定义
      • 访问
      • resize操作
  • 四、vector扩容原理
    • push_back
  • 总结

本文将详细介绍STL容器之vector的用法,并对相关底层原理说明。

一、介绍

  • vector是STL容器中的一种常用的容器,和数组类似,由于其大小(size)可变,常用于数组大小不可知的情况下来替代数组。
  • vector是为了实现动态数组而产生的容器,然而向量这个名字是STL编写者取名没区好,因为在数学上的向量在几何中是矢量,两者名字相同而意义大相径庭。
  • vector也是一种顺序容器,在内存中连续排列,因此可以通过下标快速访问,时间复杂度为O(1)。然而,连续排列也意味着大小固定,数据超过vector的预定值时vector将自动扩容。

二、vector的创建和方法

首先,使用vector时需包含头文件:

#include <vector>

创建vector

vector本质是类模板,可以存储任何类型的数据。数组在声明前需要加上数据类型,而vector则通过模板参量设定类型。

比如,声明一个int型的vector数组。

vector<int> arr1;								//一个空数组
vector<int> arr2 {1, 2, 3, 4, 5};				//包含1、2、3、4、5五个变量
vector<int> arr3(4);							//开辟4个空间,值默认为0
vector<int> arr4(5, 3);							//5个值为3的数组
vector<int> arr5(arr4);							//将arr4的所有值复制进去,和arr4一样
vector<int> arr6(arr4.begin(), arr4.end());		//将arr4的值从头开始到尾复制
vector<int> arr7(arr4.rbegin(), arr4.rend());	//将arr4的值从尾到头复制

方法

iterators(迭代器)

名字描述
begin返回指向容器中第一个元素的迭代器。
end返回指向容器最后一个元素所在位置后一个位置的迭代器
rbegin返回容器逆序的第一个元素的迭代器
rend返回容器逆序的最后一个元素的前一个位置的迭代器
cbegin和begin()功能相同,在其基础上增加了 const 属性,不能用于修改元素。
cend和end()功能相同,在其基础上增加了 const 属性,不能用于修改元素。
crbegin和rbegin()功能相同,在其基础上增加了 const 属性,不能用于修改元素。
crend和rend()功能相同,在其基础上增加了 const 属性,不能用于修改元素。

Capacity(容量)

名字描述
size返回实际元素的个数
capacity返回总共可以容纳的元素个数
max_size返回元素个数的最大值。这个值非常大,一般是2^32-1
empty判断vector是否为空,为空返回true否则false
resize改变实际元素的个数,对应于size
reserve增加容器的容量,控制vector的预留空间
shrink_to_fit减少capacity到size的大小,即减小到size的大小

Element access(元素访问)

名字描述
operator[]vector可以和数组一样用[]访问元素
atvector.at(i)等同于vector[i],访问数组下表的元素
front返回第一个元素
back返回最后一个元素
data返回指向容器中第一个元素的指针

Modifiers(修改器)

名字描述
push_back在容器的尾部插入元素
pop_back删除最后一个元素
insert插入元素
erase删除元素
clear清除容器内容,size=0,存储空间不变
swap交换两个元素的所有内容
assign用新元素替换原有内容。
emplace插入元素,和insert实现原理不同,速度更快
emplace_back在容器的尾部插入元素,和push_back不同

三、vector的具体用法

下面将讲解vector的具体用法

3.1 遍历vector

3.1.1 迭代器访问

  • 通过迭代器访问从begin()到end(),需要定义iterator,当然可以用auto替代。
  • begin()表示第一个元素,而end()不是最后一个元素,end()是最后一个元素的前一个位置。
//迭代器:vector<int>::iterator
for (vector<int>::iterator it = arr.begin(); it != arr.end(); it++)
{
    cout << *it << endl;
}
//迭代器:vector<int>::reverse_iterator
for (vector<int>::reverse_iterator it = arr.rbegin(); it != arr.rend(); it++)
{
    cout << *it << endl;
}

3.1.2 下标访问

和数组类似,从下标0开始遍历,而不到size的大小。

for (int i = 0; i < arr.size(); i++)
{
	cout << arr[i] << endl;
}

3.1.3 范围for循环

C++11的特性,范围for,遍历元素十分方便。

for (auto num : arr)
{
	cout << num << endl;
}

3.2 vector 容量和大小

  • 顾名思义,size表示当前有多少个元素,capacity是可容纳的大小。因为vector是顺序存储的,那么和数组一样,有一个初始容量,在vector里就是capacity。capacity必然大于等于size,每次扩容时会改变,具体大小和vector底层实现机制有关。

  • max_size是可存储的最大容量,和实际的编译器、系统有关,使用的比较少。

  • empty很好理解,判断vector是否为空,其实就是判断size是否等于0。定义vector时设定了大小、resize修改大小等操作,vector都不为空;clear后,size=0,那么empty判断就为空。

  • resize改变size的大小,而reserve改变capacity的大小,shrink_to_fit减小capacity到size

    vector<int> arr;
    arr.resize(4);
    arr.reserve(6);
    cout << arr.size() << " " << arr.capacity() << endl;
    cout << "##########################" << endl;
    arr.shrink_to_fit();
    cout << arr.size() << " " << arr.capacity() << endl;
    

3.3 vector 常用算法

3.3.1 push_back、pop_back 和 emplace_back

  • push_back和pop_back用法简单
vector<int> arr;
for (int i = 0; i < 5; i++)
{
    arr.push_back(i);
}
for (int i = 0; i < 5; i++)
{
    arr.pop_back();
}
  • emplace_back的效果和push_back一样,都是尾部插入元素
arr.emplace(10);

两者的差别在于底层实现的机制不同push_back将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。所以emplace_back的速度更快。

3.3.2 insert 和 emplace

insert有三种用法:

  • 在指定位置插入值为val的元素。

    //在arr的头部插入值为10的元素
    vector<int> arr;
    arr.insert(arr.begin(), 10);
    
  • 在指定位置插入n个值为val的元素

    //从arr的头部开始,连续插入3个值为10的元素
    vector<int> arr;
    arr.insert(arr.begin(), 3, 10);
    
  • 在指定位置插入区间[start, end]的所有元素

    //从arr的头部开始,连续插入arrs区间[begin, end]的所有元素
    vector<int> arr;
    vector<int> arrs = { 1, 2, 3, 4, 5 };
    arr.insert(arr.begin(), arrs.begin(), arrs.end());
    

emplace和insert同为插入元素,不过emplace只能插入一个元素:

//在arr的头部插入值为10的元素
vector<int> arr;
arr.emplace(arr.begin(), 10);

insert和emplace的区别和上面类似,就是一个是拷贝和复制的过程,而另一个则是直接创建一个新元素。

3.3.3 erase

erase通过迭代器删除某个或某个范围的元素,并返回下一个元素的迭代器

vector<int> arr{1, 2, 3, 4, 5};
//删除arr开头往后偏移两个位置的元素,即arr的第三个元素,3
arr.erase(arr.begin() + 2);
//删除arr.begin()到arr.begin()+2之间的元素,删除两个;即删除arr.begin()而不到arr.begin()+2的元素
arr.erase(arr.begin(), arr.begin() + 2);

3.3.4 assign

assign修改vector,和insert操作类似,不过insert是从尾部插入,而assign则将整个vector改变。

  • 将整个vector修改为n个值为val的容器

    //将arr修改为3个值为5的vector。
    vector<int> arr = {5, 4, 3, 2, 1};
    arr.assign(3, 10);
    
  • 将整个vector修改为某个容器[start, end]范围内的元素

    //将arr修改为范围[arrs.begin, arrs.end]内的元素
    vector<int> arr = {5, 4, 3, 2, 1};
    vector<int> arrs = { 1, 2, 3, 4, 5 };
    arr.assign(arrs.begin(), arrs.end());
    
  • 用数组的值进行范围修改

    //将arr替换为数组arrs
    vector<int> arr = {5, 4, 3, 2, 1};
    int arrs[5] = { 1, 2, 3, 4, 5 };
    arr.assign(arrs, arrs + 5);
    

3.3.5 swap 和 clear

swap将两个vector进行交换。

vector<int> arr = {5, 4, 3, 2, 1};
vector<int> arrs = { 1, 2, 3, 4, 5 };
arr.swap(arrs);

clear清空整个vector,size变为0,但空间仍然存在。

arr.clear();

3.4 vector二维操作

实际上,二维vector其实就是嵌套定义vector,那么对其进行操作我们可以从嵌套的vector得到单层的vector,就可以调用其方法了。

定义

vector<vector<int>> arr;						//定义一个空的二维vector
vector<vector<int>> arr(5, vector<int>(3, 1));	//定义一个5行3列值全为1的二维vector

访问

和二维数组一样通过 [] [] 访问即可。

for (int i = 0; i < arr.size(); i++)
{
	for (int j = 0; j < arr[0].size(); j++)//注意如果arr为空不可直接arr[0]
	{
		cout << arr[i][j] << endl;
	}
}

或者用范围for:

for (auto nums : arr)
{
    for (auto num : nums)
    {
    	cout << num << endl;
    }
}

resize操作

vector<vector<int>> arr;
arr.resize(5);
for (auto num : arr)
{
    num.resize(3);
}

四、vector扩容原理

前面我们提到,vector作为容器有着动态数组的功能,当加入的数据大于vector容量(capacity)时会自动扩容,系统会自动申请一片更大的空间,把原来的数据拷贝过去,释放原来的内存空间。

看以下一段代码:

vector<int> arr;
for (int i = 0; i < 20; i++)
{
    arr.push_back(i);
    cout << arr.size() << " " << arr.capacity() << endl;
}

在这里插入图片描述

在VS中运行以上代码测试扩容,发现:

  • 初始时capacity和size都是零;
  • 开始capacity和size大小一致,在size=5时,capacity从4 -> 6,即发生了扩容:4 * 1.5 = 6,以1.5倍开始扩容。同样,在9、13、19时均是以1.5倍的方式扩容,向下取整。
  • 其实,在capacity等于size时,下一次插入操作时vector就以1.5倍开始扩容。开始时,0 * 1.5 = 1(需要), 1 * 1.5 = 2(此时需要),2 * 1.5 = 3, 3 * 1.5 = 4,4 * 1.5 = 6,6 * 1.5 = 9 。。。

可以看到,理论上每次都是1.5扩容,但是遇到一些特殊情况如:0、1或者一次性插入多个元素时,也许1.5扩容就无法满足了。其实很简单,按照我们自己的思路,这无非是程序健壮性的体现,加一句判断语句即可。

看如下VS中vector扩容的源码:

size_type _Calculate_growth(const size_type _Newsize) const {
    
    const size_type _Oldcapacity = capacity();
    const auto _Max              = max_size();

    //扩容后将超出max_size,返回max_size
    if (_Oldcapacity > _Max - _Oldcapacity / 2) {
        return _Max; 
    }
	//采取1.5倍扩容
    const size_type _Geometric = _Oldcapacity + _Oldcapacity / 2;
	//扩容后仍然小于新加入元素后的大小,以新加入元素后的大小为准
    if (_Geometric < _Newsize) {
        return _Newsize; 
    }

    return _Geometric;
}

由此可见,确实是以1.5倍扩容,并且还有需要判断:是否超过max_size,以及是否小于newsize。

而其实,扩容时在插入时元素需要进行判断的,所以在vector的方法如:push_back、insert中都有用到扩容。

push_back

  1. 首先,在VS中,push_back有两个重载函数。_Ty就是vector模板的类型,如vector< int >中的int。发现push_back其实是调用了emplace_back成员函数。

    void push_back(const _Ty& _Val) { 
    	emplace_back(_Val);
    }
    
    void push_back(_Ty&& _Val) { 
    	emplace_back(_STD move(_Val));
    }
    
  2. 接着,进入emplace_back函数。判断capacity和size是否相等,如果相等就进入_Emplace_reallocate函数。

    tips:对于size和capacity,代码里通过这三个指针实现内存管理。
    在这里插入图片描述

    template <class... _Valty>
        decltype(auto) emplace_back(_Valty&&... _Val) {
            
            auto& _My_data   = _Mypair._Myval2;
            pointer& _Mylast = _My_data._Mylast;
            if (_Mylast != _My_data._Myend) {
                return _Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...);
            }
    		
            _Ty& _Result = *_Emplace_reallocate(_Mylast, _STD forward<_Valty>(_Val)...);
    #if _HAS_CXX17
            return _Result;
    #else // ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv
            (void) _Result;
    #endif // _HAS_CXX17
        }
    
  3. 我们进入_Emplace_reallocate函数。在这函数里,首先会检查size是否等于max_size,超过最大值时触发错误。接着,就看到了之前提到的扩容函数 _Calculate_growth,修改capacity的值。

    template <class... _Valty>
    pointer _Emplace_reallocate(const pointer _Whereptr, _Valty&&... _Val) {
        
        _Alty& _Al        = _Getal();
        auto& _My_data    = _Mypair._Myval2;
        pointer& _Myfirst = _My_data._Myfirst;
        pointer& _Mylast  = _My_data._Mylast;
    	
        _STL_INTERNAL_CHECK(_Mylast == _My_data._Myend);
    
        const auto _Whereoff = static_cast<size_type>(_Whereptr - _Myfirst);
        const auto _Oldsize  = static_cast<size_type>(_Mylast - _Myfirst);
    	
        if (_Oldsize == max_size()) {
            _Xlength();
        }
    	
        const size_type _Newsize     = _Oldsize + 1;
        const size_type _Newcapacity = _Calculate_growth(_Newsize);
    
        const pointer _Newvec           = _Al.allocate(_Newcapacity);
        const pointer _Constructed_last = _Newvec + _Whereoff + 1;
        pointer _Constructed_first      = _Constructed_last;
    
        _TRY_BEGIN
        _Alty_traits::construct(_Al, _Unfancy(_Newvec + _Whereoff), _STD forward<_Valty>(_Val)...);
        _Constructed_first = _Newvec + _Whereoff;
    
        if (_Whereptr == _Mylast) { // at back, provide strong guarantee
            _Umove_if_noexcept(_Myfirst, _Mylast, _Newvec);
        } else { // provide basic guarantee
            _Umove(_Myfirst, _Whereptr, _Newvec);
            _Constructed_first = _Newvec;
            _Umove(_Whereptr, _Mylast, _Newvec + _Whereoff + 1);
        }
        _CATCH_ALL
        _Destroy(_Constructed_first, _Constructed_last);
        _Al.deallocate(_Newvec, _Newcapacity);
        _RERAISE;
        _CATCH_END
    	
        _Change_array(_Newvec, _Newsize, _Newcapacity);
        return _Newvec + _Whereoff;
    }
    

总结

  vector在项目或者刷题中有大量的运用,熟练掌握他们的用法是必不可少的一步。同时,vector扩容的机制就是面试常考的题目,理解其源码对我们编写代码也有很大益处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

详解C++STL容器系列(一)—— vector的详细用法和底层原理 的相关文章

  • Nginx部署多个Vue项目,配置不同域名

    文章目录 一 前言二 上传dist文件三 配置nginx cnf四 域名解析 一 前言 一个服务器需要部署多个前端项目 比如需要一个企业官网比如需要一个管理系统 这时候一个Nginx要怎么配置多个前端项目呢本文详细讲解 xff1a 通过不同
  • ESP32-C3入门教程 问题篇⑫——undefined reference to rom_temp_to_power, in function phy_get_romfunc_addr

    文章目录 一 前言 二 发现问题 三 解决问题 一 前言 本文基于VS Code IDE进行编程 编译 下载 运行等操作 基础入门章节请查阅 ESP32 C3入门教程 基础篇 基于VS Code构建Hello World 教程目录大纲请查阅
  • USART RX 不上拉的后果

    这两天写一个STM32的程序 xff0c 其中USART1是要接一个串口屏做显示的 xff0c 调试前期是还没用到显屏 xff0c 就拿USART1做log打印 然后就发现了一个很怪异的现象 USART1串口转usb接到电脑 xff0c 程
  • 虚拟机ros系统安装

    一 新建虚拟机 1 这里选择自定义安装 这里为了灵活性一般使用稍后安装 红款内根据自己情况选择安装路径 这一步一定要选择IDE否则开机 会报错 这里默认20g就够用 点击完成虚拟机就安装完成了 二安装ros系统 点击这个光驱安装镜像 把镜像
  • 用python实现realsenseD435i相机实现视频显示,并按空格键执行拍照,保存照片的程序

    为了使用Intel RealSense D435i相机 xff0c 我们需要安装pyrealsense2库 你可以通过以下命令安装它 xff1a pip install pyrealsense2 下面是一个使用pyrealsense2库实现
  • 二元信号量、互斥量和临界区之间的区别

    二元信号量 适合只能被唯一一个线程独占访问的资源 多元信号量 适合允许多个线程并发访问的资源 互斥量 和二元信号量类似 xff0c 资源仅同时允许一个线程访问 xff0c 但和信号量不同的是 xff0c 信号量在整个系统可以被任意线程获取并
  • ROS摄像机的标定

    本文主要为ROS camera calibration 单目相机标定教程的翻译 原文 xff1a http wiki ros org camera calibration Tutorials MonocularCalibration 仅供英
  • <视觉>——单目相机的标定(简单原理+Opencv实现)

    单目相机的标定原理大致如下 xff1a 世界坐标到像素坐标的转换 期间的参数有S尺度因子 xff0c 内参矩阵K xff0c 旋转矩阵R xff0c 平移矩阵T xff0c 一共八个未知数 在Opencv中我们可以方便的根据相机拍摄不同位姿
  • Python入门自学进阶-Web框架——4、HttpRequest和HttpResponse及模板

    HTTP请求中产生两个核心的对象 xff1a http请求 xff1a HttpRequest对象 http响应 xff1a HttpResponse对象 所在位置django http xff0c 前边用的reques就是HttpRequ
  • 维修杜邦线(母头)

    在一个研发团体中 xff0c 即使有某一位或几位财大气粗的 xff0c 也难免有其他成员借设备使用的 xff0c 研发过程中使用的电子设备在底层通讯之间大都采用杜邦线连接 xff0c 大家都熟悉 xff0c 优点就不说了 xff0c 先说说
  • 【酷毙了】野火新版fireTools多功能调试助手,有Windows和Linux版本,就问你喜不喜欢。...

    01 软件简介 野火fireTools 多功能调试助手 xff0c 是一款使用QT开发 xff0c 可以在Windows和Linux环境下完美运行的绿色客户端 xff0c 不需要安装 xff0c 双击即可运行 xff0c 其功能包括 xff
  • 结合模型,视频动态演示PID三个参数的作用!

    PID控制器 xff08 比例 积分 微分控制器 xff09 xff0c 由比例单元 xff08 P xff09 积分单元 xff08 I xff09 和微分单元 xff08 D xff09 组成 可以通过调整这三个单元的增益Kp xff0
  • 单片机数字滤波算法如何实现?(附代码)

    ID xff1a 技术让梦想更伟大 整理 xff1a 李肖遥 单片机主要作用是控制外围的器件 xff0c 并实现一定的通信和数据处理 但在某些特定场合 xff0c 不可避免地要用到数学运算 xff0c 尽管单片机并不擅长实现算法和进行复杂的
  • HNU软件能力实训2-9. 字符串压缩

    写在前面 你好 xff01 欢迎来到我的博客 xff0c 希望我的思路能够帮到你 xff01 问题描述 给定一个由n个小写字母组成的字符串s xff0c 需要使用最少数量的钱币来压缩它 压缩该字符串 xff0c 必须将s表示为多个相互连接的
  • HNU软件能力实训2-21. 新型冠状病毒(COVID19)传播

    写在前面 你好 xff01 欢迎来到我的博客 xff0c 希望我的思路能够帮到你 xff01 问题描述 防控新冠病毒 xff0c 必须时刻引起大家的足够重视 xff0c 特别是人员集中活动场所 xff0c 保持好社交距离 然而 xff0c
  • HNU软件能力实训3-8. ab串

    写在前面 你好 xff01 欢迎来到我的博客 xff0c 希望我的思路能够帮到你 xff01 问题描述 给定一个由字符 a 和字符 b 组成的字符串 xff0c 可以删除若干字符 xff0c 使得剩下来的字符串满足前后段为a xff0c 中
  • HNU软件能力实训3-9. 占座位

    写在前面 你好 xff01 欢迎来到我的博客 xff0c 希望我的思路能够帮到你 xff01 问题描述 一个人可以去占多个座位 xff0c 而且一定是要连续的座位 xff0c 如果占不到他所要求的这么多座位 xff0c 那么他就一个座位也不
  • ROS编程入门(C++ 及 思路)

    使用Autolabor官方入门教程 xff0c 笔记内容为注意事项 首页 Autolabor开源ROS机器人底盘 官方网站 一 ROS通信机制的解释 例如在生活中 xff0c 我们在家里有一个放零食的箱子 xff0c 而操作服务器就是这个箱
  • HNU软件能力实训4-5. 小希的数表

    写在前面 你好 xff01 欢迎来到我的博客 xff0c 希望我的思路能够帮到你 xff01 问题描述 Gardon 昨天给小希布置了一道作业 xff0c 即根据一张由不超过 5000 的 N 3 lt 61 N lt 61 100 个正整
  • HNU软件能力实训4-12. 疫情期间

    写在前面 你好 xff01 欢迎来到我的博客 xff0c 希望我的思路能够帮到你 xff01 问题描述 正值新冠疫情期间 xff0c 阿迪没法返回学校学习 xff0c 他希望通过参加一些比赛来提高一下编程技能 xff0c 同时做做运动 他收

随机推荐

  • HNU软件能力实训4-14. 组个最小数

    写在前面 你好 xff01 欢迎来到我的博客 xff0c 希望我的思路能够帮到你 xff01 问题描述 给定数字0 9各若干个 你可以以任意顺序排列这些数字 xff0c 但必须全部使用 目标是使得最后得到的数尽可能小 xff08 注意0不能
  • CMakeLists.txt的编写

    首先是编写好的CMakeLists txt文件 span class token function cmake minimum required span span class token punctuation span VERSION
  • 第一课 神经网络与深度学习 第二周 神经网络基础(已完结(虽然有坑))

    视频地址 二分分类 怎么说 xff0c 第一段话就颠覆了我的想象 xff0c 遍历m个样本不需要用for循环 这里是介绍了图片的预处理 xff0c 将图片切分为rgb三个颜色空间 xff08 这个我熟 xff09 xff0c 然后将所有的分
  • leetcode 1200. 最小绝对差

    1200 最小绝对差 span class token keyword class span span class token class name Solution span span class token punctuation sp
  • 648. 单词替换

    648 单词替换 span class token keyword class span span class token class name Solution span span class token punctuation span
  • 1217. 玩筹码

    1217 玩筹码 span class token comment 由题目描述可知 xff0c 移动1步成本为1 移动2步没有成本 那么我们可以不耗费成本的将不同奇数位置的筹码移动到某一个奇数位置 此时的成本为0 同理 也可以将不同偶数位置
  • dronekit控制实体无人机起飞降落

    摘要 xff1a 本文基于dronekit在实体无人机上实现最基本的起飞和降落 xff0c 测试了这一过程中速度的变化以及起落位置的偏移 实体实验环境 树莓派4BUbuntu mate 20 04飞控Pixhawk 2 4 8飞控固件APM
  • Gazebo中针对Gazebo软件或生成模型出现process has died问题的参考方案

    在基于ROS机器人仿真时 xff0c 打开Gazebo经常出现一些问题 xff0c 比如Gazebo窗口打开了 xff0c 终端却显示gazebo进程已死 本文记录了一次遇到的类似问题 xff0c 并给出了在部分情况下能够适用的参考方案 问
  • ROS 入门 (launch文件)

    本章主要内容介绍在ROS中上述问题的解决策略 见本章目录 xff0c 预期达成学习目标也与上述问题对应 xff1a 掌握元功能包使用语法 xff1b 掌握launch文件的使用语法 xff1b 理解什么是ROS工作空间覆盖 xff0c 以及
  • 报错:Multiple annotations found at this line: - user cannot be resolved

    问题 xff1a Multiple annotations found at this line user cannot be resolved 第一步 xff1a 右键找到Build Path 点击Configure Build Path
  • Nuxt 生命周期

    目录 服务端生命周期1 nuxtServerInit nuxt中第一个运行的生命周期 2 RouteMiddleware 第二个 xff1a 中间键 xff0c 路由导航守卫 4 validate 是用来校验url参数符不符合5 async
  • 使用ESP-idf-4.23一次编译通过ESP32-Drone四旋翼无人机代码

    为了编译ESP32 Drone四旋翼无人机代码 xff0c 试用了几种编译环境 xff0c 折腾一个上午 xff0c 最后使用ESP idf 4 23一次性编译通过 记录一下过程 1 获取ESP32 Drone四旋翼无人机项目源代码 xff
  • 基于ESP32四旋翼无人机如何根据PID算法进行电机的PWM duty补偿

    1 计算模型 电机位置和补偿输出的关系 xff0c 需要求解的是C1 C2 C3 C4的电机输出补偿值 分别对应M1 M2 M3 M4四个电机 2 推导过程 xff08 可以跳过不看 xff0c 直接到第三步 xff09 3 四个电机的PI
  • 基于ESP32四旋翼无人机的MPU6050姿态数据采集和处理方式

    1 MPU6050姿态数据采集和处理 在DMP任务里面采集MPU6050的四元数的姿态数据 xff0c 然后解算出机体坐标系的三个角姿态角 dmp task任务通过消息队列将姿态角发送给姿态控制程序 dmp task gt dandelio
  • 基于ESP32四旋翼无人机同蓝牙遥控器通信处理方式

    1 蓝牙初始化 在app main调用函数初始化蓝牙 inf ble gatt init 2 判断蓝牙是否链接 在dandelion task中调用函数inf ble gatt connected 判断蓝牙是否链接 xff0c 进而调用da
  • 论文Handheld Multi-Frame Super-Resolution的相关学习笔记

    导语 这里汇总了阅读这篇论文可能会参考到的相关知识汇总 xff0c 这篇主要为了让自己查找方便 但是也希望阅读这篇博文的你能够通过我的笔记更快理解 上手这篇论文 文章题目 xff1a Hand held Multi frame super
  • ASP读EXCEL2000的文章!!!

    由于工作需要 要用ASP读取EXCEL的工资单 所以在网上找了些资料 写了以下程序 送给大家 xff1a xff09 lt 39 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 6
  • Linux下软件安装方法

    对于Linux初学者来说 xff0c 安装一个很小的软件恐怕都是一件很让人头疼的事 xff0c 因为在Linux下安装软件不像在 Windows中那样简单 在Linux中大多数软件提供的是源代码 xff0c 而不是现成的可执行文件 xff0
  • linux指令大全(二)

    cat cd chmod chown cp cut 名称 xff1a cat 使用权限 xff1a 所有使用者 使用方式 xff1a cat AbeEnstTuv help version fileName 说明 xff1a 把档案串连接后
  • 详解C++STL容器系列(一)—— vector的详细用法和底层原理

    目录 一 介绍二 vector的创建和方法创建vector方法 三 vector的具体用法3 1 遍历vector3 1 1 迭代器访问3 1 2 下标访问3 1 3 范围for循环 3 2 vector 容量和大小3 3 vector 常