STLvector源码——实现框架、具体实现的详细分段剖析(重点是insert_aux在指定位置插入元素和在指定位置插入n个元素的源码)、vector实现的基本函数总结

2023-10-27

VS2010的源码真的让人放弃,还是安安稳稳看侯捷老师的SGI

源码(SGI vector)

实现框架

#include<iostream>
#include<cstddef>//用到了size_t和ptrdiff_t
using namespace std;
template<class T,class Alloc=alloc>
class vector
{}

(1) 空间分配属性,由于是对外封闭的,所以protected
定义一个空间分配器,当然要有空间的起始地址存储结束地址最大存储结束地址以及初始化的函数和释放空间的函数

protected:
		typedef simple_alloc<value_type,Alloc>data_allocator;//定义一个空间分配器
		iterator start;//起始地址
		iterator finish;//容器实际大小的末端
		iterator end_of_storage;//容器最大可容大小的末端
 
		void fill_initialize(size_type n,const T&x);//分配n个元素的大小,初值为x
		void deallocate();//释放整个容器空间

(2) 共有访问的属性,可供外部用户访问, 定义为public

/*******公有属性,类型别名************/
		typedef T value_type;//元素类型
		typedef value_type* pointer;//指针类型
		typedef value_type* iterator;//迭代器类型
		typedef const value_type* const_iterator;//指向常量的迭代器类型
		typedef value_type& reference;//引用类型
		typedef size_t size_type;//大小类型
		typedef ptrdiff_t difference_type;//指针差值类型
 

(3) 容器的构造函数和析构函数
注意带一个参数的构造函数注意要用关键字explicit,原因见上篇

/***********构造/析构函数*************/
	vector();//默认构造函数
	explicit vector(size_type n);//单形参构造函数,explicit防止类型的隐式转化
	vector(size_t n,const T & t);//带初值的构造函数
	~vector();//析构函数

(4)插入操作

/***********插入操作******************/
	void push_back(const T& t);//后插入值t
	iterator insert(iterator iter,const T& t);//在iter前插入值t
	void insert(iterator iter,size_type n,const T& t);//在iter前插入n个初值为t的元素
	void insert(iterator iter,iterator b,iterator e);//在iter前插入迭代器范围[b,e)的元素

(5)删除操作

/***********删除操作******************/
	iterator erase(iterator iter);//删除iter所指向的元素
	iterator erase(iterator b,iterator e);//删除迭代器范围[b,e)所指向的元素
	void clear();//清除容器内所有的元素
	void pop_back();//将容器的最后一个元素弹出

(6)大小操作
max_size()是获取编译器可申请的最大空间

/***********大小操作******************/
		size_type size()const;//获取实际使用的大小
		size_type max_size()const;//获取编译器可申请的最大大小,以元素的个数为单位
		size_type capacity()const;//获取容器当前的容量
		bool empty()const;//是否为空容器
		void resize(size_type n);//将容器的实际大小调整为n
		void resize(size_type n,const T& t);//将容器的时间大小调整为n,并提供必要的初值t

(7)访问操作
end()是取容器最后一个元素的下一个指针

/***********访问操作******************/
		iterator begin();//取容器头指针
		iterator end();//取容器最后一个元素的下一个指针
		reference operator[](size_type i);//v[i]
		reference at(size_type i);//取容器的第i个元素,等价于v[i]
		reference front();//返回容器头部元素的值
		refrence back();//返回容器尾部元素的值

具体实现

1,空间分配器

data_allocator进行内存空间的分配,用data_allocator:deallocate()进行释放,初始化的时候不多分配内存,内存空间结束点和已经使用的内存空间结束点是相同的
allocate_and_fill是发配空间,并且复制对象到分配的空间处

protected:
	// 这个提供STL标准的allocator接口
	typedef simple_alloc <value_type, Alloc> data_allocator;
 
	iterator start;               // 表示目前使用空间的头
	iterator finish;              // 表示目前使用空间的尾
	iterator end_of_storage;      // 表示实际分配内存空间的尾
 void fill_initialize(size_type n, const T& value)//初始化
	{
		start = allocate_and_fill(n, value);
		finish = start + n;                         // 设置当前使用内存空间的结束点
		// 构造阶段, 此实作不多分配内存,
		// 所以要设置内存空间结束点和已经使用的内存空间结束点相同
		end_of_storage = finish;
	}
