C++特殊类设计

目录

不能被拷贝的类

只能在堆上创建对象的类 

构造函数私有化: 

析构函数私有化:

只能在栈上创建对象的类

不能被继承的类

只能创建一个对象的类(单例模式)

设计模式:

单例模式:

饿汉模式:

懒汉模式:

线程不安全的懒汉模式: 

线程安全的懒汉模式:

静态对象:

不能被拷贝的类

要想设计一个不能被拷贝的类,首先需要知道哪些场景中会发生类的拷贝。拷贝只会发生在两个场景拷贝构造时赋值时,因此想要让一个类不能被拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

C++98的标准中,需要把拷贝构造函数和赋值重载函数只声明不定义且设置为私有,此时该类就无法调用拷贝构造函数和赋值重载函数了。

class NoCopy
{
public:NoCopy(){}~NoCopy(){}
private://拷贝构造和赋值重载只声明不定义,且设置为私有的NoCopy(const NoCopy& nc);NoCopy& operator=(const NoCopy& nc);
};int main()
{NoCopy n1;NoCopy n2(n1);//调用拷贝构造NoCopy n3;n3 = n1;//调研赋值重载return 0;
}

上述代码中,定义了一个NoCopy类,该类的拷贝构造和赋值重载只声明不定义,且设置为私有的。然后再main函数中尝试调用NoCopy类的拷贝构造和赋值重载。尝试编译运行一下:

可见把类的拷贝构造和赋值重载只声明不定义,且设置为私有的这种做法确实可以让一个类无法被拷贝。

注意:只声明不定义设置为私有两个条件缺一不可

  • 设置为私有:如果没有设置成private,那么用户就可以在类外定义了,就不能禁止拷贝了。
  • 只声明不定义:不定义是因为该函数根本不会调用,定义了也没有什么意义,不写反而省事了,而且如果定义了,就可能会在成员函数内部进行拷贝了。

C++11中扩展了delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上'=delete',表示让编译器强制删除掉该默认成员函数

此时再想设计一个不能被拷贝的类,只需要把该类的拷贝构造函数和赋值重载函数使用delete强删除即可,且即使设置为公有的也不影响

