STL 剖析

STL 六大组件

「STL 六大组件的交互关系」

  • Container 通过 Allocator 取得数据储存空间
  • Algorithm 通过 Iterator 存取 Container 内容
  • Functor 可以协助 Algorithm 完成不同的策略变化
  • Adapter 可以修饰或套接 Functor、Iterator

配置器(allocator)

配置器:负责空间配置与管理,从实现的角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的 class template。

空间配置器:整个 STL 的操作对象(所有的数值)都存放在容器之内,而容器一定需要配置空间以存放内容。

具有次配置力(sub-allocation)的 SGI 空间配置器

SGI STL 空间配置器的结构

SGI STL 的配置器,其名称是 alloc 而不是 allocator,而且不接受任何参数。

SGI STL 的每一个容器都已经指定其缺省的空间配置器为 alloc。

template <class T, class Alloc = alloc>  // 缺省使用 alloc 为配置器class vector {...};vector<int, std::alloc> iv;

  • <defalloc.h>----SGI 标准的空间配置器,std::allocator

allocator 只是基层内存配置/释放行为(::operator::new 和 ::operator::delete)的一层薄薄的包装,并没有考虑到任何效率上的强化。

  • SGI 特殊的空间配置器,std::alloc
    • <stl_construct.h>:定义了全局函数 construct() 和 destroy(),负责对象的构造和析构。
    • <stl_alloc.h>:定义了一、二级配置器,配置器名为 alloc。
    • <stl_uninitialized.h>:定义了全局函数,用来填充(fill)或复制(copy)大块内存数据。
  • 构造和析构基本工具

具体看 <stl_construct.h> 源码,功能是构造和析构操作。

  • 空间的配置和释放,std::alloc
    • 向 system heap 要求空间
    • 考虑多线程(multi-threads)状态
    • 考虑内存不足时的应变措施
    • 考虑过多 “小型区块” 可能造成的内存碎片问题

对象构造前的空间配置 和 对象析构后的空间释放,具体看 <stl_alloc.h>。

SGI STL 空间配置器的分析

考虑到小型区块可能造成内存碎片问题,SGI 采用两级配置器,第一级配置器直接使用 malloc() 和 free() 实现;第二级配置器使用 memory pool 内存池管理。

第二级配置器的原理:

  • 当配置区块超过 128 bytes,就使用第一级配置器
  • 当配置区块小于 128 bytes,使用内存池管理

enum {_ALIGN = 8};  // 小型区块的上调边界

enum {_MAX_BYTES = 128}; // 小区区块的上限

enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN  free-list 的个数

// free-list 的节点结构,降低维护链表 list 带来的额外负担

union _Obj {union _Obj* _M_free_list_link;  // 利用联合体特点char _M_client_data[1];    /* The client sees this. */};

static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS];  // 注意,它是数组,每个数组元素包含若干相等的小额区块

其中 free-list 是指针数组,16 个数组元素,就是 16 个 free-list,各自管理大小分别为 8, 16, 24, 32,...128 bytes(8 的倍数)的小额区块。

小额区块的结构体 union _Obj 使用链表连接起来。

配置器负责配置,同时也负责回收。

迭代器(iterator)

迭代器:扮演容器与算法之间的桥梁,是所谓的 “泛型指针”,共有五种类型,以及其它衍生变化。从实现的角度来看,迭代器是一种将 operator*,operator->,operator++,operator-- 等指针相关操作予以重载的 class template。 所有 STL 容器都附带有自己专属的迭代器。 native pointer 也是一种迭代器。

迭代器(iterator) 是一种 smart pointer

迭代器是一种行为类似指针的对象,而指针的各种行为中最常见的用途是 dereference 和 member access。迭代器最重要的就是对 operator* 和 operator->进行重载工作。

auto_ptr:用来包装原生指针(native pointer)的对象,在头文件 中定义。

为什么每一种 STL 容器都提供有专属迭代器的缘故。

主要是暴露太多细节,所以把迭代器的开发工作交给容器去完成,这样所有实现细节可以得到封装,不被使用者看到。