protected:
	// 分配空间, 并且复制对象到分配的空间处
	iterator allocate_and_fill(size_type n, const T& x)
	{
		iterator result = data_allocator::allocate(n);
		uninitialized_fill_n(result, n, x);
		return result;
	}
	// 释放分配的内存空间
	void deallocate()
	{
		// 由于使用的是data_allocator进行内存空间的分配,
		// 所以需要同样使用data_allocator::deallocate()进行释放
		// 如果直接释放, 对于data_allocator内部使用内存池的版本
		// 就会发生错误
		if (start)
			data_allocator::deallocate(start, end_of_storage - start);
	}
	
 

(2) 共有访问的属性,可供外部用户访问

public:
	// 获取几种迭代器
	iterator begin() { return start; }
	iterator end() { return finish; }
 
	// 返回当前对象个数
	size_type size() const { return size_type(end() - begin()); }
	size_type max_size() const { return size_type(-1) / sizeof(T); }
	// 返回重新分配内存前最多能存储的对象个数
	size_type capacity() const { return size_type(end_of_storage - begin()); }
	bool empty() const { return begin() == end(); }
	reference operator[](size_type n) { return *(begin() + n); }

(3)构造函数和析构函数

默认构造函数不分配内存空间
单参数构造函数需要对象提供默认构造函数
析构函数需要首先析构对象destory(),然后释放内存deallocate()
重载等号操作符来构造函数其底层用的就是拷贝构造函数

    vector() : start(0), finish(0), end_of_storage(0) {}//默认构造函数,不分配内存空间
 
 
	vector(size_type n, const T& value) { fill_initialize(n, value); }
	vector(int n, const T& value) { fill_initialize(n, value); }
	vector(long n, const T& value) { fill_initialize(n, value); }
 
	// 需要对象提供默认构造函数
	explicit vector(size_type n) { fill_initialize(n, T()); }
 
	vector(const vector<T, Alloc>& x)//拷贝构造函数?将x的拷贝到当前容器中
	{
		start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
		finish = start + (x.end() - x.begin());
		end_of_storage = finish;
	}
 
	~vector()
	{
		// 析构对象
		destroy(start, finish);
		// 释放内存
		deallocate();
	}
 vector<T, Alloc>& operator=(const vector<T, Alloc>& x);//还可以重载等号操作符进行构造初始化,用拷贝构造函数作为底层

(4) 插入操作

在插入元素之前需要先判断内存是否已满,如果还没有则直接加,否则的话需要用insert_aux()重新分配内存为原来的2倍,它会首先判断内存是否够用,像在函数指定位置插入元素时就没有在本体函数内部判断内存是否够,而是到insert_aux()中再去做的判断

void insert_aux(iterator position, const T& x);//它还会再中心判断是否内存够用
void push_back(const T& x)//在容器尾部追加一个元素
	{
		// 内存满足条件则直接追加元素, 否则需要重新分配内存空间
		if (finish != end_of_storage)
		{
			construct(finish, x);
			++finish;
		}
		else
			insert_aux(end(), x);
	}
	
	iterator insert(iterator position, const T& x)//在指定位置插入元素
	{
		size_type n = position - begin();
		if (finish != end_of_storage && position == end())//如果刚好需要插在末尾且内存够就直接插入
		{
			construct(finish, x);
			++finish;
		}
		else
			insert_aux(position, x);//否则,到这个函数再去操作,是否内存不足也去这里判断
		return begin() + n;
	}

⭐⭐⭐insert_aux()

insert_aux 在指定位置插入一个元素

  1. 首先判断是否还有空间,如果有,从opsition开始, 整体向后移动一个位置,
  2. 否则没有备用空间的话,
    2.1. 先看当前内存容量,如果当前没有内存是0,因为vector默认构造函数是不分配内存段的,分配len = 1;如果当前内存不为0,则分配len = 原来的2倍
    2.2. 用data_allocator进行分配len的长度,vector的每次扩容数据都是要进行搬迁的,所以一开始new_finish = new_start;
    2.3. 首先将原vector的安插点以前的内容拷贝到新vector,将新元素放上position,再搬剩下的元素;
    2.3. 扩容复制完之后要删除原空间的元素释放原空间内存;
  3. 代码中还有回滚操作,那就是释放新范围的元素再释放内存空间即可
