当前位置: 首页 > article >正文

c++从入门到精通(四)--动态内存,模板与泛型编程

文章目录

    • 动态内存
      • 直接管理内存
      • Shared_ptr类
      • Unique_ptr
      • Weak_ptr
      • 动态数组
      • allocator类
      • 文本查询程序
    • 模板与泛型编程
      • 定义模板
        • 函数模板
        • 类模板
        • 模板参数
        • 成员模板
        • 控制实例化
      • 模板实参推断
      • 重载与模板
      • 可变参数模板
      • 模板特例化

动态内存

c++中动态内存的管理是通过new和delete运算符来实现的,c++中定义了两种智能指针来管理动态对象:shared_ptr允许多个指针指向同一个对象,unique_ptr独占所指向的对象。weak_ptr指向shared_ptr所管理的对象

在如下三种情况下需要使用动态内存:

  1. 程序不知道自己所需多少对象-容器类
  2. 程序不知道所需对象的准确类型
  3. 程序需要在多个对象间共享数据

直接管理内存

  • 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运算符来实现的…...

C盘清理秘籍:快速提升系统性能

C盘清理的重要性 C盘作为系统盘&#xff0c;存储着操作系统和关键程序文件。随着使用时间的增加&#xff0c;C盘空间会逐渐被占用&#xff0c;导致系统运行缓慢、程序启动延迟等问题。定期清理C盘可以有效提升系统性能&#xff0c;延长硬盘寿命。 清理临时文件 Windows系统在…...

从 Vue3 回望 Vue2:组件设计升级——Options API vs Composition API

文章目录 从 Vue3 回望 Vue2&#xff1a;组件设计升级——Options API vs Composition API1、组件范式&#xff1a;框架设计思想的投影2、Vue2&#xff1a;Options API 的结构与局限结构清晰&#xff1a;新手友好、职责分明核心痛点&#xff1a;逻辑分散&#xff0c;难以聚合复…...

寻找两个正序数组的中位数 - 困难

************* Python topic: 4. 寻找两个正序数组的中位数 - 力扣&#xff08;LeetCode&#xff09; ************* Give the topic an inspection. Do the old topic will give you some new sparks. Before that, I do some really good craetive things about my logo. …...

国产密码新时代!华测国密 SSL 证书解锁安全新高度

在数字安全被提升到国家战略高度的今天&#xff0c;国产密码算法成为筑牢网络安全防线的关键力量。华测国密SSL证书凭借其强大性能与贴心服务&#xff0c;为企业网络安全保驾护航&#xff0c;成为符合国家安全要求的不二之选&#xff01;​ 智能兼容&#xff0c;告别浏览器适配…...

【金仓数据库征文】从云计算到区块链:金仓数据库的颠覆性创新之路

目录 一、引言 二、金仓数据库概述 2.1 金仓数据库的背景 2.2 核心技术特点 2.3 行业应用案例 三、金仓数据库的产品优化提案 3.1 性能优化 3.1.1 查询优化 3.1.2 索引优化 3.1.3 缓存优化 3.2 可扩展性优化 3.2.1 水平扩展与分区设计 3.2.2 负载均衡与读写分离 …...

互联网大厂Java求职面试:AI与大模型集成的云原生架构设计

互联网大厂Java求职面试&#xff1a;AI与大模型集成的云原生架构设计 引言 在现代互联网企业中&#xff0c;AI与大模型技术的应用已经成为不可或缺的一部分。特别是在短视频平台、电商平台和金融科技等领域&#xff0c;如何高效地将大模型集成到现有的云原生架构中是一个巨大…...

股指期货套期保值怎么操作?

股指期货套期保值就是企业或投资者通过持有与其现货市场头寸相反的期货合约&#xff0c;来对冲价格风险的一种方式。换句话说&#xff0c;就是你在股票市场上买了股票&#xff08;现货&#xff09;&#xff0c;担心股价下跌会亏钱&#xff0c;于是就在期货市场上卖出相应的股指…...

基于IBM BAW的Case Management进行项目管理示例

说明&#xff1a;使用IBM BAW的难点是如何充分利用其现有功能根据实际业务需要进行设计&#xff0c;本文是示例教程&#xff0c;因CASE Manager使用非常简单&#xff0c;这里重点是说明如何基于CASE Manager进行项目管理&#xff0c;重点在方案设计思路上&#xff0c;其中涉及的…...