迭代器相应类型(associated types)

迭代器所指对象的类型。

利用 function template 的参数推导机制,只能推导出参数的类型,无法推导出函数返回值类型。

迭代器相应类型有五种:

  • value type
  • difference type
  • pointer
  • reference
  • iterator category

Traits 编程技术

traits 意为 “特性”,扮演 “特性萃取机” 角色,萃取各个迭代器的特性(相应类型)。

template partial specialization 模板偏特化:针对 template 参数更进一步的条件限制所设计出来的一个特化版本,本身仍然是 template。

tempalte<typename I>struct iterator_traits{typedef typename I::iterator_category  iterator_category;typedef typename I::value_type  value_type;typedef typename I::difference_type  difference_type;typedef typename I::pointer  pointer;typedef typename I::reference  reference;};
  • 迭代器相应类型之一:value type

value type 就是迭代器所指对象的类型。

template <class T>typename iterator_traits<I>::value_type func(I ite){return *ite;}
  • 迭代器相应类型之二:difference type

difference type 用来表示两个迭代器之间的距离。

template <class I, class T>typename iterator_traits<I>::difference_type cout(I first, I last, const T& value){typename iterator_traits<I>::difference_type n = 0;for (; first != last; ++first){++n;}return n;}
  • 迭代器相应类型之三:reference type

在 c++ 中,函数如果要传回左值,都是以 by reference 的方式进行,所以如果 p 是一个迭代器,它的 value type 是 T ,那么*p 应该是T& (即reference typ·e)

  • 迭代器相应类型之四:pointer type
    •      迭代器相应类型之五:iterator_category
      • 输入迭代器 (InputIterator) 是能从所指向元素读取的迭代器 (Iterator) 。输入迭代器 (InputIterator) 仅保证单趟算法的合法性。
      • 输出迭代器 (OutputIterator) 是能写入所指元素的迭代器 (Iterator) 。
      • 向前迭代器 (ForwardIterator) 是一种能从所指向元素读取数据的迭代器 (Iterator) 。
      • 双向迭代器 (BidirectionalIterator) 是能双向移动(即自增与自减)的向前迭代器 (ForwardIterator) 。
      • 随机访问迭代器 (RandomAccessIterator) 是能在常数时间内移动到指向任何元素的双向迭代器 (BidirectionalIterator) 。

总结

traits 本质是什么?

多一层间接性,换来灵活性。

iterator_traits 负责萃取迭代器的特性,__type_traits 负责萃取类型的特性

容器(container)

容器:包括序列式容器和关联式容器;即各种数据结构,如 vector,list,deque,set,map 等用来存储数据;从实现的角度来看,STL 容器是一种 class template。

任何特定的数据结构都是为了实现某种特定的算法。

序列式容器(sequence container)

  • array (C++ 提供,build-in)
  • vector
  • heap (内含一个 vector)
  • priority-queue (内含一个 heap)
  • list
  • slist (非标准)
  • deque
  • stack (内含一个 deque) (adapter 配接器)
  • queue (内含一个 deque) (adapter 配接器)

怎么理解序列式容器,其中的元素都可序(ordered), 但未必有序(sorted)?

ordered 是容器集合被排序,可以使用指定的顺序去遍历集合。 sorted 是一个容器集合根据某些规则确定排序的。

关联式容器(associative container)

  • RB-tree (非公开)
  • set (内含一个 RB-tree)
  • map (内含一个 RB-tree)
  • multiset (内含一个 RB-tree)
  • multimap (内含一个 RB-tree)
  • hashtable (非标准)
  • hash_set (内含一个 hashtable) (非标准)
  • hash_map (内含一个 hashtable) (非标准)
  • hash_multiset (内含一个 hashtable) (非标准)
  • hash_multimap (内含一个 hashtable) (非标准)

熟悉关联式容器,需要有 RB-tree(红黑树原理) 和 hash table(哈希表原理) 基础。

算法(algorithm)

