c++从入门到精通(四)--动态内存,模板与泛型编程
文章目录
- 动态内存
- 直接管理内存
- Shared_ptr类
- Unique_ptr
- Weak_ptr
- 动态数组
- allocator类
- 文本查询程序
- 模板与泛型编程
- 定义模板
- 函数模板
- 类模板
- 模板参数
- 成员模板
- 控制实例化
- 模板实参推断
- 重载与模板
- 可变参数模板
- 模板特例化
动态内存
c++中动态内存的管理是通过new和delete运算符来实现的,c++中定义了两种智能指针来管理动态对象:shared_ptr允许多个指针指向同一个对象,unique_ptr独占所指向的对象。weak_ptr指向shared_ptr所管理的对象
在如下三种情况下需要使用动态内存:
- 程序不知道自己所需多少对象-容器类
- 程序不知道所需对象的准确类型
- 程序需要在多个对象间共享数据
直接管理内存
- new返回一个指向该对象的指针
- 出于与变量初始化相同的原因,对动态分配的对象进行初始化通常是个好主意。
int *p1=new int;未定义,int *p2=new int();初始未0
int *p(new int(42));
- 使用auto自动推断元素类型
auto p1=new auto(obj);
- delete接受的指针必须是指向动态分配的内存的指针。释放一块非new分配的内存行为是未定义的。
Shared_ptr类
-
类似于vector,智能指针也是模板。
-
make_shared函数
shard_ptr<int> p=make_shared<int>(42);
,该函数和顺序容器类型的emplace成员类似,会用参数来构造给定类型的对象。 -
对shared_ptr拷贝的时候,每个shard_ptr都会记录有多少个其他的指针指向相同的对象。
-
shared_ptr基于引用计数的规则管理对象。
-
⭐共享数据,我们希望一个类的不同拷贝之间共享相同的元素。
class StrBlob{public:typedef std::vector<std::string>::size_type size_type;StrBlob();StrBlob(std::initializer_list<std::string> il);size_type size() const{return data->size();}bool empty() const{return data->empty();}//添加或删除元素void push_back(const std::string &t){data->push_back(t);}void pop_back();//元素访问std::string& front();std::string& back(); private:std::shared_ptr<std::vector<std::string>> data;//如果data[i]不合法,抛出一个异常void check(size_type i,const std::string &msg) const; } //构造函数 StrBlob::StrBlob(): data(make_shared<vector<string>>()){} StrBlob::StrBlob(initializer_list<string> il): data(make_shared<vector<string>>(il)){}void StrBlob::check(size_type i,const string &msg) const{if (i>=data->size())throw out_of_range(msg); }String& StrBlob::front(){check(0,"font on empty StrBlob");return data->front(); }string& StrBlob::back(){check(0,"back on empty StrBlob");return data->back(); } const String& StrBlob::front() const {check(0,"font on empty StrBlob");return data->front(); }const string& StrBlob::back() const {check(0,"back on empty StrBlob");return data->back(); }void StrBlob::pop_back(){check(0,"pop_back on empty Strblob");data->pop_back(); }
-
我们可以使用new返回的指针来初始化智能指针。接受指针参数的智能指针的构造函数是explicit的,我们只能使用直接初始化的方式初始化智能指针,
shared_ptr<ing> p1(new int(42));
-
出于相同的原因,一个返回shared_ptr的函数不能在其返回语句中隐式转换一个普通指针。我们可以使用这种写法:
return shared_ptr<int>(new int(42));
-
默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象
-
如果将一个shared_ptr绑定到一个普通指针,我们就不应该再使用内置指针来访问shared_ptr所指向的内存了。
-
不能使用get初始化另一个智能指针,或者为智能指针赋值。智能指针的get函数返回的是一个普通内置指针,使用get返回的指针的代码不能delete此指针,否则会导致二次delete(第一次delete是用get返回的指针初始化的智能指针,第二次delete是调用get成员函数的智能指针)。
-
reset和unique。如果有多个shared_ptr指向同一块区域,但是某个shared_ptr不希望改变共享区域的内容,而是选择重新开辟一块区域。我们可以使用如下方式:
if(!P.unique())p.reset(new string(*p));reset返回一个新的对象,新对象的引用计数+1,原对象的引用计数-1 *p+=newval;
-
使用智能指针在发生异时也可以防止内存不被释放。发生异常后会销毁智能指针导致引用计数递减,从而在合适的时候自动调用delete。
-
可以在使用智能指针的时候传递一个函数来替代析构函数,比如管理链接的智能指针,可以构建指向连接对象的智能指针,同时传递关闭连接的函数。当连接对象无任何引用时,自动调用关闭连接的函数。
Unique_ptr
-
某时刻只能有一个unique_ptr指向一个给定的对象。
-
当我们定义一个unique_ptr时,需要将其绑定到一个new返回的指针上。类似shared_ptr,初始化unique_ptr必须采用直接初始化形
-
可以调用release或者reset将指针的所有权从一个unique_ptr转移给另一个unique
unique_ptr<string> p2(p1.release()); unique_ptr<string> p3(new string("123")); p2.reset(p3.release());
-
虽然不能拷贝unique但是可以返回unique或者返回局部变量的拷贝(返回之后原本的那个就会被销毁,依旧可以保证只有一个指针指向某个区域)。因为编译器知道要返回的对象将要被销毁(可以保证之后只有一个指针指向某一个区域)。在这种情况下编译器会执行一个特殊的拷贝
unique_ptr<int> clone(int p) {return unique_ptr<int>(new int(p)); }unique_ptr<int> clone(int p){unique_ptr<int> ret(new int(p));return ret; }
-
我们可以为unique_ptr提供一个删除器,与shared_ptr不同,删除其作为unique_ptr类型的一部分
shared_ptr我们传递的函数(替代析构函数的函数)不是shared_ptr类型的一部分
unique_ptr<objT,delT> p(new objT,fcn); unique_ptr<connection, decltype(end_connection)*> p(&c, end_connection)
Weak_ptr
- 将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放(即使有weak_ptr指向对象还是会被释放)
- 创建weak_ptr需要用shared_ptr来 初始化它
- 我们不能使用weak_ptr直接访问对象,必须调用lock
//创建
auto p=make_shared<int>(43);
weak_ptr<ing> wp(p);//访问,最终还是使用shared_ptr访问,访问过程中引用计数+1,结束后-1
if(shared_ptr<ing> np =wp.lock()){}
动态数组
- 动态数组并不会分配一个数组类型的对象,返回的是元素类型的指针。不能对动态数组条用begin和end,也不能用范围for循环处理动态数组。
- 我们可以使用unique_ptr来管理new分配的数组.可以通过下标直接访问数组
- shared_ptr不直接支持管理动态数组,如果使用,必须提供自己定义的删除器.
- 用shared_ptr管理动态数组在访问元素的时候,shared_ptr没有定义下标运算,并且智能指针不支持算数运算。因此我们必须调用get得到普通指针。每次get的都是指向数组元素的首指针。
//创建
int *pia=new int[get_size()];
typedef int arrT[42];
int *pia new arrT;//未定义
int *pia new arrT();//初始值未0//释放必须用【】表明要释放的是一个动态数组。不能用类型别名
delete [] pia;//使用ptr管理
unique_ptr<int[]> up(new int[10]);
up.release();//自动用delete[]销毁//用shared管理。删除器(lambda表达式)接受一个指向数组的指针,删除此指针指向的动态数组
shared_ptr<int> sp(new int[10], [](int *p){deleate [] p;});
sp.reset();//使用lambda释放数组。
for(size_t i=0;i!=10;1++)*(sp.get()+i)=i;
allocator类
- 将内存分配和对象构造分离开。allocator分配的内存是未构造的,采用construct函数构造,额外的参数必须是与构造的对象的类型相匹配的合法的初始化器。
- 我们必须对每个构造的元素调用destory来销毁。销毁后我们可以重新构造元素,也可以还给系统(deallocate)
- allocator还定义了拷贝和填充未初始化内存的算法
//分配
allocator<string> alloc;
auto const p=alloc.allocate(n);//分配n个未初始化的sring,返回指向首元素的指针。//构造
auto q=p;
alloc.construct(q++);
alloc.construct(q++,10,'c');
alloc.construct(q++,"hji");//销毁
while(q!=p)alloc.destory(--q);//释放内存
alloc.deallocate(p,n);//拷贝
autp p=alloc.allocate(vi.size()*2);
auto q=unitialized_copy(vi.begin,vi.end(),p);//把迭代器指向的范围的元素拷贝到p所指向的动态内存空间。返回指向最后一个拷贝元素的指针
uninitialized_fill_n(q,vi.size(),42);//在q所指动态内存中填充vi.size个值为42的元素。
文本查询程序
见本人csdn文章–c++练手项目简单文本查询
模板与泛型编程
面向对象编程(OOP)和泛型编程都能处理在编写程序时不知道类型的情况。不同之处在于:OOP能处理类型在程序运行之前都未知的情况;而在泛型编程中,在编译时就能获知类型了。
模板是泛型编程的基础。一个模板就是一个创建类或函数的蓝图或者说公式。
定义模板
函数模板
模板中的函数参数是const的引用。函数体中的条件判断仅使用<比较运算。
template <typename T>
int compare(const T &v1,const T &v2)
{if (v1<v2) return -1;if (v2>v1) return 1;return 0;
}
**非类型参数:**非类型参数被一个用户提供的或编译器推断出的值所代替。这些值必须是常量表达式。
template<unsigned N,unsigned M> //N和M是非类型参数
int compare(const char (&p1)[N], const char (&p2)[M]){return strcmp(p1,p2);
}
compare("hi","mom");//编译器确定N=3,M=4,注意字符串字面值常量末尾会被插入一个空字符作为终结符。
一个非类型参数可以是一个整型,或者是一个指向对象或函数类型的指针或(左值)引用。绑定到非类型整型参数的实参必须是一个常量表达式。绑定到指针或引用非类型参数的实参必须具有静态的生存期。在模板定义内,模板非类型参数是一个常量值。在需要常量表达式的地方,可以使用非类型参数,例如,指定数组大小。
**inline和constexpr的函数模板:**函数模板可以声明为inline或constexpr的。
**模板编译:**当编译器遇到一个模板定义时,它并不生成代码。为了生成一个实例化版本,编译器需要掌握函数模板或类模板成员函数的定义。因此,与非模板代码不同,模板的头文件通常既包括声明也包括定义。
模板的设计者应该提供一个头文件,包含模板定义以及在类模板或成员定义中用到的所有名字的声明。模板的用户必须包含模板的头文件,以及用来实例化模板的任何类型的头文件。
保证传递给模板的实参支持模板所要求的操作,以及这些操作在模板中能正确工作,是调用者的责任。
类模板
编译器不能为类模板推断模 板参数类型,为了使用类模板,我们必须在模板名后的尖括号中提供额外信息,用来代替模板参数的模板实参列表。
类模板的成员函数本身是一个普通函数。但是,类模板的每个实例都有其自己版本的成员函数。因此,类模板的成员函数具有和模板相同的模板参数。因而,定义在类模板之外的成员函数就必须以关键字template开始,后接类模板参数列表。
默认情况下,对于一个实例化了的类模板,其成员只有在使用时才被实例化。
当我们使用一个类模板类型时必须提供模板实参,但这一规则有一个例外。在类模板自己的作用域中,我们可以直接使用模板名而不提供实参。
template <typename T> class Blob{
public:typedef T value_type;Blob& operator++();//没有使用Blob<T>&friend class BlobPtr<T>;//每个Blob实例将访问权限授权给用相同类型实例化的BlobPtr
}
template <typename T> int Blob<T>::func(int a){return 1;
}template <typename T>class C2{friend class Pal<T>;//c2的每个实例都将相同实例化的Pal声明为友元template <typename X> friend class Pal2;//pal2是一个模板,pal2的所有实例都是c2每个实例的友元,不需要前置声明,多对对。friend class pal3;//pal3是一个非模板类,它是c2所有实例的友元。
}
如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例。如果友元自身是模板,类可以授权给所有友元模板实例,也可以只授权给特定实例。
在新标准中,我们可以将模板类型参数声明为友元。friend Type;将访问权限授予用来实例化类模板的Type类。此时Foo将成为Bar的友元
**模板别名:**当我们定义一个模板类型别名时,可以固定一个或多个模板参数
typedef Blob<string> StrBlob;
template<typename T> using twin=pair<T,T>;
twin<string> authors;//==pair<string,string>template <typename T> using parNo=pair<T,unsigned>;
parNo<string> books;//==pair<string,unsigned>
**类模板的static成员:**模板类的每个static数据成员必须有且仅有一个定义。但是,类模板的每个实例都有一个独有的static对象
template <typename T> class Foo{public:static std::size_t count(){return ctr;}private:static std::size_t ctr;
}
template <typename T> size_t Foo<T>::ctr=0;
模板参数
模板参数于作用域:
- 模板内不能重用模板参数名字,如果B是模板参数名字,double B;是错误的语法。
模板声明:
- 一个特定文件所需要的所有模板的声明通常一起放置在文件开始位置,出现于任何使用这些模板的代码之前
在模板中使用类的类型成员
- c++默认通过作用域运算符访问的名字不是类型而是一个数据成员。如果我们想要使用模板类型参数的类型成员,就必须用typename T::value_type。这表示我们使用的是T类型的类型成员value_type而不是static成员。
函数模板和类模板的默认实参
- 与函数默认实参一样,对于一个模板参数,只有当它右侧的所有参数都有默认实参时,它才可以有默认实参。
- 我们如果使用一个类模板的全部默认实参,不能省略
<>
成员模板
一个类的成员函数可以是模板,成员模板不能是虚函数
普通类的成员模板:
class DebugDelete{public:DebugDelete(std::ostream &s =std::cerr): os(s){}template <typename T> void operator()(T *p) const{os<<"deleting unique_ptr"<<std::endl; delete *p;}private:std::ostream &os;
}double *p=new double;
DebugDelete d;
d(p);//编译器自动判断T为double类型
int *ip = new int;
DebugDelete()(ip);//编译器自动推断T未int类型//使用DebugDelete作为unique_ptr的删除器
unique_ptr<int,DebugDelete> p(new int,DebugDelete());//编译器自动判断Debug Delete的T为int
uneqie_ptr<string,DebugDelete> sp(new string, DebugDelete());编译器自动判断Debug Delete的T为string
**类模板的成员模板:**对于类模板,我们也可以为其定义成员模板。类和成员各自有自己的、独立的模板参数。
当我们在类模板外定义一个成员模板时,必须同时为类模板和成员模板提供模板参数列表。类模板的参数列表在前,后跟成员自己的模板参数列表
template <typename T> class Blob{template <typename IT> Blob(IT b,IT e);
}
templage <typename T>
template <typename IT>
Blob<T>::Blob(IT b,IT e):data(std::make_shared<std::vector<T>>(b,e))
控制实例化
- 在大型系统中,实例化相同参数的模板造成的额外开销可能非常严重,我们可以通过显示实例化来避免这种开销。
- 当编译器遇到extern模板声明时,它不会再本文件中生成实例化代码 。
- 实例化定义会实例化所有成员。即使我们不使用某个成员,它也会被实例化。因此,我们用来显式实例化一个类模板的类型,必须能用于模板的所有成员。
extern template class Blob<string>;
extern template int compare (const int&, const int&);
Blob<string> sa1,sa2;//实例化出现在其他位置
Blob<int> a1={1,2,3}//在本文件中实例化。//实例化定义文件
template int compare(const int&, const int&);
template class Blob<string>;
模板实参推断
-
算数类型转换,派生类向基类的转换,用户定义的转换都不能应用于函数模板。
-
函数模板形参如果是引用,数组不会被转换为指针,此时不同大小的数组类型是不匹配的。
-
我们可以定义用户指定返回类型的函数模板
T1 sum(T2,T3)
,用户提供显示模板实参的方式于定义类模板实例的方式相同sum<long>(i,lng)
,此调用显式指定T1的类型。而T2和T3的类型则由编译器从i和lng的类型推断出来。 -
显示指出模板类型参数可以进行正常的类型转换
long lng; compare(lng,1024);//错误,模板参数不匹配 lng和1024类型不匹配 compare<long>(lng,1024);//正确,1024被转换为long类型
-
尾置返回类型,如果函数的返回类型依赖于模板实参的类型,我们可以用尾置返回类型加decltype。编译器遇到函数的参数列表前beg是不存在的,所以只能用尾置返回。
template <typename It> auto func(It beg)->decltype(*beg)
-
decltype(*beg)返回元素类型的引用类型,我们可以用remove_reference::type脱去引用,剩下元素类型本身.
template <typename T> auto fcn2(T *beg)->typename remove_reference<decltype(*beg)>::type//我们需要声明typename表示type是一个类型。type是一个类的成员,该类依赖于一个模板参数。 {return *beg; }
-
标准库提供了一些类型转换模板,我们可以利用这些模板得到转换后的类型。
- 我们使用函数模板初始化函数指针时,编译器根据指针的类型推断模板实参。如果存在重载版本,编译器无法确定模板实参类型,此时我们可以使用显示模板实参来消除歧义,
template <typename T> int compare(const T&,const T&);
int (*p)(const int&,const int&)=compare;//T为intvoid func(int(*)(const string &));
void func(int(*)(const int &));
func(compare);//歧义,无法确定compare的模板实参是int还是stringfunc(conpare<ing>);//显示模板实参消除歧义。传递compare(const int&);
模板实参推断和右值引用:
-
一般而言我们不能将一个左值引用绑定到右值引用参数,但是有两个例外(这也是标准库设施move的实现基础)。
-
例外一:我们将左值绑定给函数右值引用参数时候,右值引用指向模板类型参数T&&时候,编译器推断模板类型参数为实值的左值引用类型(T 为int,我们传递int左值时,编译器推断T的类型为int &)。这表明我们开可以通过模板类型参数间接定义引用的引用。
-
例外二:如果我们间接建一个引用的引用,则这些引用形成了“折叠”。
X&&、X&&&和X&&&都折叠成类型X&
类型X&&&&折叠成X&&
-
例外1和2组合在一起就会产生下面奇妙的效果:
总结,如果如果一个函数参数是一个指向模板类型参数的右值引用(如,T&&),则它可以被绑定到一个左值。如果实参是一个左值,则推断出的模板实参类型将是一个左值引用,且函数参数将被实例化为一个(普通)左值引用参数(T&)
-
接受右值引用参数的模板函数可能出现不同的程序行为。如果我们提供右值引用,则T t=val,是val的拷贝,改变t不会改变val。如果我们提供左值引用T t=val,t是val的引用,改变t会改变val。因此我们一般需要重载接受右值引用参数的模板函数
template <typename T> void f(T &&)
接受右值引用template <typename T> void f(const T&)
接受左值引用和const右值。接受const右值,T是const引用。 -
有了上面的了解后,我们就可以探究std::move函数了,该函数用remove_reference保证返回值是右值引用,用static_case把左值引用转换为右值引用==(从一个左值static_cast到一个右值引用是允许的)。虽然不能隐式地将一个左值转换为右值引用,但我们可以用static_cast显式地将一个左值转换为一个右值引用。
因此我们可以直接使用static_case转化右值,但使用标准库的move函数容易的多,并且统一使用std::move是的我们在程序中查找潜在的截断左值代码变得很容易。
转发:
使用forward来保持传递给模板类型参数的实参属性。如果实参是一个右值,则T1是一个普通类型,forward将返回T1&&,结果是一个右值引用。如果实参是一个左值,T1是一个左值引用类型,forward返回的类型是一个左值引用,结果是一个左值引用。
template <typename F,typename T1,typename T2>
void fun(F f,T1 &&t1,T2 &&t2){f(std::forward<T2>(t2),std::forward<T1>(t1));
}
重载与模板
- 模板函数重载的时候编译器优先选择精确匹配的函数模板(不需要类型转换),如果都是精确匹配的,再选择更特例化的模板==(例如const T&本质上可以用于任何类型,包括指针类型,而T*只能用于指针类型,因此编译器会选择T*为函数形参的模板函数)==
- 实参从数组类型或函数类型转换成对应的指针类型是精确匹配的。
- 在定义任何函数之前,记得声明所有重载的函数版本。这样就不必担心编译器由于未遇到你希望调用的函数而实例化一个并非你所需的版本(通过模板实例化出并不需要的版本)。
可变参数模板
- 编译器会通过函数调用时传递的实参数量自动推断出模板参数包的类型和数量以及函数参数包的数量。
- 调用sizeof…运算符可以得到函数参数的数目或类型参数的数目(模板类型参数)
//Args是模板类型参数包,rest是函数参数包
//Args表示零个或多个函数类型参数
//rest表示零个或多个函数参数
template <typename T,typename... Args>
void foo(const T&, const Args& ... rest);cout<<sizeof...(Args)<<endl;cout<<sizeof...(res)<<endl;
-
我们可以使用initializer_list来定义接收可变参数的函数,但是这些参数必须具有相同的类型。我们可以编写可变类型参数的模板作为接受可变参数的函数(这些参数类型不同)
**包扩展:**我们在参数包后面用…来展开包。注意debug_rep(rest)…和debug_rep(rest…)的扩展含义不同,后者表示在debug_rep函数内扩展rest参数
**转发参数包:**我们可以组合使用可变参数模板与forward机制来编写函数,实现将其实参不变地传递给其他函数。
模板特例化
-
在某些情况下,通用模板的定义对特定类型是不适合的。当我们不能(或不希望)使用模板版本时,可以定义类或函数模板的一个特例化版本。
-
一个特例化版本本质上是一个实例,而非函数名的一个重载版本。
-
模板及其特例化版本应该声明在同一个头文件中。所有同名模板的声明应该放在前面,然后是这些模板的特例化版本。
//模板为
template <typename T>int compare(const T&, const T&);
//我们想要特例化的模板中T类型为 char* const。即底层const指针。
template<>
int compare(const char* const & p1. );//指向const类型的const指针。
特例化类模板:
-
特例化类模板,我们必须在原模板定义所在的命名空间特例化,以特列化hash类模板来计算我们自定义类型的hash时:
-
与函数模板不同,类模板的特例化不必为所有模板参数提供实参。我们可以只指定一部分而非所有模板参数,或是参数的一部分而非全部特性。一个类模板的部分特例化(partial specialization)本身是一个模板
-
部分特例化版本的模板参数列表是原始模板的参数列表的一个子集或者是一个特例化版本。在本例中,特例化版本的模板参数的数目与原始模板相同,但是类型不同。两个特例化版本分别用于左值引用和右值引用类型
特例化成员而不是类:
-
我们可以只特例化特定成员函数而不是特例化整个模板。例如,如果Foo是一个模板类,包含一个成员Bar,我们可以只特例化该成员:
相关文章:
c++从入门到精通(四)--动态内存,模板与泛型编程
文章目录 动态内存直接管理内存Shared_ptr类Unique_ptrWeak_ptr动态数组allocator类文本查询程序 模板与泛型编程定义模板函数模板类模板模板参数成员模板控制实例化 模板实参推断重载与模板可变参数模板模板特例化 动态内存 c中动态内存的管理是通过new和delete运算符来实现的…...
反病毒反垃圾U-Mail邮件系统从容应对
在数字化时代,电子邮件依然是企业沟通的核心工具。然而,垃圾邮件、病毒邮件和钓鱼邮件等安全威胁,如同潜伏在暗处的幽灵,随时可能侵蚀企业的信息安全。因此,企业需要构建一套严密的邮件安全防御体系,才能有…...
第一天的尝试
目录 一、每日一言 二、练习题 三、效果展示 四、下次题目 五、总结 一、每日一言 可能我们会失败,但是人生容错率挺高的,你没必要活成万众瞩目的样子,我们也想要这样的生活,但是我们要付出努力和时间,所以当情绪来…...
GUI图形化演示
概述 Swing组件通常被称为“轻量级组件”,他完全由Java编写,不依赖操作系统语言,他的类继承关系如下: Java.lang.Object->Java.awt.Component->Java.awt.Container->Javax.swing.JCompoment JCompoent是swing组件存放的位置&…...
Day118 | 灵神 | 二叉树 | 删点成林
Day118 | 灵神 | 二叉树 | 删点成林 1110.删点成林 1110. 删点成林 - 力扣(LeetCode) 思路: 最直接的思路就是看当前结点的值是不是在要删除的列表中,在的话删除当前结点并把左右孩子加入res中 很可惜这样是错的,…...
每周靶点:IL31、B7H3及文献分享
本期精选了《炎症中的“瘙痒”细胞因子IL31》《免疫检查点分子B7H3》《重组抗体:抗体测序和人工智能助力抗体设计》《文献分享:用于HER2特异性递送的单链Fab衍生药物偶联物》《文献分享:全长抗体、片段和双特异性格式的可开发性的比较研究》五…...
机器学习笔记——特征工程
大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本笔记介绍机器学习中常见的特征工程方法、正则化方法和简要介绍强化学习。 文章目录 特征工程(Fzeature Engineering)1. 特征提取ÿ…...
麒麟v10 部署 MySQL 5.6.10 完整步骤
需要包的私信我 一、安装依赖(Perl环境) # 在线安装依赖 yum -y install perl perl-devel# 离线安装(需提前下载好rpm包) mkdir /data/ybn/soft/pre yum install --downloadonly --downloaddir/data/ybn/soft/pre perl perl-dev…...
digitalworld.local: DEVELOPMENT靶场
digitalworld.local: DEVELOPMENT 来自 <https://www.vulnhub.com/entry/digitalworldlocal-development,280/> 1,将两台虚拟机网络连接都改为NAT模式 2,攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.18…...
高等数学基础(梯度下降法求函数的最小值)
梯度下降法, 一般是寻找函数极小值最常用的优化方法. 当目标函数时凸函数时, 梯度下降时全局解, 但是一般情况没办法保证是全局最优的. 通常在求最优解时, 首先会设定好步长大小进行调整, 按照上述方法对参数进行调整后就会逼近一个极小值 设函数 f ( x ) f(x) f(x)为一元连续函…...
【AI News | 20250515】每日AI进展
AI Repos 1、helix-db 专用于RAG以及AI应用的一款高性能图向量数据库:HelixDB,比Neo4j快1000倍,比TigerGraph快100倍,向量搜索性能和Qdrant相当。原生支持图形和矢量数据类型,比较适合RAG和AI应用,像知识图…...
大数据架构选型分析
选择依据 1.业务需求与技术要求 用户需要根据自己的业务需求来选择架构,如果业务对于Hadoop、Spark、Strom等关键技术有强制性依赖,选择Lambda架构可能较为合适;如果处理数据偏好于流式计算,又依赖Flink计算引擎,那么…...
C++中多重继承下的虚表结构
在 C 的多重继承 中,虚表(vtable)结构会变得更加复杂。 一、基础回顾:单继承下的虚表结构 类中含有虚函数 → 编译器生成虚表(每类一张);每个对象有一个隐藏的虚表指针(vptr&#x…...
安全巡检清单
安全巡检报告清单 引言 安全巡检是保障信息系统稳定运行和数据安全的关键环节。通过周期性的状态检查、安全扫描、日志分析和补丁管理,可以及时发现并修复潜在的安全隐患和漏洞,确保网络设备、服务器、操作系统及应用系统的高可用性和安全性。本清单旨…...
【redis】redis常见数据结构及其底层,redis单线程读写效率高于多线程的理解,
redis常用数据结构及底层 string字符串、list链表、set无序集合、zset有序集合、hash哈希 1.string 底层结构是SDS简单动态字符串 struct sdshdr {int len; // 已用长度(字符串实际长度)int free; // 剩余可用空间char buf[]; // 数组&#…...
Redis6为什么引入了多线程?
大家好,我是锋哥。今天分享关于【Redis6为什么引入了多线程?】面试题。希望对大家有帮助; Redis6为什么引入了多线程? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis 6 引入多线程的主要目的是提升性能…...
使用GmSSL v3.1.1实现SM2证书认证
1、首先使用gmssl命令生成根证书、客户端公私钥,然后使用根证书签发客户端证书; 2、然后编写代码完成认证功能,使用根证书验证客户端证书是否由自己签发,然后使用客户端证书验证客户端私钥对随机数的签名是否正确。 第一部分生成根…...
Spring MVC 接口的访问方法如何设置
RequestMapping 是 Spring 框架中用于映射 HTTP 请求到控制器方法的注解。它支持以下 HTTP 方法访问类型,通过 method 属性指定: GET:用于获取资源POST:用于提交数据PUT:用于更新资源DELETE:用于删除资源PA…...
虚拟网络编辑器
vmnet1 仅主机模式 hostonly 功能:虚拟机只能和宿主机通过vmnet1通信,不可连接其他网络(包括互联网) vmnet8 地址转换模式 NAT 功能:虚拟机可以和宿主通过vmnet8通信,并且可以连接其他网络,但是…...
【hadoop】Flume日志采集系统的安装部署
一、Flume安装与配置 步骤: 1、使用XFTP将Flume安装包apache-flume-1.9.0-bin.tar.gz发送到master机器的主目录。 2、解压安装包: tar -zxvf ~/apache-flume-1.9.0-bin.tar.gz 3、修改文件夹的名字,将其改为flume,或者创建软…...
Kafka快速安装与使用
引言 这篇文章是一篇Ubuntu(Linux)环境下的Kafka安装与使用教程,通过本文,你可以非常快速搭建一个kafka的小单元进行日常开发与调测。 安装步骤 下载与解压安装 首先我们需要下载一下Kafka,这里笔者采用wget指令: wget https:…...
C# 实现雪花算法(Snowflake Algorithm)详解与应用
在现代分布式系统中,生成全局唯一的标识符(ID)是一个非常重要的问题。随着微服务架构和分布式系统的普及,传统的单机数据库生成 ID 的方式已无法满足高并发和高可用的需求。为了解决这个问题,Twitter 提出了 雪花算法&…...
中间件-MQ常见问题
MQ常见问题 消息丢失消息会在哪些环节丢失应对机制 消息的顺序性消息幂等消息积压的处理 消息丢失 消息会在哪些环节丢失 网络传输环节:生产者发送消息到broker,broker中master同步消息给slave,consumer消费消息,这3个环节都是跨…...
Redis学习打卡-Day2-缓存更新策略、主动更新策略、缓存穿透、缓存雪崩、缓存击穿
缓存更新策略 对于低一致性需求:使用内存淘汰机制。例如店铺类型的查询缓存。对于高一致性需求:主动更新,并以超时剔除作为兜底方案。例如店铺详情查询的缓存。 主动更新策略(缓存读写策略) 1. Cache Aside Pattern&…...
Git - 1( 14000 字详解 )
一: Git 初识 1.1 提出问题 在工作或学习中,我们常常会面临文档管理的问题,尤其是在编写各种文档时。为了防止文档丢失或因更改失误而无法恢复,我们常常会创建多个版本的副本,例如:“报告-v1”、“报告-v…...
搭建Centos环境安装禅道
关于禅道: 禅道项目管理软件,将CMMI模型的要求有机融合到项目管理各个过程,支持Scrum、瀑布、看板和狭义IPD并支持融合使用。禅道项目管理软件功能强大,集产品管理、项目管理、质量管理、文档管理、组织管理和事务管理于一体&…...
语音识别——语音转文字
SenseVoiceSmall阿里开源大模型,SenseVoice 是具有音频理解能力的音频基础模型,包括语音识别(ASR)、语种识别(LID)、语音情感识别(SER)和声学事件分类(AEC)或…...
语音识别——声纹识别
通过将说话人的声音与数据库中的记录声音进行比对,判断说话人是否为数据库白名单中的同一人,从而完成语音验证。目前,3D-Speaker 声纹验证的效果较为出色。 3D-Speaker 是一个开源工具包,可用于单模态和多模态的说话人验证、说话…...
c++作业整理2
直接访问就是直接利用变量的地址直接进行访问。 答案:T 解析:直接访问通过变量名(实际对应内存地址)访问数据,与间接访问(通过指针)相对。 char *s"C Language"; 表示 s 是一个指向字…...
无人机屏蔽与滤波技术模块运行方式概述!
一、模块运行方式 1. 电磁屏蔽模块 动态频段干扰:通过发射与无人机通信频段(如2.4GHz、5.8GHz、GPS频段等)同频的强干扰信号,切断无人机与遥控器、图传设备间的通信链路,实现迫降或返航功能。例如便携式屏蔽器通过…...
兼顾长、短视频任务的无人机具身理解!AirVista-II:面向动态场景语义理解的无人机具身智能体系统
作者:Fei Lin 1 ^{1} 1, Yonglin Tian 2 ^{2} 2, Tengchao Zhang 1 ^{1} 1, Jun Huang 1 ^{1} 1, Sangtian Guan 1 ^{1} 1, and Fei-Yue Wang 2 , 1 ^{2,1} 2,1单位: 1 ^{1} 1澳门科技大学创新工程学院工程科学系, 2 ^{2} 2中科院自动化研究所…...
深入探索 OpenCV:从实时视频流到图像处理的实战指南
引言 在当今数字化时代,计算机视觉技术正逐渐成为推动科技发展的核心力量之一。从自动驾驶汽车到智能家居设备,从医疗影像诊断到工业自动化,计算机视觉的应用无处不在。而 OpenCV(Open Source Computer Vision Library࿰…...
Linux线程控制
POSIX线程库 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的要使用这些函数库,要通过引入头文 <pthread.h>链接这些线程函数库时要使用编译器命令的“-lpthread”选项 创建线程 功能:创建⼀个新…...
软件设计师考试《综合知识》设计模式之——工厂模式与抽象工厂模式考点分析
软件设计师考试《综合知识》工厂模式与抽象工厂模式考点分析 1. 分值占比与考察趋势(75分制) 年份题量分值占总分比例核心考点2023111.33%抽象工厂模式适用场景2022222.67%工厂方法 vs 抽象工厂区别2021111.33%工厂方法模式结构2020111.33%简单工厂模式…...
携程旅行 酒店详情 token1004 分析 phantom-token
声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 部分python代码 这个网站有一个坑&am…...
QT——概述
<1>, Qt概述 Qt 是⼀个 跨平台的 C 图形⽤⼾界⾯应⽤程序框架 Qt ⽀持多种开发⼯具,其中⽐较常⽤的开发⼯具有:Qt Creator、Visual Studio、Eclipse. 一,Qt Creator 集成开发环境(IDE) Qt Creator 是⼀个轻量…...
uniapp-vue3项目中引入高德地图的天气展示
前言: uniapp-vue3项目中引入高德地图的天气展示 效果: 操作步骤: 1、页面上用定义我们的 当前天气信息:<view></view> 2、引入我们的map文件 <script setup>import amapFile from ../../libs/amap-wx.js …...
最新版VSCode通过SSH远程连接Ubuntu 16.04等旧版Linux的方法
根据官方文档Remote Development FAQ - Can I run VS Code Server on older Linux distributions?,自Visual Studio Code 1.99起,VSCode Remote - SSH Server由于运行库依赖更新,会无法连接到旧版Linux发行版上。但是好在官方在文档中还给了…...
Unity碰撞检测:射线与胶囊体投射/Layer(层)、LayerMask(遮罩层)
一、Physics碰撞检测 1.Physics.Raycast射线投射 Physics.Raycast 是 Unity 中用于执行射线检测(Raycasting)的方法。它允许你从一个点沿特定方向发射一条无形的“射线”,并检查这条射线是否与场景中的任何碰撞体相交。这个功能非常有用&am…...
浪潮云边协同:赋能云计算变革的强力引擎
在数字化浪潮以排山倒海之势席卷全球的当下,第五届数字中国建设峰会在福州盛大开幕。这场以“创新驱动新变革,数字引领新格局”为主题的行业盛会,宛如一座汇聚智慧与力量的灯塔,吸引了国内外众多行业精英齐聚一堂,共同…...
“傅里叶变换算法”来检测纸箱变形的简单示例
为了创建一个具有科技质感且能动态展示结果的纸箱变形检测傅里叶变换网页,下面将分别更新 HTML、CSS 和 JavaScript 文件。以下是更新后的代码: 1. HTML 文件 (index.html) <!DOCTYPE html> <html lang"zh-CN"> <head><…...
【SPIN】用Promela验证顺序程序:从断言到SPIN实战(SPIN学习系列--2)
你写了一段自认为“天衣无缝”的程序,但如何确保它真的没有bug?靠手动测试?可能漏掉边界情况;靠直觉?更不靠谱!这时候,Promela SPIN组合就像程序的“显微镜”——用形式化验证技术,…...
如何卸载并重新安装 Mozilla Firefox 浏览器
如果你在 Windows 上遇到现有的 Mozilla FireFox 安装问题,以下是重新安装 FireFox 的步骤。这可以帮助用户解决由于某些扩展或设置问题,或者不小心下载了令人讨厌的广告软件而导致的问题。虽然现在使用 Firefox 浏览器的用户在渐渐沦为小众群体,但是 Firefox 浏览器依然是最…...
Linux 后台运行的方法
Linux 后台运行的两种方法:screen 和 nohup 使用指南 如有错误,敬请指正 方法一:使用 screen 管理后台任务(推荐) 🔹 安装(如未安装) sudo apt install screen # Ubuntu/Debian …...
《无限暖暖》画质测评
《无限暖暖》作为一款采用虚幻5引擎打造的多平台畅玩、高自由度换装探索类RPG游戏,凭借其精美的画面、沉浸式操作和暖暖美丽坚毅的人设吸引了大量玩家。 在其中玩家可以通过做各样任务收集美好并感受到丰富的人生体验,暖暖所在的世界里有超多的NPC可以互…...
websocket简介与基本使用
websocket是什么 WebSocket 是一种基于 TCP 的全双工通信协议,允许客户端和服务器之间建立持久连接,实现实时、双向的数据传输。它是 HTTP 协议的补充,专为低延迟、高效率的实时通信设计。 核心特点 特性说明全双工通信客户端和服务器可以同时…...
面试题:请解释Java中的垃圾回收机制(Garbage Collection, GC),并讨论不同的垃圾回收算法及其优缺点
Java垃圾回收机制(GC) Java的垃圾回收机制负责自动管理内存,回收不再使用的对象以释放内存空间。GC通过以下步骤实现: 标记(Marking) :识别哪些对象是可达的,哪些是不可达的。清除…...
解决 Ubuntu 22.04 安装后启动卡死问题
最近在一台 PC 上安装了 Ubuntu 22.04 系统,但发现系统启动时出现问题:屏幕上出现一个旋转的小圈,旋转片刻后停止,系统无法正常进入桌面环境。经过一番排查,我找到了一种有效的解决方法,通过进入恢复模式并…...
线程的两种实现方式
线程的两种实现方式——内核支持线程(kernal Supported Thread, KST), 用户级线程(User Level Thread, ULT) 1. 内核支持线程 顾名思义,内核支持线程即为在内核支持下的那些线程,它们的创建&am…...
Python Bug 修复案例分析:asyncio 事件循环异常引发的程序崩溃 两种修复方法
在 Python 异步编程的工作中,asyncio库为我们提供了高效处理并发任务的强大工具。然而,asyncio在使用过程中也可能因为一些细节处理不当而引发 Bug。下面,我们就来深入分析一个因asyncio事件循环异常导致程序崩溃的典型案例。兴趣的友友可以借…...