黑马k8s(七)

1.Pod介绍 查看版本&#xff1a; 查看类型,这里加s跟不加s没啥区别&#xff0c;可加可不加 2.Pod基本配置 3.镜像拉去策略 本地没有这个镜像&#xff0c;策略是Never&#xff0c;启动失败 查看拉去策略&#xff1a; 更改拉去策略&#xff1a; 4.启动命令 运行的是nginx、busv…...

九、HQL DQL七大查询子句

作者&#xff1a;IvanCodes 日期&#xff1a;2025年5月15日 专栏&#xff1a;Hive教程 Apache Hive 的强大之处在于其类 SQL 的查询语言 HQL&#xff0c;它使得熟悉 SQL 的用户能够轻松地对存储在大规模分布式系统&#xff08;如 HDFS&#xff09;中的数据进行复杂的查询和分析…...

基于中心点预测的视觉评估与可视化流程

基于中心点预测的视觉评估与可视化流程 基于中心点预测的视觉评估与可视化流程一、脚本功能概览二、可视化与评分机制详解1. 真实框解析2. 调用模型处理帧3. 预测中心点与真实值的对比4. 打分策略5. 图像可视化三、目录结构要求四、运行方式五、应用场景与拓展思路六、总结七,…...

RTSP 播放器技术探究:架构、挑战与落地实践

RTSP 播放器为什么至今无法被淘汰&#xff1f; 在实时视频传输领域&#xff0c;RTSP&#xff08;Real-Time Streaming Protocol&#xff09;作为最基础、最常见的协议之一&#xff0c;至今依然被广泛用于监控设备、IP Camera、视频服务器等设备中。然而&#xff0c;要构建一个稳…...

实验5 DNS协议分析与测量

实验5 DNS协议分析与测量 1、实验目的 了解互联网的域名结构、域名系统DNS及其域名服务器的基本概念 熟悉DNS协议及其报文基本组成、DNS域名解析原理 掌握常用DNS测量工具dig使用方法和DNS测量的基本技术 2、实验环境 硬件要求&#xff1a;阿里云云主机ECS 一台。 软件要…...

编程日志5.8

二叉树练习题 1.965. 单值二叉树 - 力扣(LeetCode) /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) :…...

【鸿蒙开发】性能优化

语言层面的优化 使用明确的数据类型&#xff0c;避免使用模糊的数据类型&#xff0c;例如ESObject。 使用AOT模式 AOT就是提前编译&#xff0c;将字节码提前编译成机器码&#xff0c;这样可以充分优化&#xff0c;从而加快执行速度。 未启用AOT时&#xff0c;一边运行一边进…...

2025-05-13 学习记录--Python-循环:while循环 + while-else循环 + for循环 + 循环控制

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、循环 ⭐️ &#xff08;一&#xff09;、while循环 &#x1f36d; 初始条件设置 -- 通常是重复执行的 计数器while 条件(判…...

Vue3学习(组合式API——生命周期函数基础)

目录 一、Vue3组合式API中的生命周期函数。 &#xff08;1&#xff09;各阶段生命周期涉及函数简单介绍。 <1>创建挂载阶段的生命周期函数。 <2>更新阶段的生命周期函数。 <3>卸载阶段的生命周期函数。 <4>错误处理的生命周期函数。 &#xff08;2&…...

全面指南:Xinference大模型推理框架的部署与使用

全面指南:Xinference大模型推理框架的部署与使用 Xinference(Xorbits Inference)是一个功能强大的分布式推理框架,专为简化各种AI模型的部署和管理而设计。本文将详细介绍Xinference的核心特性、版本演进,并提供多种部署方式的详细指南,包括本地部署、Docker-Compose部署…...

计量——检验与代理变量

1.非嵌套模型的检验 1Davidson-Mackinnon test 判断哪个模型好 log&#xff08;y&#xff09;β0β1x1β2x2β3x3u log&#xff08;y&#xff09;β0β1log&#xff08;x1&#xff09;β2log&#xff08;x2&#xff09;β3log&#xff08;x3&#xff09;u 1.对log&#xff…...

Cocos Creator 3.8.5 构建依赖环境配置文档