算法:各种常用算法如 sort,search,copy,erase 等,从实现的角度来看,STL 算法是一种 function template。

所有泛型算法的前两个参数都是一对迭代器,STL 习惯使用前闭后开的区间,[first, last)。

最后一个元素的下一位置,称为 end()。

数值的传递由 pass-by-value 改为 pass-by-reference,好处是,在模板中,参数的类型可以任意,当对象一大,传递成本便会上升,所以用 pass-by-reference 可以节省空间。

数值算法 <stl_numeric.h>

STL 将数值算法的内部实现放在 <stl_numeric.h> 中,用户调用数值算法的接口,需要包含 头文件。  

元素累加 accumulate

算法 accumulate 用来计算 init 和 [first, last) 内所有元素的总和。

相邻元素的差值 adjacent_difference

算法 adjacent_difference 用来计算 [first, last) 中相邻元素的差值。

内积 inner_product

算法 inner_product 计算 [first1, last1) 和 [first2, first2 + (last1 - first1)) 的一般内积。 

局部求和 partial_sum

算法 partial_sum 用来计算局部求和。

幂次方 power

算法 power 用来计算某数的 n 幂次方。

递增 iota

在某区间 [first, last) 填入某指定值 value 的递增序列。

基本算法 <stl_algobase.h>

判断两个区间是否相等 equal

如果两个序列在 [first, last) 区间内相等,equal() 返回 true。

注意,如果第二个序列的元素比较多,多出来的元素不予考虑,只要与第一个序列的元素相等,就返回 true。

改填元素 fill

将 [first, last) 内的所有元素改填新值。

改填元素的值 n 次 fill_n

将 [first, last) 内的前 n 个元素改填新值,返回的迭代器指向被填入的最后一个元素的下一位置。

元素互换 iter_swap

将两个 Forwarditerators 所指的对象对调。

以字典顺序进行比较 lexicographical_compare

以 "字典排列方式" 对两个序列 [first1, last1) 和 [first2, last2) 进行比较。

最大值 max

取两个对象的较大值。

最小值 min

取两个对象的最小值。

找出不匹配的点 mismatch

用来平行比较两个序列,指出两者之间的第一个不匹配点。

交换 swap

该函数用来交换两个对象的内容。

复制 copy

copy 算法可将输入区间 [first, last) 内的元素复制到输出区间 [result, result + (last-first)) 内。

逆向复制 copy_backward

将 [first, last) 区间内的每一个元素,以逆行的方向复制到以 result-1 为起点,方向亦为逆行的区间上。

set 相关算法

  • 并集 set_union

算法 set_union 可构造 S1、S2 之并集(S1 U S2),此集合内含 S1 或 S2 内的每一个元素。其中 S1、S2 及其并集都是以排序区间表示。

  • 交集 set_intersection

算法 set_intersection 可构造 S1、S2 之交集。

  • 差集 set_difference

算法 set_difference 可构造 S1、S2 之差集。此集合内含出现于 S1 但不出现于 S2 的每一个元素。

  • 对称差集 set_symmetric_difference

算法 set_symmetric_difference 可构造 S1、S2 之对称差集。此集合内容出现于 S1 但不出现于 S2 以及 出现于 S2 但不出现 S1 的每一个元素。

heap 算法

头文件 <stl_heap.h>

  • make_heap() 建堆
  • pop_heap() 从堆中取出一个元素
  • push_heap() 将一个元素推进堆内
  • sort_heap() 对堆排序

其它算法 <stl_algo.h>

定义于 SGI <stl_algo.h> 内的所有算法。

查找相邻而重复的元素 adjacent_find

对一个序列,查找相邻元素值相等的第一个元素。

计数 count

将 [first, last) 区间内的每一个元素拿来和指定值 value 比较,并返回与 value 相等的元素个数。

在特定条件下计数 count_if

将指定操作(一个仿函数) pred 实施于 [first, last) 区间内的每一个元素身上,并将造成 pred 计算结果为 true 的所有元素的个数返回。

循环查找 find

