STL中的vector以及简单实现

news2024/9/21 7:25:14

vector的简单介绍:

头文件:

#include<vector>

vector是属于STL的一员,虽然vector的英文意思是向量,但是vector就是一个顺序表;

对于vector来说,面对string的设计的复杂和冗余,vector就简洁很多了;

vector就是一个标准的模板,作为类模板,vector只能是显式实例化;

vector 学习时一定要学会查看文档: vector的文档介绍

vector的使用:

vector 在实际中非常的重要,在实际中我们熟悉常见的接口就可以,下面列出了哪些接口是要重点掌握的

构造:

(constructor) 构造函数声明
接口说明
vector() (重点)

无参构造
vector size_type n,
const value_type&val = value_type())

构造并初始化 n val
vector (const vector& x); (重点)

拷贝构造
vector (InputIterator first,
InputIterator last);
使用迭代器进行初始化构造
//对于类模板是要显式实例化的<type_name>
//无参构造
vector<int> v1;
//初始化一个数组,数组有10个1
vector<int> v2(10, 1);
//用迭代器的区间进行初始化
vector<int> v3(++v2.begin(), --v2.end());
//用其他容器的迭代器初始化
//........

迭代器:

iterator 的使
接口说明
begin + end (重点)
获取第一个数据位置的 iterator/const_iterator , 获取最后一个数据的下一个位置的iterator/const_iterator
rbegin + rend
获取最后一个数据位置的 reverse_iterator ,获取第一个数据前一个位的reverse_iterator

位置说明

vector 空间增长问题:

容量空间
接口说明
size
获取数据个数
capacity
获取容量大小
empty
判断是否为空
resize (重点)
改变 vector size
reserve (重点)
改变 vector capacity
capacity 的代码在 vs g++ 下分别运行会发现, vs capacity 是按 1.5 倍增长的, g++ 是按 2 倍增长的 。这个问题经常会考察,不要固化的认为, vector 增容都是 2 倍,具体增长多少是根据具体的需求定义的。vs PJ 版本 STL g++ SGI 版本 STL;
reserve 只负责开辟空间,如果确定知道需要用多少空间, reserve 可以缓解 vector 增容的代价缺陷问题;
resize 在开空间的同时还会进行初始化,影响 size;

vector 增删查改:

vector 增删查改
接口说明
push_back (重点)
尾插
pop_back (重点)
尾删
find
查找(注意这个是算法模块实现,不是 vector 的成员接口
insert
position 之前插入 val
erase
删除 position 位置的数据
swap
交换两个 vector 的数据空间
operator[] (重点)
像数组一样访问

vector没有提供find,但是在算法中有提供find(函数模板),因为string不仅要find一个字符,还要find一个字符串,所以不用算法里面的find,string比较特殊,所以自己实现

int x;
cin >> x;
auto pos = find(v.begin(), v.end(), x);

C++要求:传迭代器区间都要传左闭右开

迭代器失效:

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对 指针进行了封装 ,比如: vector 的迭代器就是原生态指针 T* 。因此 迭代器失效,实际就是迭代器底 层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间 ,造成的后果是程序崩溃 ( 如果继续使用已经失效的迭代器,程序可能会崩溃 )

会引起其底层空间改变的操作,都有可能是迭代器失效

比如:resizereserve、insert、assign、push_back等。

1.类似于野指针:

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t old_size = size();
				T* tmp = new T[n];
				memcpy(tmp, _start, size() * sizeof(T));
				delete[] _start;
			
				_start = tmp;
				_finish = tmp + old_size;
				_end_of_storage = _start + n;
			}

		}
void insert(iterator pos, const T& x)
{
	if (_finish == _end_of_storage)
	{
		//空间满了
		reserve(capacity() == 0 ? 4 : capacity() * 2);
	}
	iterator end = _finish - 1;
	while (end >= pos)
	{
		*(end + 1) = *end;
		--end;
	}
	*pos = x;
	++_finish;
}

问题出现在pos还指向在原来的空间,没有跟着变换到新的空间,所以,解决该问题的方法就是还原pos的相对位置:

void insert(iterator pos, const T& x)
{
	if (_finish == _end_of_storage)
	{
		//空间满了
		size_t len = pos - _start;
		reserve(capacity() == 0 ? 4 : capacity() * 2);
		pos = _start + len;
	}
	iterator end = _finish - 1;
	while (end >= pos)
	{
		*(end + 1) = *end;
		--end;
	}
	*pos = x;
	++_finish;
}

另外:insert以后pos就实效了,不要去访问:因为pos还是指向旧的空间,其实就是形参的改变不影响实参,pos依旧是指向原来的位置,形参的改变并没有影响到实参,但是严格来说也不能加引用,这样就把带有常性的临时对象和普通引用放到一起了,权限放大了 ,如果const的话,那就不能修改了:(实在要访问修改的话,库中有说明,要访问就更新这个失效的迭代器的值)

int x;
cin >> x;
auto p = find(v.begin(), v.end(), x);
if (p != v.end())
{
	/*v.insert(p, 40);
	(*p) *= 10;*/

	p = v.insert(p, 40);
	(*(p + 1)) *= 10;
}
print_vector(v);

更新这个失效的迭代器的值:

iterator insert(iterator pos, const T& x)
{
	if (_finish == _end_of_storage)
	{
		//空间满了
		size_t len = pos - _start;
		reserve(capacity() == 0 ? 4 : capacity() * 2);
		pos = _start + len;
	}
	iterator end = _finish - 1;
	while (end >= pos)
	{
		*(end + 1) = *end;
		--end;
	}
	*pos = x;
	++_finish;

	return pos;
}

总之:还是不要访问的好 ,本质就是类似野指针。(空间扩容)

2.位置意义已经发生改变:

在没有发生扩容的时候,pos位置并没有跟随数据的向后移动而跟随,整体来说,pos已经不是指向原来数据,位置意义也已经发生改变,这种情况也可以称为迭代器失效(上面情况是空间扩容带来的类似野指针的行为)

3. 注意:Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端:

// 1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int main()
{
	vector<int> v{ 1,2,3,4,5 };
	for (size_t i = 0; i < v.size(); ++i)
		cout << v[i] << " ";
	cout << endl;
	auto it = v.begin();
	cout << "扩容之前,vector的容量为: " << v.capacity() << endl;
	// 通过reserve将底层空间设置为100,目的是为了让vector的迭代器失效
	v.reserve(100);
	cout << "扩容之后,vector的容量为: " << v.capacity() << endl;
	// 经过上述reserve之后,it迭代器肯定会失效,在vs下程序就直接崩溃了,但是linux下不会
		// 虽然可能运行,但是输出的结果是不对的
		while (it != v.end())
		{
			cout << *it << " ";
			++it;
		}
	cout << endl;
	return 0;
}
//程序输出:
//1 2 3 4 5
//扩容之前,vector的容量为: 5
//扩容之后,vector的容量为 : 100
//0 2 3 4 5 409 1 2 3 4 5
// 2. erase删除任意位置代码后,linux下迭代器并没有失效
// 因为空间还是原来的空间,后序元素往前搬移了,it的位置还是有效的
#include <vector>
#include <algorithm>
int main()
{
	vector<int> v{ 1,2,3,4,5 };
	vector<int>::iterator it = find(v.begin(), v.end(), 3);
	v.erase(it);
	cout << *it << endl;
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	return 0;
}
//程序可以正常运行,并打印:
//4
///4 5
// 3: erase删除的迭代器如果是最后一个元素,删除之后it已经超过end
// 此时迭代器是无效的,++it导致程序崩溃
int main()
{
	vector<int> v{ 1,2,3,4,5 };
	// vector<int> v{1,2,3,4,5,6};
	auto it = v.begin();
	while (it != v.end())
	{
		if (*it % 2 == 0)
			v.erase(it);
		++it;
	}
	for (auto e : v)
		cout << e << " ";
	cout << endl;
	return 0;
}
========================================================
// 使用第一组数据时,程序可以运行
[sly@VM - 0 - 3 - centos 20220114]$ g++ testVector.cpp - std = c++11
[sly@VM - 0 - 3 - centos 20220114]$ . / a.out
1 3 5
======================================================== =
// 使用第二组数据时,程序最终会崩溃
[sly@VM - 0 - 3 - centos 20220114]$ vim testVector.cpp
[sly@VM - 0 - 3 - centos 20220114]$ g++ testVector.cpp - std = c++11
[sly@VM - 0 - 3 - centos 20220114]$ . / a.out
Segmentation fault