template <class T, class Alloc>
void insert_aux(iterator position, const T& x)
	{
		if (finish != end_of_storage)    // 还有备用空间
		{
			// 在备用空间起始处构造一个元素,并以vector最后一个元素值为其初值
			construct(finish, *(finish - 1));//[start,finish)
		++finish;//扩容完成
			T x_copy = x;
			copy_backward(position, finish - 2, finish - 1);//从opsition开始, 整体向后移动一个位置
			*position = x_copy;
		}
		else   // 已无备用空间
		{
			const size_type old_size = size();
			const size_type len = old_size != 0 ? 2 * old_size : 1;
			// 以上配置元素:如果大小为0,则配置1(个元素大小)
			// 如果大小不为0,则配置原来大小的两倍
			// 前半段用来放置原数据,后半段准备用来放置新数据
 
			iterator new_start = data_allocator::allocate(len);  // 实际配置
			iterator new_finish = new_start;
			// 将内存重新配置
			try
			{
				// 将原vector的安插点以前的内容拷贝到新vector
				new_finish = uninitialized_copy(start, position, new_start);
				// 为新元素设定初值 x
				construct(new_finish, x);
				// 调整水位
				++new_finish;
				// 将安插点以后的原内容也拷贝过来
				new_finish = uninitialized_copy(position, finish, new_finish);
			}
			catch(...)
			{
				// 回滚操作
				destroy(new_start, new_finish);
				data_allocator::deallocate(new_start, len);
				throw;
			}
			// 析构并释放原vector
			destroy(begin(), end());
			deallocate();
 
			// 调整迭代器,指向新vector
			start = new_start;
			finish = new_finish;
			end_of_storage = new_start + len;
		}
	}

insert_aux在指定位置插入n个元素

  1. 首先判断n是否等于0,等于0不做任何操作; 否则判断内存空间是否足够,
  2. 空间够的话
    2.1. 根据要插入数的个数和[position, finish)元素即待后移元素个数多少不进痛行不同的指针移动,具体方法画图就能明了:
    2.2 如果待插入元素少,先将最后n个元素后移到finish后,这一步目的就是为了增加n个元素空间,再将position后元素后移,最后插入;
    2.3 如果待插入元素多,那一定会占据完剩余的空间,并且就n来说还需要n-elem_after个元素,现在position后的元素一定在新插入元素之后,所以先增加差值个元素,再在之后将position后的元素移动,方法非常巧妙,可学习
  3. 空间不够的话:
    3.1. 首先决定新长度:就长度的两倍 , 或旧长度+新增元素个数
    3.2 用data_allocator::allocate(len)配置空间,还是一样,首先将旧的vector的插入点之前的元素复制到新空间,再将新增元素(初值皆为n)填入新空间,最后将旧vector的插入点之后的元素复制到新空间
    3.3移动完之后要将原来的元素删除,将原来的空间释放,并将迭代器重新指向
    3.4 回滚同理