循环查找 [first, last) 内的所有元素,找出第一个匹配条件的,返回指向该元素的迭代器。

在特定条件下循环查找 find_if

根据指定的 pred 运算条件,循环查找 [first, last) 内的所有元素,找出第一个令 pred 运算结果为 true,返回指向该元素的迭代器。

查找某个子序列的最后一次出现点 find_end

在序列一 [first, last) 所涵盖的区间中,查找序列二 [first, last) 的最后一个出现点。

查找某些元素的第一次出现点 find_first_of

本算法以 [first2, last2) 区间内的某些元素作为查找目标,寻找在 [first1, last1) 区间内的第一次出现地点。

对区间内的每一个元素进行某操作 for_each

将仿函数 f 作用于 [first, last) 区间内的每一个元素上。

以特定操作之运算结果填充特定区间内的元素 generate

将仿函数 gen 的运算结果赋值给 [first, last) 区间内的所有元素上。

以特定操作之运算结果填充 n 个元素内容 generate_n

将仿函数 gen 的运算结果填写在从迭代器 first 开发的 n 个元素身上。

应用于有序区间 includes

S1 和 S2 必须是有序集合,其中的元素可以重复,判断 S1 是否包含于 S2。includes 算法可供用户选择采用 less 或 greater 进行两元素的大小比较。

最大值所在位置 max_element

这个算法返回一个迭代器,指向序列之中数值最大的元素。

应用于有序区间的合并操作 merge

将两个经过排序的集合 S1 和 S2,合并起来置于另一段空间。所得结果也是一个有序序列。

最小值所在位置 min_element

这个算法返回一个迭代器,指向序列之中数值最小的元素。

分割 partition

partition 将区间 [first, last) 中的元素重新排列。所有被一元条件运算 pred 判定为 true 的元素,都会被放在区间的前段,被判定为 false 的元素,都会被放在区间的后段。

如果需要保留原始相对位置,应使用 stable_partition。

移除并不删除 remove

移除 [first, last) 之中所有与 value 相等的元素,这一算法并不真正从容器中删除那些元素,而是将每一个不与 value 相等的元素轮番赋值给 first 之后的空间。

移除某类元素并将结果复制到另一容器 remove_copy

移除 [first, last) 之中所有与 value 相等的元素。它并不真正从容器中删除那些元素,而是将结果复制到一个以 result 标示起始位置的容器身上。

有条件地删除某类元素 remove_if

移除 [first, last) 区间内所有被仿函数 pred 认定为 true 的元素,每一个不符合 pred 条件的元素都会被轮番赋值给 first 之后的空间。

有条件地删除某类元素并将结果复制到另一容器 remove_copy_if

移除 [first, last) 区间内所有被仿函数 pred 认定为 true 的元素,它并不真正从容器中删除那些元素,而是将结果复制到一个以 result 标示起始位置的容器身上。

替换某类元素 replace

将 [first, last) 区间内的所有 old_value 都以 new_value 取代。

替换某类元素,并将结果复制到另一个容器 repalce_copy

唯一不同的是新序列会被复制到 result 所指的容器中。

有条件地替换 replace_if

将 [first, last) 区间内的所有被 pred 评估为 true 的元素,都以 new_value 取而代之。

有条件地替换,并将结果复制到另一个容器 replace_copy_if

行为与 replace_if() 类似,新序列会被复制到 result 所指的区间内。

反转元素次序 reverse

将序列 [first, last) 的元素在原容器中颠倒重排。

反转元素次序并将结果复制到另一个容器 reverse_copy

行为与 reverse() 类似,新序列会被复制到 result 所指的容器中。

旋转 rotate

将 [first, middle) 内的元素和 [middle, last) 内的元素互换,middle 所指的元素会成为容器的第一个元素。

旋转,并将结果复制到另一个容器 rotate_copy

行为与 rotate_copy() 类似,新序列会被复制到 result 所指的容器中。

查找某个子序列 search

在序列一 [first1, last1) 所涵盖的区间中,查找序列二 [first2, last2) 的首次出现点。