Cocos Creator 3.8.5 构建依赖环境配置文档 文章目录 Cocos Creator 3.8.5 构建依赖环境配置文档✅ 构建依赖汇总表✅ 构建平台配置说明&#x1f449; Windows 构建&#x1f449; Android 构建 ✅ 推荐构建环境组合&#xff08;稳定&#xff09;✅ 常见问题提示 适用于打包 An…...

实验五:以太网UDP全协议栈的实现(通过远程实验系统)

文章目录 FPGA以太网:从ARP到UDP的完整协议栈一、引言二、核心模块详解1. ARP协议处理模块1.1 `arp_cache`:ARP缓存模块1.2 `arp_tx`:ARP请求与应答发送模块1.3 `arp_rx`:ARP接收与解析模块2. MAC层处理模块2.1 `mac_layer`:MAC层顶层模块2.2 `mac_tx_mode`:MAC发送模式选…...

HTML-实战之 百度百科(影视剧介绍)

本系列可作为前端学习系列的笔记&#xff0c;代码的运行环境是在HBuilder中&#xff0c;小编会将代码复制下来&#xff0c;大家复制下来就可以练习了&#xff0c;方便大家学习。 系列文章目录 HTML-1.1 文本字体样式-字体设置、分割线、段落标签、段内回车以及特殊符号 HTML…...

了解光学影像

本文来源 &#xff1a; 腾讯元宝 光学影像是一种通过光学技术捕捉、记录和处理图像的技术&#xff0c;广泛应用于医学、工业、安防、科研等多个领域。以下是关于光学影像的详细介绍&#xff1a; 1. ​​基本原理​​ 光学影像基于光的传播、反射、折射和散射等物理现象。通过…...

计算机视觉---目标追踪(Object Tracking)概览

一、核心定义与基础概念 1. 目标追踪的定义 定义&#xff1a;在视频序列或连续图像中&#xff0c;对一个或多个感兴趣目标&#xff08;如人、车辆、物体等&#xff09;的位置、运动轨迹进行持续估计的过程。核心任务&#xff1a;跨帧关联目标&#xff0c;解决“同一目标在不同…...

Weblogic SSRF漏洞复现(CVE-2014-4210)【vulhub靶场】

漏洞概述&#xff1a; Weblogic中存在一个SSRF漏洞&#xff0c;利用该漏洞可以发送任意HTTP请求&#xff0c;进而攻击内网中redis、fastcgi等脆弱组件。 漏洞形成原因&#xff1a; WebLogic Server 的 UDDI 组件&#xff08;uddiexplorer.war&#xff09;中的 SearchPublicR…...

fakeroot 在没有超级用户权限的情况下模拟文件系统的超级用户行为

fakeroot 是一个在 Linux 环境中使用的工具&#xff0c;它允许用户在没有超级用户权限的情况下模拟文件系统的超级用户行为。它是一个在 Linux 环境中广泛使用的工具&#xff0c;通常包含在大多数 Linux 发行版的软件仓库中。‌ 主要功能 ‌模拟 root 权限‌&#xff1a;fake…...

AI大模型应用:17个实用场景解锁未来

任何新技术的普及都需要经历一段漫长的过程&#xff0c;人工智能大模型也不例外。 尽管某些行业的从业者已经开始将大模型融入日常工作&#xff0c;但其普及程度仍远未达到“人手必备”的地步。 那么&#xff0c;究竟是什么限制了它的广泛应用&#xff1f;普通人如何才能用好…...

激光雷达点云畸变消除:MCU vs CPU 方案详解

在移动机器人、自动驾驶等场景中&#xff0c;激光雷达&#xff08;LiDAR&#xff09;用于获取高精度的空间点云数据。然而&#xff0c;当雷达在运动中扫描时&#xff0c;不同点的采集时刻对应的位置不同&#xff0c;就会出现“运动畸变&#xff08;Motion Distortion&#xff0…...

java17

1.常见API之BigDecimal 底层存储方式&#xff1a; 2.如何分辨过时代码&#xff1a; 有横线的代码表示该代码已过时 3.正则表达式之字符串匹配 注意&#xff1a;如果X不是单一字符&#xff0c;需要加[]中括号 注意&#xff1a;1.想要表达正则表达式里面的.需要\\. 2.想要表…...