class NoCopy
{
public:NoCopy(){}~NoCopy(){}//使用delete强制删除拷贝构造函数和赋值重载函数NoCopy(const NoCopy& nc) = delete;NoCopy& operator=(const NoCopy& nc) = delete;};int main()
{NoCopy n1;NoCopy n2(n1);//调用拷贝构造NoCopy n3;n3 = n1;//调研赋值重载return 0;
}

上边的代码中,NoCopy类的拷贝构造函数和赋值重载函数被使用delete强制删除了,且是在public区域中,在main函数中尝试调用拷贝构造函数和赋值重载函数。尝试编译运行:

可见把类的拷贝构造函数和赋值重载函数使用delete强制删除,是可以让一个类无法被拷贝的。

只能在堆上创建对象的类 

构造函数私有化: 

创建一个类对象,只能创建在两个位置,要么是创建在栈上,要么是创建在堆上。而要创建一个类对象,必会调用构造函数或拷贝构造函数。而想要在堆上创建对象,就必须通过new/malloc等实现。因此要想实现只能在堆上创建对象,首先要将构造函数私有化,同时拷贝构造和赋值重载需要强制删除(或者只声明不定义且设置为私有),提供一个static成员函数,在该函数中完成对象的创建并返回对象指针

class HeapOnly
{
public:static HeapOnly* CreateObject(){return new HeapOnly;}//通过类成员函数返回对象/*HeapOnly test(){return *this;}*/
private://构造函数HeapOnly() {}//拷贝构造和赋值重载//C++98:只声明不定义,且设置为私有//HeapOnly(const HeapOnly&);//HeapOnly& operator=(const HeapOnly& h);//C++11:使用delete强制删除HeapOnly(const HeapOnly&) = delete;HeapOnly& operator=(const HeapOnly& h) = delete;};int main()
{HeapOnly* hp1 = HeapOnly::CreateObject();//如果不把拷贝构造函数和赋值重载函数删除,就可以通过下边的方法在栈上创建对象/*HeapOnly hp2(*hp1);HeapOnly* hp3 = HeapOnly::CreateObject();HeapOnly hp4(*hp3);hp4 = *hp1;HeapOnly hp5 = hp3->test();*/delete hp1;return 0;
}

上边的代码实现了一个只能在堆上创建对象的类HeapOnly,到那时还存在一个问题,CreateObject()方法返回的是一个原生指针,HeapOnly类虽然禁止了类对象的拷贝和赋值,但是原生指针之间还是可以互相赋值的,这就会导致多个指针指向同一份资源,释放资源时就会出问题。

int main()
{HeapOnly* hp1 = HeapOnly::CreateObject();HeapOnly* hp2 = hp1;delete hp1;delete hp2;return 0;
}

上边的代码先通过CreateObject()方法创建了一个对象并把对象指针返回给后hp1,然后又把hp1赋值给hp2,编译运行代码:

可以发现程序运行崩溃了,就是以为重复释放了同一份资源导致的。

要解决这个问题就需要用到以前说过的智能指针了,通过智能指针可以更加安全有效的管理资源。

class HeapOnly
{
public:static shared_ptr<HeapOnly> CreateObject(){return shared_ptr<HeapOnly>(new HeapOnly);}/*static HeapOnly* CreateObject(){return new HeapOnly;}*/
private://构造函数HeapOnly() {}HeapOnly(const HeapOnly&) = delete;HeapOnly& operator=(const HeapOnly& h) = delete;};int main()
{shared_ptr<HeapOnly> hp1 = HeapOnly::CreateObject();shared_ptr<HeapOnly> hp2 = hp1;return 0;
}

上述代码通过修改CreateObject()函数的返回值,实现了对资源的安全管理,可以正常编译运行。

shared_ptr可以让多个对象共享同一块资源,而unique_ptr是独占资源,可以根据不同的场景灵活使用。

需要注意的是CreateObject()函数在返回对象时不能使用make_shared<HeapOnly>()

make_shared<HeapOnly>()

  • make_shared 需要直接调用 HeapOnly的构造函数。

  • 但 make_shared的模板实例化代码位于标准库中(<memory> 头文件),不在 HeapOnly类的成员函数作用域内

  • 因此,make_shared无法访问 HeapOnly的私有构造函数,导致编译错误。

  • 要想使用make_shared,需要在HeapOnly类中声明make_shared为友元:

    class HeapOnly {
    public:template <typename T, typename... Args>friend shared_ptr<T> std::make_shared(Args&&... args);// 其他代码...
    };

shared_ptr(new HeapOnly)

  • new HeapOnly的调用发生在 CreateObject()成员函数内部。
  • 成员函数可以访问类的私有成员(包括私有构造函数)。
  • 因此,new HeapOnly合法,shared_ptr可以安全接管指针。

析构函数私有化:

 上边通过构造函数私有化实现了一个只能在堆上创建的类,此外还可以通过将析构函数私有化实现一个只能在堆上创建的类。

class HeapOnly
{
public://构造函数HeapOnly() {}void del(){delete this;}
private://析构函数~HeapOnly(){}HeapOnly(const HeapOnly&) = delete;HeapOnly& operator=(const HeapOnly& h) = delete;};int main()
{HeapOnly* hp1 = new HeapOnly;hp1->del();HeapOnly hp2;return 0;
}

 上述代码中定义了一个HeapOnly类,该类将析构函数进行了私有化处理,在main函数中通过new在堆上创建一个对象,又直接在栈上定义了一个对象,编译运行:

 编译直接报错,这是因为编译器在编译阶段会检查对象的完整生命周期包括析构函数的可访问性,即使构造函数是公有的,如果析构函数不可访问,编译器会直接拒绝栈对象的定义。

new操作符仅依赖构造函数的可访问性与析构函数无关。堆对象的销毁必须通过显式调用del()函数,不能直接使用delete操作符,因为delete操作符会尝试调用析构函数,而析构函数是私有的,无法在外部直接调用;而del()是类的成员函数,可以直接访问私有的析构函数。

只能在栈上创建对象的类

有了只能在堆上创建对象的经验,要设计一个只能在栈上创建对象的类就很简单了。要想在堆上创建对象,必须要调用new操作符,当使用new动态分配对象时,编译器会先调用operator new分配内存,再调用构造函数。因此只需要把operator new强制删除,就可以禁止在堆上创建对象了。

class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}StackOnly(){}// 禁用 new 操作符void* operator new(size_t) = delete;void operator delete(void*) = delete;// 禁用 new[] 和 delete[]void* operator new[](size_t) = delete;void operator delete[](void*) = delete;
private:};int main()
{StackOnly so1=StackOnly::CreateObj();StackOnly so2;//StackOnly* so3 = new StackOnly;//报错return 0;
}

不能被继承的类

在C++的继承体系中,子类的构造函数必须调用父类的构造函数初始化父类的那一部分成员,如果父类没有默认的构造函数,则必须在子类构造函数的初始化列表阶段显示调用。因此如果把父类的构造函数设置为私有的,那么在子类构造函数中将无法调用父类的构造函数,这就实现了父类不可被继承。

class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};class A:public NonInherit
{
public:A(){}};int main()
{A a;return 0;
}

上述代码中定义了一个NoInherit类,NoInherit类的构造函数设置为了私有的,有一个A类继承自NoInherit类,然后再main函数中定义A类对象,编译运行:

可以发现A类将无法定义对象,也就实现了NoInherit类不可被继承,因为只要继承了NoInherit类的子类都无法定义对象。

除了上述方法,C++11引入了final关键字来修饰类,表示该类不可被继承。

class NonInherit final
{
public:NonInherit(){}
};

只能创建一个对象的类(单例模式)

设计模式:

设计模式是解决软件设计中常见问题的可复用方案,它们可以分为三大类:​创建型结构型行为型

创建型模式:控制对象的创建过程,解耦对象的创建与使用,提高灵活性和可维护性。主要包括:单例模式、工厂模式等。

结构型模式组织类和对象的结构,通过组合或继承实现更灵活的设计。主要包括:适配器模式、装饰器模式等。

行为型模式:​管理对象间的交互和职责分配,优化通信流程。主要包括:观察者模式、命令模式等。

实用设计模式的目的:提高代码可重用性让代码更容易被他人理解保证代码可靠性。使代码编写真正工程化。

单例模式:

一个类只能创建一个对象,这种模式叫做单例模式。单例模式确保一个类只有一个实例并提供全局访问点该实例被所有程序模块共享,需要通过静态对象实现。主要应用场景:数据库连接池、全局配置管理器。

单例模式有两种实现模式:饿汉模式懒汉模式

饿汉模式:

饿汉模式的设计思想是不管是否使用在程序启动时(main函数之前)就直接创建一个唯一的静态实例对象

优点:

  • 简单,没有线程安全的问题。

缺点:

  • 如果单例对象数据较多,构造初始化成本较高,那么会影响程序启动的速度。迟迟进不了main函数。
  • 如果多个单例类有初始化启动依赖关系,饿汉模式无法控制。假设有A和B两个单例,B类依赖于A类,要求A先初始化,B再初始化,此时饿汉模式将无法保证初始化顺序。
//饿汉模式
namespace Hunger
{//单例类class Singleton{public:static Singleton* GetInstance(){return &_sing;}void Print(){cout << _x << endl;cout << _y << endl;for (auto& e : _vstr){cout << e << " ";}cout << endl;}void AddStr(const string& s){_vstr.push_back(s);}private://将拷贝构造和赋值重载强制删除,防止通过它们破坏单例的唯一性Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;//构造函数私有化,防止随意创建对象Singleton(int x, int y, const vector<string>& vstr):_x(x), _y(y), _vstr(vstr){}int _x;int _y;vector<string> _vstr;// 静态成员对象,不存在对象中,存在静态区,只有一份,相当于全局的,定义在类中,受类域限制static Singleton _sing;};//类外定义静态成员//只能在此处进行初始化设置数据Singleton Singleton::_sing(1, 2, { "hello","haha" });
}int main()
{Hunger::Singleton* hs=Hunger::Singleton::GetInstance();hs->Print();hs->AddStr("nihao");hs->Print();return 0;
}

上述代码中实现了一个饿汉模式的单例类Hunger::Singleton,并在main函数中进行了相关调用,编译运行:

饿汉模式由于提前加载资源,适用于实例小且频繁使用的情况,可避免资源竞争,提高响应速度。

懒汉模式:

懒汉模式的设计思想是在第一次使用实例对象时,创建对象

优点:

  •  第一次使用实例对象时,创建对象。程序启动无负载。多个单例实例启动顺序自由控制

缺点:

  • 复杂,存在线程安全的问题。
线程不安全的懒汉模式: 
namespace Lazy
{class Singleton{public://获取单例对象static Singleton* GetInstance(){//静态成员变量只会创建一次if (_psing == nullptr)//在第一次调用时创建{_psing = new Singleton;}return _psing;}void Print(){cout << _x << endl;cout << _y << endl;for (auto& e : _vstr){cout << e << " ";}cout << endl;}void AddStr(const string& s){_vstr.push_back(s);}//删除单例对象static void DelInstance(){std::cout << "static void DelInstance()" << std::endl;if (_psing){delete _psing;_psing = nullptr;}}~Singleton() {}private:Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;//构造函数私有化,防止随意创建对象Singleton(int x = 0, int y = 0, const vector<string>& vstr = { "xxxxxxx" }):_x(x), _y(y), _vstr(vstr){}int _x;int _y;vector<string> _vstr;// 静态成员对象,不存在对象中,存在静态区,相当于全局的,定义在类中,受类域限制static Singleton* _psing;//内部类,帮助删除单例对象class GC{public:~GC(){Singleton::DelInstance();}};static GC _gc;};//静态成员类内声明,类外定义Singleton* Singleton::_psing = nullptr;Singleton::GC Singleton::_gc;
}int main()
{Lazy::Singleton* ls = Lazy::Singleton::GetInstance();ls->Print();ls->AddStr("zaijian");ls->Print();//ls->DelInstance();手动调用return 0;
}

上述代码中实现了一个基础的懒汉模式的单例类Lazy::Singleton,由于静态成员变量是一个指针,无法转动销毁对象资源,需要提供一个静态成员方法DelInstance(),用来释放对象资源,为防止忘记手动调用DelInstance()方法,设计一个内部类GC,专门用于调用DelInstance()方法释放对象资源。编译运行:

可以发现,DelInstance()方法自动调用了。

这种基础的懒汉模式的单例类,存在一个很大的问题,它是线程不安全的,多线程下可能创建多个实例(竞态条件)

单例模式的核心是确保一个类只有一个实例,并在全局提供访问点。在单线程环境下,因为GetInstance()会检查_psing是否为nullptr,如果是,则创建新实例,如果不是,则直接返回。但在多线程环境下,可能会有多个线程同时进入GetInstance()导致多个实例被创建,从而破坏单例的唯一性

具体来说,线程不安全的原因在于没有同步机制。当两个或多个线程同时执行if (_psing==nullptr)时,它们都可能发现_psing为nullptr,从而各自执行_psing = new Singleton,导致多次实例化。

void test()
{Lazy::Singleton* ls = Lazy::Singleton::GetInstance();std::cout << ls << std::endl;}
int main()
{/*Lazy::Singleton* ls = Lazy::Singleton::GetInstance();ls->Print();ls->AddStr("zaijian");ls->Print();*///ls->DelInstance();手动调用vector<thread> threads;// 启动多个线程for (int i = 0; i < 10; ++i) {threads.emplace_back(test);}// 等待所有线程结束for (auto& t : threads) {t.join();}return 0;
}

上边的代码中,test函数每次都会获取实例,并打印地址,main函数中,创建了10个线程都去执行test函数,观察现象:

可以发现,这是个线程打印的地址多数都是不同的,说明进行了多次实例化。

线程不安全的问题并不容易复现,因为线程的调度是操作系统控制的,可能在某些情况下测试通过,但在其他情况下失败。为了增加竞态发生的概率,可以在if条件判断后和实际创建实例前插入一些延迟(this_thread::sleep_for(chrono::milliseconds(100))),模拟线程切换的情况,以增加复现概率

线程安全的懒汉模式:

为了保证线程安全,可以通过加锁的方法来实现。

namespace Lazy
{class Singleton{public://获取单例对象static Singleton* GetInstance(){//静态成员变量只会创建一次//双检查加锁,保证线程安全if (_psing == nullptr){unique_lock<mutex> lock(_mutex);//加锁if(_psing ==nullptr)//在第一次调用时创建{ this_thread::sleep_for(chrono::milliseconds(100));//手动延时_psing = new Singleton;}}return _psing;}void Print(){cout << _x << endl;cout << _y << endl;for (auto& e : _vstr){cout << e << " ";}cout << endl;}void AddStr(const string& s){_vstr.push_back(s);}//删除单例对象static void DelInstance(){std::cout << "static void DelInstance()" << std::endl;if (_psing){delete _psing;_psing = nullptr;}}~Singleton(){}private:Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;//构造函数私有化,防止随意创建对象Singleton(int x = 0, int y = 0, const vector<string>& vstr = {"xxxxxxx"}):_x(x), _y(y), _vstr(vstr){}int _x;int _y;vector<string> _vstr;static mutex _mutex;//锁// 静态成员对象,不存在对象中,存在静态区,相当于全局的,定义在类中,受类域限制static Singleton* _psing;//内部类,帮助调用单例类的析构class GC{public:~GC(){Singleton::DelInstance();}};static GC _gc;};//静态成员类内声明,类外定义Singleton* Singleton::_psing = nullptr;mutex Singleton::_mutex;Singleton::GC Singleton::_gc;
}void test()
{Lazy::Singleton* ls = Lazy::Singleton::GetInstance();std::cout << ls << std::endl;}
int main()
{vector<thread> threads;// 启动多个线程for (int i = 0; i < 10; ++i) {threads.emplace_back(test);}// 等待所有线程结束for (auto& t : threads) {t.join();}return 0;
}

上边的代码通过加锁,保证了线程安全。

前边所说的懒汉模式的代码,都必须通过一个静态方法来释放对象资源,为防止忘记手动调用,还需要一个内部类GC来实现自动释放资源,因为单例对象是一个静态指针,无法自动释放资源,那可不可以直接使用静态对象来实现单例模式,这样就不用再单独考虑资源释放的问题了。

答案是可以的,但是需要在C++11之后才可以,因为C++11之前静态对象的创建无法保证线程安全,C++11之后保证了静态对象创建是线程安全的

静态对象:
namespace Lazy
{class Singleton{public://获取单例对象static Singleton* GetInstance(){// 局部的静态对象,第一次调用函数时构造初始化// C++11及之后这样写才可以// C++11之前无法保证这里的构造初始化是线程安全的this_thread::sleep_for(chrono::milliseconds(100));static Singleton sint;this_thread::sleep_for(chrono::milliseconds(100));return &sint;}void Print(){cout << _x << endl;cout << _y << endl;for (auto& e : _vstr){cout << e << " ";}cout << endl;}void AddStr(const string& s){_vstr.push_back(s);}private:Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;//构造函数私有化,防止随意创建对象Singleton(int x = 0, int y = 0, const vector<string>& vstr = { "xxxxxxx" }):_x(x), _y(y), _vstr(vstr){}~Singleton(){cout << "~Singleton()" << endl;}int _x;int _y;vector<string> _vstr;};
}
void test()
{Lazy::Singleton* ls = Lazy::Singleton::GetInstance();std::cout << ls << std::endl;}
int main()
{vector<thread> threads;// 启动多个线程for (int i = 0; i < 10; ++i) {threads.emplace_back(test);}// 等待所有线程结束for (auto& t : threads) {t.join();}return 0;
}

上边的代码通过静态对象实现了一个线程安全的懒汉模式单例类。

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

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

相关文章

Linux系统之配置HAProxy负载均衡服务器

Linux系统之配置HAProxy负载均衡服务器 前言一、HAProxy介绍1.1 HAProxy简介1.2 主要特点1.3 使用场景二、本次实践介绍2.1 本次实践简介2.2 本次实践环境规划三、部署两台web服务器3.1 运行两个Docker容器3.2 编辑测试文件3.3 访问测试四、安装HAProxy4.1 更新系统软件源4.2 安…

从零开始学机器学习——什么是机器学习

这个系列的文章旨在为初学者提供机器学习知识&#xff0c;避免使用专业术语和复杂的概念&#xff0c;以便更好地理解和应用。 首先给大家介绍一个很好用的学习地址&#xff1a;https://cloudstudio.net/columns 机器学习 在这里简要介绍机器学习&#xff1a;它利用真实世界或…

AI驱动的消费者体验优化——DeepBI如何用智能策略助力亚马逊卖家“俘获”消费者的心

在亚马逊这个竞争异常激烈的电商平台上&#xff0c;消费者体验已经成为决定卖家成败的关键因素之一。优质的消费者体验不仅能够提升客户满意度&#xff0c;还能加速口碑传播&#xff0c;带动销量持续增长。 今天&#xff0c;我们就来深入解析&#xff0c;DeepBI如何依托 AI 驱动…

Devart dbForge Studio for MySQL Enterprise 9.0.338高效数据库管理工具

Devart dbForge Studio for MySQL Enterprise 9.0.338 是一款功能强大的 MySQL 数据库管理工具&#xff0c;专为数据库开发人员和管理员设计。它提供了丰富的功能&#xff0c;帮助用户更高效地管理、开发和维护 MySQL 数据库 Devart dbForge Studio for MySQL Enterprise 9.0.…

SQL_语法

1 数据库 1.1 新增 create database [if not exists] 数据库名; 1.2 删除 drop database [if exists] 数据库名; 1.3 查询 (1) 查看所有数据库 show databases; (2) 查看当前数据库下的所有表 show tables; 2 数据表 2.1 新增 (1) 创建表 create table [if not exists…

PX4中的UAVCAN_V1的实现库libcanard与数据格式DSDL

libcanard简介 libcanard 是用于嵌入式实时系统的 UAVCAN 协议的缩减版实现库。 在 PX4 中&#xff0c;在 src/drivers/uacvan_v1 目录中&#xff0c;与 0.9 版本的相比&#xff0c;名称更改了(v0.9版本为 libuavcan)&#xff1a; 此库有几个点需要注意&#xff1a; 1&#…

物联网系统搭建

实验项目名称 构建物联网系统 实验目的 掌握物联网系统的一般构建方法。 实验要求&#xff1a; 1&#xff0e;构建物联网系统&#xff0c;实现前后端的交互。 实验内容&#xff1a; CS模式MQTT&#xff08;不带数据分析处理功能&#xff09; 实现智能设备与应用客户端的交…

SpringBoot优雅关机,监听关机事件,docker配置

Spring Boot 提供了多种方法来实现优雅停机&#xff08;Graceful Shutdown&#xff09;&#xff0c;这意味着在关闭应用程序之前&#xff0c;它会等待当前正在处理的请求完成&#xff0c;并且不再接受新的请求。 一、优雅停机的基本概念 优雅停机的主要步骤如下&#xff1a; …

Docker 学习(二)——基于Registry、Harbor搭建私有仓库

Docker仓库是集中存储和管理Docker镜像的平台&#xff0c;支持镜像的上传、下载、版本管理等功能。 一、Docker仓库分类 1.公有仓库 Docker Hub&#xff1a;官方默认公共仓库&#xff0c;提供超过10万镜像&#xff0c;支持用户上传和管理镜像。 第三方平台&#xff1a;如阿里…

java环境部署

java环境部署 一、准备工作 jrejdkeclipse jdk下载&#xff1a;21和1.8-----官网&#xff1a;Oracle&#xff1a;Java 下载 |神谕 该处选择要依据自身的系统类型选择下载 idea的下载安装&#xff1a;IntelliJ IDEA | Other Versions 二、安装 三、环境配置 四、使用 五、i…

从0开始的操作系统手搓教程21:进程子系统的一个核心功能——简单的进程切换

目录 具体说说我们的简单RR调度 处理时钟中断处理函数 调度器 schedule switch_to 我们下面&#xff0c;就要开始真正的进程切换了。在那之前&#xff0c;笔者想要说的是——我们实现的进程切换简单的无法再简单了——也就是实现一个超级简单的轮询调度器。 每一个进程按照…

【办公类-99-03】养老护理初级考题抽取(2套大题抽1+7小套题抽2——共有42种可能)

背景需求 三八妇女节当天就要考养老护理实操了。这几天晚上都在疯狂练习。 考试时&#xff0c;两套大题抽一题。七套小题抽两题。会有多少种不重复的排列方式呢&#xff1f; 手机版本"通义万象” 有432。 这是我在公交车上用通义AI写的。 回家后继续用我熟悉的“星火讯…

Spring统一格式返回

目录 一&#xff1a;统一结果返回 1&#xff1a;统一结果返回写法 2&#xff1a;String类型报错问题 解决方法 二&#xff1a;统一异常返回 统一异常返回写法 三&#xff1a;总结 同志们&#xff0c;今天咱来讲一讲统一格式返回啊&#xff0c;也是好久没有讲过统一格式返…

Redis数据结构,渐进式遍历,数据库管理

1.Redis的其他数据结构 前面我们主要讲述了Redis中比较常用的集中数据结构String&#xff0c;List&#xff0c;Hash&#xff0c;Set&#xff0c;Zset&#xff0c;但这并不代表Redis只用这几种数据结构还有如Streams&#xff0c;Geospatial&#xff0c;Hyperloglog&#xff0c;…

DeepSeek DeepEP学习(二)normal notify dispatch

背景 相对于low latency的追求延迟&#xff0c;normal版本追求更高的带宽&#xff0c;传统all2all算子在发送到同一台机器的不同rank时&#xff0c;会存在重复token的发送&#xff0c;而DeepSeek团队使用的机型的机内带宽大于机间带宽&#xff0c;因此DeepSeek提出了两阶段的a…

立即释放 Mac 空间!Duplicate File Finder 8 重复文件高速清理工具

Duplicate File Finder 专业的 Mac 重复文件清理工具。查找并删除重复的文件、文件夹&#xff0c;甚至相似的照片。 不要让无用的文件占用磁盘上的宝贵空间。 整理你的 Mac。用最好的重复文件查找器来管理你的文件集合。 扫描任何磁盘或文件夹 主文件夹、照片/音乐库、外部磁…

一个前端vue3文字hover效果

效果 组件代码 <template><span class"word-text" :style"[{ transitionDuration: ${props.speed}ms }]"><slot></slot></span> </template><script setup> const props defineProps({// 动画速率 单位msspee…

数据结构 常见的排序算法

&#x1f33b;个人主页&#xff1a;路飞雪吖~ &#x1f320;专栏&#xff1a;数据结构 目录 &#x1f33b;个人主页&#xff1a;路飞雪吖~ 一、插入排序 &#x1f31f;直接插入排序 &#x1f31f;希尔排序 二、选择排序 &#x1f31f;选择排序 &#x1f31f;堆排序…

【微信小程序】每日心情笔记

个人团队的比赛项目&#xff0c;仅供学习交流使用 一、项目基本介绍 1. 项目简介 一款基于微信小程序的轻量化笔记工具&#xff0c;旨在帮助用户通过记录每日心情和事件&#xff0c;更好地管理情绪和生活。用户可以根据日期和心情分类&#xff08;如开心、平静、难过等&#…

SD-WAN解决方案架构(SD WAN Solution Architecture)

简介 SD-WAN&#xff08;软件定义广域网&#xff09;是一种新型的网络技术&#xff0c;它将传统的广域网&#xff08;WAN&#xff09;与现代化的软件定义网络&#xff08;SDN&#xff09;技术相结合&#xff0c;提供更智能、更灵活的网络管理方式‌。SD-WAN通过软件程序配置分…