查找连续发生 n 次的子序列 search_n

在序列 [first, last) 所涵盖的区间中,查找连续 count 个符合条件之元素所形成的子序列,并返回一个迭代器指向该子序列起始处。

指定区间交换 swap_ranges

将 [first1, last1) 区间内的元素与从 first2 开始、个数相同的元素互相交换。这两个序列可位于同一容器中,也可位于不同的容器中。

以两个序列为基础,交互作用产生第三个序列 transform

transform() 两个版本都执行结果放进迭代器 result 所标示的容器中。

将重复的元素删除,只保留一个 unique

算法 unique 能够移除重复的元素。每当在 [first, last) 内遇到重复元素群,它便移除该元素群中第一个以后的所有元素。

将重复的元素删除,只保留一个, 并复制 result 中unique_copy

算法 unique_copy 可从 [first, last) 中将元素复制到以 result 开头的区间上。

lower_bound (应用于有序区间)

二分查找,在已排序的 [first, last) 中的寻找元素 value,返回位置。

upper_bound (应用于有序空间)

二分查找,在已排序的 [first, last) 中的寻找元素 value,与 lower_bound 区别是返回查找值的位置。

二分查找 binary_search (应用于有序空间)

二分查找法,在已排序的 [first, last) 中的寻找元素 value,查找到,返回 true,否则 false。

求下一个排列组合 next_permutation

next_permutation() 获取 [first, last) 所标示之序列的下一个排列组合。

实现原理:

在当前序列中,从尾端往前寻找两个相邻元素,前一个记为 *i,后一个记为 *ii,并且满足 *i < *ii。然后再从尾端寻找另一个元素 *j,如果满足 *i < *j,即将第 i 个元素与第 j 个元素对调,并将第 ii 个元素之后(包括ii)的所有元素颠倒排序,即求出下一个序列了。

求上一个排列组合 prev_permutation

prev_permutation() 获取 [first, last) 所标示之序列的上一个排列组合。

实现原理:

在当前序列中,从尾端往前寻找两个相邻元素,前一个记为 *i,后一个记为 *ii,并且满足 *i > *ii。然后再从尾端寻找另一个元素 *j,如果满足 *i > *j,即将第 i 个元素与第 j 个元素对调,并将第 ii 个元素之后(包括ii)的所有元素颠倒排序,即求出上一个序列了。

随机重排元素 random-shuffle

这个算法将 [first, last) 的元素次序随机重排, 在 N!种可能的元素排列顺序中随机选出一种,此处 N 为 last-first。

局部排序 partial_sort/partial_sort_copy

本算法接受一个 middle 迭代器(位于序列 [first, last) 之内),然后重新安排 [first, last),使序列中的 middle-first 个最小元素以递增顺序排序,置于 [first, middle)内。其余 last-middle 个元素安置于 [middle, last) 中,不保证有任何特定顺序。

排序算法 sort

STL 的 sort 算法,数据量大时采用 Quick Sort,分段递归排序,当数据量小于某个门槛(5-20),就改用 Insertion Sort。

Insertion Sort

插入排序是以双层循环的形式进行。时间复杂度为 O(N^2)。

将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。

Quick Sort

平均时间复杂度为 O(NlogN),最坏情况下将达 O(N^2)。

STL 早期采用 Quick Sort,现在 SGI STL 改用 IntroSort(极类似 median-of-three QuickSort 的一种排序算法)。

递归

Median-of-Three(三点中值) 中间值

Partitioning 分割

SGI STL sort

混合式排序算法,Introspective Sorting,当做 Partitioning 操作,有恶化为二次行为的倾向时,改用 Heap Sort,使其效率维持在 Heap Sort 的 O(NlogN)。

用 __lg() 控制分割恶化的情况:

// 找出 2^k <= n 的最大值 ktemplate <class size>inline Size __lg(Size n) {Size k;for (k = 0; n > 1; n >>= 1)++k;return k;}

最多允许分割 2k 层;