template <class T, class Alloc>
template <class T, class Alloc>
	void insert(iterator position, size_type n, const T& x)
	{
		// 如果n为0则不进行任何操作
		if (n != 0)
		{
			if (size_type(end_of_storage - finish) >= n)
			{      // 剩下的备用空间大于等于“新增元素的个数”
				T x_copy = x;
				// 以下计算插入点之后的现有元素个数
				const size_type elems_after = finish - position;
				iterator old_finish = finish;
				if (elems_after > n)
				{
					// 插入点之后的现有元素个数 大于 新增元素个数
					uninitialized_copy(finish - n, finish, finish);
					finish += n;    // 将vector 尾端标记后移
					copy_backward(position, old_finish - n, old_finish);
					fill(position, position + n, x_copy); // 从插入点开始填入新值
				}
				else
				{
					// 插入点之后的现有元素个数 小于等于 新增元素个数
					uninitialized_fill_n(finish, n - elems_after, x_copy);
					finish += n - elems_after;
					uninitialized_copy(position, old_finish, finish);
					finish += elems_after;
					fill(position, old_finish, x_copy);
				}
			}
			else
			{   // 剩下的备用空间小于“新增元素个数”(那就必须配置额外的内存)
				// 首先决定新长度:就长度的两倍 , 或旧长度+新增元素个数
				const size_type old_size = size();
				const size_type len = old_size + max(old_size, n);
				// 以下配置新的vector空间
				iterator new_start = data_allocator::allocate(len);
				iterator new_finish = new_start;
				__STL_TRY
				{
					// 首先将旧的vector的插入点之前的元素复制到新空间
					new_finish = uninitialized_copy(start, position, new_start);
					// 再将新增元素(初值皆为n)填入新空间
					new_finish = uninitialized_fill_n(new_finish, n, x);
					// 再将旧vector的插入点之后的元素复制到新空间
					new_finish = uninitialized_copy(position, finish, new_finish);
				}
#         ifdef  __STL_USE_EXCEPTIONS
				catch(...)
				{
					destroy(new_start, new_finish);
					data_allocator::deallocate(new_start, len);
					throw;
				}
#         endif /* __STL_USE_EXCEPTIONS */
				destroy(start, finish);
				deallocate();
				start = new_start;
				finish = new_finish;
				end_of_storage = new_start + len;
			}
		}
	}

(5)删除操作

iterator erase(iterator first, iterator last)
	{
		iterator i = copy(last, finish, first);//删除first到last就意味着将last到finish的值拷贝到first √
		destroy(i, finish);// 析构掉需要析构的元素
		finish = finish - (last - first);
		return first;
	}
void clear() { erase(begin(), end()); }

(6)大小操作

// 调整size, 但是并不会重新分配内存空间
	void resize(size_type new_size, const T& x)
	{
		if (new_size < size())
			erase(begin() + new_size, end());
		else
			insert(end(), new_size - size(), x);
	}
	void resize(size_type new_size) { resize(new_size, T()); }
 

(7)访问操作

reference front() { return *begin(); }
reference back() { return *(end() - 1); }

以上部分参考并感谢https://blog.csdn.net/jxh_123/category_2333293.html

vector容器概述

  1. vector是动态数组,与之对应的是array静态数组,array是静态空间,空间大小一旦配置了就不能改变;但vector如果想改变(变大或变小)都是可以做到的:
    改变过程: 1,首先配置一块新空间; 2,将元素从现在的地址一一复制到新地址; 3,再将原来空间空间释放
    至于什么时候进行扩大或缩小,vector内部会自动实现, 因此vector的实现技术关键就在于对其空间大小的控制以及重新配置时的数据移动效率
  2. vector维护的是一个连续性空间,所以vector支持随机存取
  3. 注意当vector动态增加大小时,并不是在原空间之后扩展新空间,因此,对vector的任何操作,一旦引起空间重新配置,指向原来vector的所有迭代器就都失效了

vector的基本函数实现

1, 构造函数

  • vector():创建一个空vector
  • vector(int nSize):创建一个vector,元素个数为nSize
  • vector(int nSize, const t&t):创建一个vector,元素个数为nSize, 且均值为t
  • vector(const vector&):复制构造函数
  • vector(begin, end);复制这个范围内另一个数组元素到vector

2, 增加函数

  • void push_back(const T& x);
  • iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素x
  • iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
  • iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据

删除元素

  • iterator erase(iterator it):删除向量中迭代器指向元素
  • iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
  • void pop_back():删除向量中最后一个元素
  • void clear():清空向量中所有元素

遍历函数

  • reference at(int pos):返回pos位置元素的引用
  • reference front():返回首元素的引用
  • reference back():返回尾元素的引用
  • iterator begin():返回向量头指针,指向第一个元素
  • iterator end(): 返回向量尾指针,指向向量最后一个元素的下一个位置
  • reverse_iterator rbegin():反向迭代器,指向最后一个元素
  • reverse_iterator rend():反向迭代器,指向第一个元素之前的位置

判断函数

  • bool empty() const:判断向量是否为空,若为空,则向量中无元素

大小函数

  • int size() const:返回向量中元素的个数
  • int capacity() const:返回当前向量所能容纳的最大元素值
  • int max_size() const:返回最大可允许的vector元素数量值

其他函数

  • void swap(vector&):交换两个同类型向量的数据,与另一个vector交换数据
  • void assign(int n,const T& x):设置向量中第n个元素的值为x
  • void assign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素