4. 与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效 

#include <string>
void TestString()
{
	string s("hello");
	auto it = s.begin();
	// 放开之后代码会崩溃,因为resize到20会string会进行扩容
	// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了
	// 后序打印时,再访问it指向的空间程序就会崩溃
	//s.resize(20, '!');
	while (it != s.end())
	{
		cout << *it;
		++it;
	}
	cout << endl;
	it = s.begin();
	while (it != s.end())
	{
		it = s.erase(it);
		// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后
		// it位置的迭代器就失效了
		// s.erase(it);
		++it;
	}
}

vector的模拟实现:

要时常注意浅拷贝带来的问题:

代码:直接在类里面实现了_and_测试代码:(放在了头文件)

#pragma once
#include<iostream>
#include<assert.h>
#include<vector>
#include<list>
using namespace std;
namespace home
{
	template<class T>
	class vector
	{
	public:

		typedef T* iterator;//模板
		typedef const T* const_iterator;

		//vector()
		//{}//写不写都会走初始化列表,有缺省值给到了(初始化)

		//C++11后
		//强制生成默认构造
		vector() = default;
		
		vector(const vector<T>& v)
		{
			reserve(v.size());//提高效率,避免下面的扩容
			for (auto& e : v)//给引用,减少想string的拷贝
			{
				push_back(e);
			}
		}

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}

		//vector<T>& operator=(const vector<T>& v)
		//类里面可以用类名替换类型,类外面不行
		vector& operator=(vector& v)
		{
			//现代:
			swap(v);
			return *this;
		}

		//迭代器区间构造
		//类模板的成员函数,还可以继续是函数模板
		//这就可以是任意类型的迭代器
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		vector(size_t n, const T& val = T())
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