混合式排序思想:

  • 先判断序列大小,当大于阈值 __stl_threshold(16),再检查分割层次,如果分割层次超过指定值 0,就改用 Heap Sort完成;
  • 在大于阈值 __stl_threshold(16),分割层次不为 0,就继续使用 Quick Sort;
  • 如果小于阈值,则用插入排序;

equal_range(应用于有序区间)

算法 equal_range 是二分查找法的一个版本,试图在已排序的 [first, last) 中寻找 value。

返回一个上下区间。

inplace_merge(应用于有序区间)

合并 并且 就地排序

nth_element

使第 n 大元素处于第 n 位置(从0开始,其位置是下标为 n的元素),并且比这个元素小的元素都排在这个元素之前,比这个元素大的元素都排在这个元素之后,但不能保证他们是有序的。

归并排序 merge sort

Merge Sort 的复杂度为 O(NlogN)。需要借用额外的内存。底层是调用 inplace_merge 实现。

仿函数/函数对象(functor/function object)

仿函数/函数对象:行为类似函数,可作为算法的某种策略,从实现的角度来看,仿函数是一种重载了 operator() 的 class 或 class template。STL 仿函数应该有能力被函数配接器(function adapter)修饰,为了拥有配接能力,每一个仿函数必须定义自己的相应类型。

以操作数的个数划分,可分为一元和二元仿函数

  • unary_function
unary_function 用来呈现一元函数的参数类型和返回值类型。// 一元函数的参数类型和返回值类型template <class _Arg, class _Result>struct unary_function {typedef _Arg argument_type;typedef _Result result_type;};binary_function
binary_function 用来呈现二元函数的第一参数类型、第二参数类型,以及返回值类型。// 二元函数的第一个参数类型和第二个参数类型,以及返回值类型template <class _Arg1, class _Arg2, class _Result>struct binary_function {typedef _Arg1 first_argument_type;typedef _Arg2 second_argument_type;typedef _Result result_type;};

功能划分

算法类(Arithmetic)仿函数

STL 内建的 "算术类仿函数",支持加法、减法、乘法、除法、模数和求反运算符。,

关系运算类(Relational)仿函数

STL 内建的 "关系运算类仿函数" 支持等于、不等于、大于、大于等于、小于、小于等于六种运算。

逻辑运算类(Logical)仿函数

STL 内建的 "逻辑运算类仿函数" 支持了逻辑运算种的 And、Or、Not 三种运算。

identity、select、project

将其参数原封不动地传回。为了间接性——间接性是抽象化的重要工具。

适配器(adapter)

适配器:一种用来修饰容器、仿函数或迭代器接口的东西。例如,STL 提供的 queue 和 stack,虽然看似容器,其实只能算是一种容器适配器,因为它们的底部完全借助 deque,所有操作都由底层的 deque 供应。改变 functor 接口者,称为 function adapter等。

适配器(adapter) 在 STL 组件的灵活组合运用功能上,扮演者转换器的角色。

应用于容器,container adapter

STL 提供的两个容器 queue 和 stack,它们修饰 deque 的接口而形成的。

应用于迭代器,iterator adapter

STL 提供了许多应用于迭代器的适配器。

insert iterator

插入迭代器内部都维护有一个容器,容器当然有自己的迭代器,当客户端对插入迭代器做赋值操作时,就在插入迭代器中被转为对该容器的迭代器做插入操作。

back_insert_iterator

用于在容器尾部插入的迭代器适配器。

front_insert_iterator

用于在容器头部插入的迭代器适配器。

reverse iterator

将迭代器的移动行为倒转。以尾到头的方向来处理序列中的元素。

stream iterator

将迭代器绑定到一个 stream 对象身上,绑定到 istream 对象为 istream_iterator,拥有输入能力。

绑定到 ostream 对象为 ostream_iterator,拥有输出能力。

应用于仿函数,function adapter

对返回值进行逻辑否定:not1, not2

对参数进行绑定:bind1st, bind2nd

用于函数合成:compose1, compose2

用于函数指针:ptr_fun