妈欸……开心,终于迈出了第一步

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

STLvector源码——实现框架、具体实现的详细分段剖析(重点是insert_aux在指定位置插入元素和在指定位置插入n个元素的源码)、vector实现的基本函数总结 的相关文章

  • 为什么通过派生类对基类的引用与 :: - 运算符不明确?

    所以我想知道为什么以下钻石问题的代码片段无法编译 我知道这个问题通常是通过虚拟继承来解决的 我不是故意使用它的 该代码只是为了展示我的问题 即为什么编译器称此不明确 因此 我在 struct Base 中声明了两个成员变量 因为这两个子类
  • Volatile.Read 和 Volatile.Write 背后的逻辑是什么?

    来自 MSDN Volatile Read 读取字段的值 在需要它的系统上 插入一个 阻止处理器重新排序内存的内存屏障 操作如下 如果在该方法之后出现读或写 代码 处理器无法移动它before这个方法 and Volatile Write
  • 在 C# 中使用“using”关键字避免多次处置的最佳实践

    当变量是 IDisposable 时 我们有using关键字来管理处置 但是如果我们在方法中返回值怎么办 using twice StringContent stringToStringContent string str using St
  • JSON.Net 反序列化返回“null”

    我正在使用 JSON Net 反序列化 JSON 字符串 JSON 字符串是 string testJson Fruits Apple color red size round Orange Pro
  • WebClient.DownloadDataAsync 冻结了我的 UI

    我在 Form 构造函数中的 InitializeComponent 之后有以下代码 using WebClient client new WebClient client DownloadDataCompleted new Downloa
  • 如何使用 ASP.NET MVC 编辑多选列表?

    我想编辑一个如下所示的对象 我希望用 UsersGrossList 中的一个或多个用户填充 UsersSelectedList 使用 mvc 中的标准编辑视图 我只得到映射的字符串和布尔值 下面未显示 我在 google 上找到的许多示例都
  • 锁定 ASP.NET 应用程序变量

    我在 ASP NET 应用程序中使用第三方 Web 服务 对第 3 方 Web 服务的调用必须同步 但 ASP NET 显然是多线程的 并且可能会发出多个页面请求 从而导致对第 3 方 Web 服务的同时调用 对 Web 服务的调用封装在自
  • 如果 JSON.NET 中的值为 null 或空格,则防止序列化

    我有一个对象需要以这样的方式序列化 即 null 和 空白 空或只是空格 值都不会序列化 我不控制对象本身 因此无法设置属性 但我知道所有属性都是字符串 环境NullValueHandling显然 忽略 只能让我找到解决方案的一部分 它 似
  • 将 OpenCV Mat 转换为数组(可能是 NSArray)

    我的 C C 技能很生疏 OpenCV 的文档也相当晦涩难懂 有没有办法获得cv Mat data属性转换为数组 NSArray 我想将其序列化为 JSON 我知道我可以使用 FileStorage 实用程序转换为 YAML XML 但这不
  • 司机和提供商之间的区别

    数据库中的驱动程序和提供程序有什么区别 有没有解释一下 不胜感激 样本 ADO NET driver for MySQL vs providerName System Data EntityClient 来自 MSDN 论坛 驱动程序是安装
  • C# 处理标准输入

    我目前正在尝试通过命令行断开与网络文件夹的连接 并使用以下代码 System Diagnostics Process process2 new System Diagnostics Process System Diagnostics Pr
  • 为什么需要数字后缀?

    C 语言 我确信还有其他语言 需要在数字文字末尾添加后缀 这些后缀指示文字的类型 例如 5m是一个小数 5f是一个浮点数 我的问题是 这些后缀真的有必要吗 或者是否可以从上下文中推断出文字的类型 例如 代码decimal d 5 0应该推断
  • Resharper:IEnumerable 的可能多重枚举

    我正在使用新的 Resharper 版本 6 在我的代码中的几个地方 它给一些文本加了下划线 并警告我可能存在IEnumerable 可能的多重枚举 我理解这意味着什么 并在适当的情况下采纳了建议 但在某些情况下 我不确定这实际上是一个大问
  • 如何在 C# 中获取 Json 数组?

    我有一个像这样的 Json 字符串 我想将它加载到 C 数组中 当我尝试这样做时 我收到异常 我的字符串 customerInformation customerId 123 CustomerName Age 39 Gender Male
  • 将错误代码映射到 C++ 中的字符串

    将错误代码从枚举映射到字符串的更有效方法是什么 在 C 中 例如 现在我正在做这样的事情 std string ErrorCodeToString enum errorCode switch errorCode case ERROR ONE
  • 如何使用 CSI.exe 脚本参数

    当你运行csi exe 安装了 Visual Studio 2015 update 2 您将得到以下语法 Microsoft R Visual C Interactive Compiler version 1 2 0 51106 Copyr
  • 从 NumPy 数组到 Mat 的 C++ 转换 (OpenCV)

    我正在围绕 ArUco 增强现实库 基于 OpenCV 编写一个薄包装器 我试图构建的界面非常简单 Python 将图像传递给 C 代码 C 代码检测标记并将其位置和其他信息作为字典元组返回给 Python 但是 我不知道如何在 Pytho
  • 无法识别解决方案文件夹中的 Visual Studio 2017 Nuget.config

    我在使用 Visual Studio 2017 时遇到问题 新的解决方案不断引用 C Users yopa AppData Roaming NuGet Nuget config 中意外位置的 Nuget config 文件 我已将 nuge
  • printf或iostream如何指定点后的最大位数

    字符串采用什么格式printf or iomanip我应该使用 iostream 中的运算符以以下格式打印浮点数 125 0 gt 125 125 1 gt 125 1 125 12312 gt 125 12 1 12345 gt 1 12
  • C++ Boost ASIO 简单的周期性定时器?

    我想要一个非常简单的周期性计时器每 50 毫秒调用我的代码 我可以创建一个始终休眠 50 毫秒的线程 但这很痛苦 我可以开始研究用于制作计时器的 Linux API 但它不可移植 I d like使用升压 我只是不确定这是否可能 boost