		vector(int n, const T& val = T())
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _end_of_storage = nullptr;
			}
		}

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		void clear()
		{
			_finish = _start; 
		}

		const_iterator begin()const
		{
			return _start;
		}

		const_iterator end()const
		{
			return _finish;
		}

		size_t size()const
		{
			return _finish - _start;//左闭右开,相减得size数
		}

		size_t capacity()const
		{
			return _end_of_storage - _start;
		}

		void reserve(size_t n)
		{
			size_t old_size = size();
			T* tmp = new T[n];
			//memcpy(tmp, _start, old_size * sizeof(T));//对于string像这种数据深拷贝类型的,对于内置类型就没什么问题,memcpy会出问题,memcpy按字节拷贝,之前的被delete,变为随机值
			//解决:需要深拷贝
			for (size_t i = 0; i < old_size; i++)
			{
				tmp[i] = _start[i];//调用赋值:释放旧空间,拷贝新空间
			}
			delete[] _start;

			_start = tmp;
			_finish = tmp + old_size;
			_end_of_storage = tmp + n;

		}

		bool empty()
		{
			return _start == _finish;
		}

		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				//空间满了
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			*_finish = x;
			_finish++;
		}

		void pop_back()
		{
			assert(!empty());
			--_finish;
		}

		//迭代器失效
		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			if (_finish == _end_of_storage)
			{
				//空间满了
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;

			return pos;
		}

		void erase(iterator pos)
		{
			assert(pos >= _start && pos <= _finish);
			auto it = pos + 1;
			while (it != end())
			{
				*(it - 1) = *it;
				++it;
			}
			--_finish;
		}

		void resize(size_t n, const T val = T())//用默认构造去构造一个匿名对象,再去拷贝构造,但是编译器优化后是直接构造的,以后大概就是这种形式来给缺省值,但是在之前内置类型并没有构造,后来出现了模板,也有了内置类型的构造,析构概念
		{
			//n<size:删除
			//size<n<capacity:少的补val
			//n>capacity:开足够空间,少的补val
			if (n < size())
			{
				_finish = _start + n;
			}
			else
			{
				reserve(n);
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
		}

		T& operator[](size_t i)
		{
			assert(i < size());
			return _start[i];
		}

		const T& operator[](size_t i)const
		{
			assert(i < size());
			return _start[i];
		}
	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage;
	};
	template<class T>
	void print_vector(const vector<T>& v)
	{
		//编译器编译到这的时候,类模板是还没有被实例化的,并不知道vector<T>是什么,
		//类模板有一个原则:
		//类模板没有被实例化的时候不敢到里面去取东西,因为里面的东西也有可能有各种的坑,分不清楚到底是类型还是静态成员变量
		//需要在前面+:typename(这就是于class的区别)
		//->规定:没有实例化的类模板里面取东西,编译器不能区分这里const_iterator是类型还是静态成员变量
		//还有一种解决方案:用auto
		auto  it = v.begin();
		while (it != v.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}



	//写成模板,打印各种容器(更通用)
	template<class Container>
	void print_container(const Container& v)
	{
		auto  it = v.begin();
		while (it != v.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	void test_vector1()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);
		v.pop_back();
		for (size_t i = 0; i < v.size(); i++)
		{
			cout << v[i] << " ";
		}
		cout << endl;
		vector<int>::iterator it = v.begin();
		while (it != v.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
		print_vector(v);
		vector<double> vd;
		vd.push_back(1.0);
		vd.push_back(2.2);
		vd.push_back(3.2);
		vd.push_back(4.2);
		vd.push_back(5.2);
		print_vector(vd);
	}
	void test_vector2()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		//v.push_back(5);

		print_vector(v);

		v.insert(v.begin() + 2, 30);

		print_vector(v);

		int x;
		cin >> x;
		auto p = find(v.begin(), v.end(), x);
		if (p != v.end())
		{
			/*v.insert(p, 40);
			(*p) *= 10;*/

			p = v.insert(p, 40);
			(*(p + 1)) *= 10;
		}
		print_vector(v);

	}
	void test_vector3()
	{
		int i = int();
		int j = int(1);
		int k(2);

		vector<int> v;
		v.resize(10, 1);
		v.reserve(20);
		print_container(v);
		cout << v.size() << endl;
		cout << v.capacity() << endl;

		v.resize(15, 2);
		print_container(v);

		v.resize(5);
		print_container(v);
	}
	void test_vector4()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		print_container(v);

		vector<int> v1 = v;
		print_container(v);

		vector<int> v2;
		v2.push_back(1);
		v2.push_back(2);
		v2.push_back(3);

		v = v2;//v1之前的空间释放掉
		print_container(v);

		vector<int> v3(v.begin()+1, v.end()-1);
		print_container(v3);

		//模板价值
		//任意容器迭代器初始化
		//要求类型是匹配的
		list<int> lt;
		lt.push_back(12);
		lt.push_back(22);
		lt.push_back(32);
		vector<int> v4(lt.begin(), lt.end());
		print_container(lt);
		printf("\n");
		print_container(v4);

		vector<string> v5(10,"1111111");
		print_container(v5);

		//会报错,因为有模板的选择,匹配不上
		/*vector<int> v6(10, 1);
		print_container(v6);*/
		//解决:
		//指定访问最后这个
		vector<int> v6(10u, 1);
		print_container(v6);
		//再给一个更佳的选择(现成)
		vector<int> v7(10, 2);
		print_container(v7);
	}


	void test_vector5()
	{
		vector<string> v;
		v.push_back("11111");
		v.push_back("11111");
		v.push_back("11111");
		v.push_back("11111");
		print_container(v);

		v.push_back("11111");
		print_container(v);
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1982642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java毕业设计 基于SSM和Vue的图书馆座位预约系统小程序

Java毕业设计 基于SSM和Vue的图书馆座位预约系统小程序 这篇博文将介绍一个基于SSM框架和Vue开发的图书馆座位预约系统微信小程序&#xff0c;适合用于Java毕业设计。 功能介绍 用户 登录 注册 首页 图片轮播 关于我们 公告信息 图书馆信息 图书馆详情 预约选座 收藏 …

Tkinter Designer:拖拽式加速Python Tkinter GUI开发的神器

引言 在Python的世界里&#xff0c;创建美观且功能强大的图形用户界面&#xff08;GUI&#xff09;向来是开发者的挑战之一。Tkinter&#xff0c;作为Python的内置GUI库&#xff0c;虽然功能强大&#xff0c;但在实际使用中&#xff0c;设计和实现GUI的过程往往耗时且繁琐。Tki…

Linux中信号的处理

进程正在递达某一个信号期间&#xff0c;同类型的信号无法被递达&#xff01;&#xff01;&#xff01; 当当前信号正在被捕捉事&#xff0c;系统会自动将当前信号加入到进程的信号屏蔽字&#xff08;block&#xff09;。 当信号完成捕捉动作&#xff0c;系统又会自动解除对该…

R语言BIOMOD2 及机器学习方法的物种分布模拟与案例分析

BIOMOD2是一个R软件包&#xff0c;用于构建和评估物种分布模型&#xff08;SDMs&#xff09;。它集成了多种统计和机器学习方法&#xff0c;如GLM、GAM、SVM等&#xff0c;允许用户预测和分析物种在不同环境条件下的地理分布。通过这种方式&#xff0c;BIOMOD帮助研究者评估气候…

Linux-理解shell

文章目录 5. 理解shell5.1 shell的类型5.2 交互shell和系统默认shell5.3 安装zsh shell程序5.4 shell的父子关系5.5 命令列表5.6 命令分组5.7 使用命令分组创建子shell5.8 子shell用法5.9 shell的非内建命令和内建命令5.9.1 非内建命令5.9.2 内建命令5.9.3 history和alias命令介…

Cornerstone加载本地Dicom文件第二弹 - Blob篇

&#x1f340; 引言 当我们刚接触Cornerstone或拿到一组Dicom文件时&#xff0c;如果没有ImageID和后台接口&#xff0c;可能只是想简单测试Cornerstone能否加载这些Dicom文件。在这种情况下&#xff0c;可以使用本地文件加载的方法。之前我们介绍了通过node启动服务器请求文件…

cuda pytorch安装详细教程 GPU版

1.先安装anaconda Anaconda 1.1这里用了最简单的方法&#xff0c;后面将pytorch直接安装到base配置下面了。 1.2下载安装&#xff0c;全部勾选。 一定添加文件夹到path中去&#xff0c;否则后面下载pytorch&#xff0c;无法传输。 1.3 通过cmd&#xff0c;输入conda --versio…

CSP-J 模拟题2

如果x大于45&#xff0c;则输出-1 设定一个整数now&#xff0c;他的初始值为9&#xff1b; 当x>now&#xff0c;就x-now&#xff0c;并且now--; 根据解析写代码1&#xff1a; #include <bits/stdc.h> using namespace std; int a[101010]; int main(){int x;cin>…

设计师必备网站,素材、灵感一手抓

设计师都在哪些地方找素材&#xff0c;找灵感&#xff1f;分享8个设计师必备网站&#xff0c;素材免费下载&#xff0c;还能看到很多国内外大神的设计之作&#xff0c;赶紧收藏起来吧~ 1、baotu 包图网_专注原创商用设计图片下载&#xff0c;会员免费设计素材模板独家图库 国内…

QChart笔记7:基于QPolarChart的雷达图、能力图

六边形战士这个词经常听说&#xff0c;用来描述这个词的是六边形雷达图/能力图。在网上搜索如何用QChart实现没有找到&#xff0c;于是就自己研究出一种写法。 先看看效果&#xff1a; 可以用这个图表示游戏中的人物属性&#xff0c;看看我的几个不太厉害的NPC。 在QT自带的实…

STL—容器—list【list的介绍和基本使用】【list的迭代器失效问题】

STL—容器—list list的使用并不难&#xff0c;有了之前使用string和vector的基础后&#xff0c;学习起来并不难。因此这里不在详细的讲解如何使用&#xff0c;而是大致的将其基本接口都熟悉一下 1.list介绍 list的文档介绍 list是可以在常数范围内在任意位置进行插入和删除…

解决App推广难题,Xinstall带你实现一键唤起,提升用户转化率!

在移动互联网时代&#xff0c;App的推广和运营成为了开发者们面临的一大挑战。如何让用户在各种场景下快速、便捷地唤起你的App&#xff0c;提升用户转化率和活跃度呢&#xff1f;今天&#xff0c;就让我们一起来了解一下Xinstall这一神奇的助手&#xff0c;它将如何解决这些痛…

基于YOLOv10和半监督学习的小麦麦穗检测算法:YOLOv10_ssod

基于YOLOv10和半监督学习的小麦麦穗检测算法&#xff1a;YOLOv10_ssod 1.引言2.数据集2.1 公共数据集2.2 自制数据集 3.YOLOv10算法及改进3.1 YOLOv10原版算法3.2 YOLOv10算法改进3.3 对比实验 4.半监督学习方法5.训练效果5.1最终检测效果5.2YOLOv10的精度曲线图5.3 半监督YOLO…

【Material-UI】Button 组件中的图标和标签按钮(Buttons with Icons and Label)详解

文章目录 一、基础用法1. 左侧图标&#xff08;startIcon&#xff09;2. 右侧图标&#xff08;endIcon&#xff09; 二、图标与标签的搭配三、高级用法和最佳实践1. 自定义图标2. 视觉一致性3. 动态图标 四、总结 在现代用户界面设计中&#xff0c;图标在提高用户体验&#xff…

如何礼貌且高效地应对工作中的无关问题

目录 礼貌而简洁地回应引导至相关资源设置边界利用自动回复工具委婉地拒绝建议通过正式渠道提问引导至相关资源的详细例子设置边界的详细例子深入探讨如何应对无关问题1. 培养对方的自主学习能力2. 利用团队合作3. 利用技术工具提高效率4. 定期培训和分享 具体的案例分析案例一…

初始Spring与SpringIOC容器

一、 Spring框架的基本理解 Spring框架是一款轻量级的开发框架&#xff0c; 核心思想是IOC (控制反转) 和AOP (面向切面编程)&#xff0c; 为Java 应用程序开发提供组件管理服务&#xff0c;用于组件之间的解耦&#xff0c;以及简化第三方JavaEE中间件技术的使用( JMS、任务调度…

python XML2SRS

step 1:练习XPATH 选取text-property标签具有nametext 属性值的标签的值 //text-property[nametext] import os import lxml.etree as etree dir "E:\\" for file in os.listdir(dir):if file.endswith(.rptdesign):with open(dirfile,r,encodingutf-8) as f:firs…

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(五)卡尔曼滤波器一:认知卡尔曼滤波器;协方差矩阵与方差;

卡尔曼滤波器 为了研究卡尔曼&#xff0c;我阅读了大量博文。不敢说完全吃透&#xff0c;但是在做一件什么事&#xff0c;可以通过下面这文章来理解&#xff0c;我读了不下五遍。并整理标准重点&#xff0c;添加自己的一些见解。 自动驾驶传感器融合算法 - 自动驾驶汽车中的激…

mprpc框架的应用示例

一、注册 有一个本地服务&#xff0c;我想把它发布成远程服务&#xff0c;首先在user.proto中定义rpc方法的描述&#xff0c;定义参数和响应的消息类型 然后在userservice.cc文件中通过继承UserServiceRpc这个类&#xff0c;重写一下响应的方法&#xff08;打四个动作&#xf…

深入了解Synchronized原理

深入了解Synchronized原理 第一章&#xff1a;并发编程中的三个问题1.1 可见性1.2 原子性1.3 有序性 第二章&#xff1a;Java内存模型(JMM)2.1 计算机结构简介2.2 Java内存模型 Java Memory Molde 第三章&#xff1a;synchronized保证三大特性3.1 synchronized保证原子性3.2 sy…