用于成员函数指针:mem_fun, mem_fun_ref

来源于  GitHub  整理

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTP—03

触发 GET 请求 1&#xff09;直接在浏览器 地址栏 输入 URL&#xff0c;此时构成了一个GET请求 2&#xff09;HTML中的一些特殊标签可能会触发 例如 img,a,link,script... 3&#xff09;通过Form表单触发&#xff08;Form本质也是一个HTML标签&#xff09; 4&#xff0…

C 数组:索引魔杖点化的数据星图阵列

一、数组 1.数组的概念 数组是⼀组相同类型元素的集合&#xff1b;从这个概念中我们就可以发现2个有价值的信息&#xff1a; 数组中存放的是1个或者多个数据&#xff0c;但是数组元素个数不能为0。数组中存放的多个数据&#xff0c;类型是相同的。 2.数组的分类 数组主要分为一…

苹果手机怎么清理空间:拯救你的拥挤手机

在数字生活的海洋中&#xff0c;我们的苹果手机就像一艘小船&#xff0c;载满了照片、应用、视频和各种下载的“宝贝”。随着时间的推移&#xff0c;这艘小船开始变得拥挤&#xff0c;航行速度放缓&#xff0c;甚至有时候直接卡壳。苹果手机怎么清理空间&#xff1f;是时候学会…

Ubuntu上如何部署Nginx?

环境&#xff1a; Unbuntu 22.04 问题描述&#xff1a; Ubuntu上如何部署Nginx&#xff1f; 解决方案&#xff1a; 在Ubuntu上部署Nginx是一个相对简单的过程&#xff0c;以下是详细的步骤指南。我们将涵盖安装Nginx、启动服务、配置防火墙以及验证安装是否成功。 1. 更新…

javaScriptBOM

1.1、BOM概述 1.1.1、BOM简介 BOM&#xff08;browser Object&#xff09;即浏览器对象模型&#xff0c;它提供了独立于内容而与浏览器窗口进行交互的对象&#xff0c;其核心对象是window。 BOM由一系列的对象构成&#xff0c;并且每个对象都提供了很多方法与属性 BOM缺乏标准…

Unity3D仿星露谷物语开发7之事件创建动画

1、目标 掌握事件通知的Publisher - Subscriber设计模式&#xff0c;并通过事件通知触发动画。 2、发布者/订阅者模式 首先&#xff0c;定义事件Event 然后&#xff0c;Publisher触发事件 最后&#xff0c;Subscriber订阅事件并进行处理 &#xff08;1&#xff09;创建动作…

点击展示大图预览

原文链接在table表格里能够实现&#xff0c;点击里面的图片实现大图预览的效果&#xff1b; 一、先安装viewer — 使用npm安装 npm install v-viewer --save二、在main.js中引入 import Viewer from v-viewer //点击图片大图预览 import viewerjs/dist/viewer.css Vue.use(…

安全算法基础(一)

安全算法是算法的分支之一&#xff0c;还的依靠大量的数学基础进行计算&#xff0c;本文参照兜哥的AI安全样本对抗&#xff0c;做一个简单的算法安全概括&#xff0c;从零学习。 最新的安全算法对于我们常规的攻击样本检测&#xff0c;效果是不理想的&#xff0c;为了探究其原…

aioice里面candidate固定UDP端口测试

环境&#xff1a; aioice0.9.0 问题描述&#xff1a; aioice里面candidate固定UDP端口测试 解决方案&#xff1a; /miniconda3/envs/nerfstream/lib/python3.10/site-packages/aioice import hashlib import ipaddress import random from typing import Optional import…

UE UMG 多级弹出菜单踩坑

多级弹出菜单 https://www.bilibili.com/video/BV1ub411J7nA 运行时添加 widget 的方法 create widget 然后 add child 到某个组件&#xff0c;比如 canvas 运行时修改 widget 位置的方法 set widget slot position 用起来没效果 怀疑是因为我没有传入 slot 但是暂时不知…

金碟中间件-AAS-V10.0安装