随机推荐

  • 软测入门(一)测试理念及基础知识

    软测入门理念 软件的分类 按层次划分 系统软件 应用软件 按组织划分 商业软件 开源软件 按结构划分 单机软件 软件缺陷 由来 Grace Hopper发明Cobol计算机语言 也是找出电脑程序中第一个bug的女程序员 Bug Defect
  • 上传源码到GitHub代码托管平台方法和步骤

    上传源码到GitHub的方法步骤 要在本地上传代码到GitHub第一步就是先在本地有git版本控制软件 或者你的IDE集成了git 否则一切都是徒劳 1 先下载git 地址 https git scm com downloads 2 安装G
  • 【漏洞复现】CVE-2021-45232 Apache-apisix-dashboard

    靶场搭建 修改版本号 启动环境 查看端口号为9090 用主机登录ip 9000 默认用户名 admin 默认密码 admin 点击 路由 进入路由页面 打开POC所在文件夹 cmd执行 刷新路由页面 查看路由配置 成功注入恶意 script
  • Oracle各种进程功能一览表

    在安装Oracle数据库的时候 我检查进程 发现了以下进程 功能如下 Ora pmon 是进程监视器 Process Monitor 的缩写 当取消当前的事务 或者释放进程占用的锁以及其它资源的时候 这个进程清空那些失败的进程 Ora vk
  • 谷歌Chrome小恐龙代码(自动跳,高跳,无敌,加速)

    目录 自动跳代码 无敌代码 高跳代码 可以改括号内参数 疾跑代码 可以改括号内参数 大多数浏览器都有自己的彩蛋 而今天我们分享的是谷歌Chrome 谷歌小恐龙游戏是一个浏览器自带的小游戏 断网联网状态都是可以玩的 那么如何在联网的状态下进行
  • Flask 增删改查

    基本操作 目录 基本操作 添加 查看数据 分页 详情 删除 修改 路由配置 创建模型类models from app extensions import db class Books db Model tablename tb books
  • Feign远程调用丢失请求头问题

    在业务中 需要使用A B两个模块 这些模块使用了SpringSession共享Session数据 在B模块中的业务需要用户登录后才能操作 当A调用B的业务时 在B模块中获取不到用户的Session信息 导致B模块判定该请求用户没有登录导致A
  • java基础错题总结

    1 解析 首先乘法的优先级高于加法 所以先进行y z 然后在这里 是连接符 因为头一个是字符串所以系统就认为是连接符 就成 10202 0 输出这个字符串 但如果第一个不是字符串类型的 就像 10 20 a 这个会输出 30 a 2 解析
  • gis中的加权求和工具在哪里_因果推理初探(5)——干预工具(上)

    本节将延续上一节学习的干预的有关概念 开始深入介绍几种干预的工具 后门调整 前门调整 逆概率加权等 本节将有大量公式来袭 请准备草稿纸或提前绕道 在上一节最后 我们推导出有关干预的重要公式 调整公式 它的形式如下 这个公式让我们可以通过观测
  • 为什么使用代理后不能上网了?

    在使用完代理服务器之后 有的用户可能会遇到这样的问题 明明网络正常 为什么我的浏览器不能打开网页了 今天就给大家说下具体解决方法 这里我们以IE浏览器为例 1 先打开浏览器 点击右上角的 工具 图标 然后点击下拉中的 Internet选项
  • elasticsearch中文分词器插件elasticsearch-analysis-ik远程自定义词典热更新

    IK简介 IK分词器基于词库进行分词 analysis ik内置了一些词典 主词典main dic 姓氏词典surname dic 量词词典quantifier dic 后缀词典suffix dic 介词词典preposition dic
  • vue项目创建

    默认3 默认2 自定义配置 js语法编辑器 ts 渐进式web应用程序 路由 状态管理器 css处理器 代码检查 单元测试 端对端测试 选择版本 路由是否选择历史模式 选择css预处理器 配置放在哪里 保存这个项目作为一个模版使用 npm
  • 【网络】Linux网络问题汇总(一)

    网卡设置了静态获取 仍然获取动态IP的解决方法 问题展示 网卡配置静态方式获取 仍然通过dhcp获取到了ip 且每次分配的ip都一样 root senlian cat etc sysconfig network scripts ifcfg
  • OAUTH之 钉钉第三方授权登录

    文章目录 OAUTH之钉钉第三方授权登录 前期用到的工具 获取access token 请求地址 请求方法 响应 扫码 使用账号密码 获取 临时 code 参数重要说明 直接访问 扫码登录 使用账号密码登录第三方网站 根据 sns 临时授权
  • 性能测试度量指标

    1 响应时间 响应时间指从用户或事务在客户端发起一个请求开始 到客户端接收到从服务器端返回的响应结束 这整个过程所消耗的时间 在性能测试实践中 为了使响应时间更具代表性 响应时间通常是指事务的平均响应时间ART 在实践中要注意 不同行业 不
  • node+koa2+mongodb搭建RESTful API风格后台

    RESTful API风格 在开发之前先回顾一下 RESTful API 是什么 RESTful 是一种 API 设计风格 并不是一种强制规范和标准 它的特点在于请求和响应都简洁清晰 可读性强 不管 API 属于哪种风格 只要能够满足需要
  • Unity之URP开启PostProcessing后使用RenderTexture渲染模型背景为不透明

    项目需要在UI界面显示角色模型 使用一个模型相机投射到RT上然后放在Raw Image上 现在这个模型相机需要开启后处理Post Processing 只针对模型添加了后处理效果 问题是开启后 Raw Image背景变了 把UI背景图遮住了
  • TensorFlow找不到cudart64_110.dll not found的解决方案

    问题描述 当我写了两句小程序准备开启我的TensorFlow之路时候 import tensorflow as tf hello tf constant hello tensorflow print Hello python sess tf
  • 安防监控视频云存储平台EasyNVR对接EasyNVS时,一直不上线该如何解决?

    视频安防监控平台EasyNVR可支持设备通过RTSP Onvif协议接入 并能对接入的视频流进行处理与多端分发 包括RTSP RTMP HTTP FLV WS FLV HLS WebRTC等多种格式 近期有用户在使用安防视频平台EasyNV
  • STLvector源码——实现框架、具体实现的详细分段剖析(重点是insert_aux在指定位置插入元素和在指定位置插入n个元素的源码)、vector实现的基本函数总结

    VS2010的源码真的让人放弃 还是安安稳稳看侯捷老师的SGI 源码 SGI vector 实现框架 include