金蝶中间件AAS-V10.0 AAS-V10.0安装 1.解压AAS-v10.0安装包 unzip AAS-V10.zip2.更新license.xml cd /root/ApusicAS/aas# 这里要将license复制到该路径 [rootvdb1 aas]# ls bin docs jmods lib modules templates config domains …

linux-----网络编程

网络编程基础概念 IP地址&#xff1a;是互联网协议地址&#xff0c;用于在网络中唯一标识一台设备。在IPv4中&#xff0c;地址是32位的二进制数&#xff0c;通常以点分十进制表示&#xff0c;如192.168.1.1。IPv6是128位的地址&#xff0c;用于提供更多的地址空间&#xff0c;格…

基于蓝牙通信的手机遥控智能灯(论文+源码)

1.系统设计 灯具作为人们日常生活的照明工具为人们生活提供光亮&#xff0c;本次基于蓝牙通信的手机遥控智能灯设计功能如下&#xff1a; &#xff08;1&#xff09;用户可以通过蓝牙通信模块的作用下&#xff0c;在手机端遥控切换智能灯不同的工作模式&#xff1b; &#x…

阿里云百炼大模型生成贪吃蛇小游戏

阿里云百炼大模型生成贪吃蛇小游戏 为了在贪吃蛇游戏中添加背景音乐&#xff0c;我们可以使用Pygame的mixer模块。以下是修改后的代码&#xff0c;包含了背景音乐的加载和播放功能&#xff1a; 安装Pygame&#xff08;如果你还没有安装&#xff09;&#xff1a; pip install p…

Pytorch | 利用FGSM针对CIFAR10上的ResNet分类器进行对抗攻击

Pytorch | 利用FGSM针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集FGSM介绍算法原理算法特点应用场景局限性 FGSM代码实现FGSM算法实现攻击效果 代码汇总fgsm.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器&#xff1a; Pytorch | 从零构建AlexNet对CIFAR1…

3D Gaussian Splatting for Real-Time Radiance Field Rendering-简洁版

1. 研究背景与问题 传统的3D场景表示方法&#xff0c;如网格和点云&#xff0c;适合GPU加速的光栅化操作&#xff0c;但缺乏灵活性。而基于神经辐射场&#xff08;NeRF&#xff09;的表示方式&#xff0c;尽管质量高&#xff0c;但需要高成本的训练和渲染时间。此外&#xff0…

安卓环境配置及打开新项目教程,2024年12月20日最新版

1.去官网下载最新的Android Studio&#xff0c;网址&#xff1a;https://developer.android.com/studio?hlzh-cn 2.下载加速器&#xff0c;注册账号&#xff0c;开启加速器。网址&#xff1a;放在文末。 3.下载安卓代码&#xff0c;项目的路径上不能有中文&#xff0c;特别是…

不会心理描写,神态描写怎么办?

不会心理描写&#xff0c;神态描写怎么办&#xff1f; 文学创作&#xff0c;精微之处在于心理与神态之描绘。 一、夯实基础&#xff0c;积累素材。 欲使心理与神态描写生动&#xff0c;需先厚积薄发。博览群书&#xff0c;尤重经典之作。 “读万卷书&#xff0c;行万里路。…

【使用MCP协议连接本地和远程数据——以Claude的Windows客户端为例】

本博客内容主要是如何在Windows系统上为Claude客户端&#xff08;无需开通会员&#xff09;配置模型上下文协议(Model Context Protocol, MCP)服务器。 为什么选择 MCP&#xff1f; MCP 可帮助您在 LLM 之上构建代理和复杂的工作流程。LLM 经常需要与数据和工具集成&#xff0…

React:闭包陷阱产生和解决

在 React 中&#xff0c;闭包陷阱是一个常见的问题&#xff0c;尤其是在处理异步操作、事件处理器、或是定时器时。理解闭包的工作原理以及它在 React 中如何与状态和渲染交互&#xff0c;可以帮助你避免陷入一些常见的错误。 一、闭包陷阱的产生 1、什么是闭包陷阱&#xff1…