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

【C++】设计模式详解:单例模式

文章目录

  • Ⅰ. 设计一个类,不允许被拷贝
  • Ⅱ. 请设计一个类,只能在堆上创建对象
  • Ⅲ. 请设计一个类,只能在栈上创建对象
  • Ⅳ. 请设计一个类,不能被继承
  • Ⅴ. 请设计一个类,只能创建一个对象(单例模式)
  • 💥单例模式:
    • 1、饿汉模式
    • 2、懒汉模式
      • 第一种写法:
      • 第二种写法:

在这里插入图片描述

Ⅰ. 设计一个类,不允许被拷贝

​ 拷贝只会发生在两个场景中:拷贝构造函数赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

  • C++98 的方式:

    1. 设置成私有:如果只声明而没有设置成 private,用户自己如果在类外定义了,还是等于可以拷贝

    2. 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就做不到防止成员函数内部拷贝了。

      class CopyBan
      {// ......
      private:// 设为私有,只声明不实现CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);
      };
      
  • C++11 的方式:

    • C++11中扩展了 delete 的用法,delete 除了释放 new 申请的资源外,如果在默认成员函数后跟上 =delete,表示让编译器删除掉该默认成员函数。
    class CopyBan
    {// 直接使用delete关键字CopyBan(const CopyBan&) = delete;CopyBan& operator=(const CopyBan&) = delete;// ......
    };
    

Ⅱ. 请设计一个类,只能在堆上创建对象

实现方式:

  1. 将类的构造函数私有化并将拷贝构造的声明也私有化,防止别人调用拷贝在栈上生成对象。(或者用 defaultdelete 关键字也行)

  2. 提供一个完成堆对象创建的静态成员函数

​ 顺便提一下,有人采用将析构函数变成私有的方法来使类的默认构造函数、拷贝构造、赋值重载不会自动生成,这也是可以的,但是这时候就需要我们手动去写一个释放的函数来调用,所以一般我们也只用上面的方法,而这种 将析构函数私有的方法不常用

class HeapOnly
{
public:// static的好处就是我们不需要对象就可以在类外通过类名::函数名直接访问static HeapOnly* CreateObject(){return new HeapOnly;}
private:// 默认构造函数不能直接封掉,因为上面的CreateObject()需要调用// 可以只声明不实现,这里直接使用default关键字HeapOnly() = default;// 拷贝构造和赋值重载要封掉,防止拷贝产生栈空间对象HeapOnly(const HeapOnly&) = delete;HeapOnly& operator=(const HeapOnly&) = delete;
};int main()
{HeapOnly* h1 = HeapOnly::CreateObject();// HeapOnly h2 = h1; // ❌// static HeapOnly h3; // ❌static HeapOnly* h3 = HeapOnly::CreateObject(); // 本质还是一个指向堆空间的对象cout << typeid(h3).name() << endl;return 0;
}// 运行结果:
class HeapOnly * __ptr64

Ⅲ. 请设计一个类,只能在栈上创建对象

  • 方法一:同上面那种情况一样,将构造函数私有化,然后设计静态方法创建对象返回即可。

    class StackOnly
    {
    public:static StackOnly CreateObject(){return StackOnly();}
    private:StackOnly() = default;/* 或者只声明不定义StackOnly(){}*/
    };int main()
    {StackOnly s1 = StackOnly::CreateObject();StackOnly* s2 = new StackOnly; // ❌static StackOnly s3; // ❌return 0;
    }
    
  • 方法二:屏蔽 operator newoperator delete。因为 new 在底层调用 void* operator new(size_t size) 函数,只需将该函数屏蔽掉即可。

    • 注意:要防止定位 new
    • 这种方法其实是不太好使的,因为就算我们禁用了 operator new 或者 operator delete,我们也很难防止其在静态区中产生对象,如果使用这种方法,那么还是得和方法一一样,将构造函数私有化,然后使用静态函数返回栈对象,那为何不直接使用第一种方法呢❓❓❓
    class StackOnly
    {
    public:StackOnly() {}
    private:void* operator new(size_t size);void operator delete(void* p);
    };int main()
    {StackOnly s1;StackOnly* s2 = new StackOnly; // ❌static StackOnly s3; // 仍然可以生成静态区对象return 0;
    }
    

​ 这里要说明一个点,就是我们还是 没办法预防产生静态变量,如下面代码:

class StackOnly
{
public:static StackOnly CreateObject(){return StackOnly();}
private:StackOnly() = default;// 不能封掉拷贝构造,不然CreateObject无法return// StackOnly(const StackOnly&) = delete;
};
int main()
{StackOnly s1 = StackOnly::CreateObject();// 无法封掉这种情况,因为如果封掉拷贝构造的话,那么我们就无法在CreateObject中return一个临时栈对象了static StackOnly s2 = StackOnly::CreateObject(); cout << typeid(s2).name() << endl;return 0;
}// 运行结果:
class StackOnly

​ 如果我们想避开这种情况,唯一的方法就是 不使用栈对象,我们只通过 CreateObject() 来调用类中的某些函数,但是一般这么做就有点一次性那味。

Ⅳ. 请设计一个类,不能被继承

  • C++98 的方式:

    // C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
    class NonInherit
    {public:static NonInherit GetInstance(){return NonInherit();}
    private:NonInherit(){}
    };
    
  • C++11 的方式

    • 使用 final 修饰类,表示该类不能被继承。
    class A  final
    {// ....
    };
    

Ⅴ. 请设计一个类,只能创建一个对象(单例模式)

设计模式(Design Pattern是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后来孙子就总结出了《孙子兵法》。孙子兵法也是类似。

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

​ 我们之前在学习 C++ 的过程中其实早就接触到了设计模式,比如迭代器模式、适配器模式等等,下面我们就来讲一下单例模式:

💥单例模式:

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。

​ ⚜️一般来说,单例模式下是不需要考虑资源释放的,因为我们这个单例对象是在主程序结束之后会自动释放的,如果没有特定需求说要提前释放,一般我们都不需要实现资源释放的功能,但是如果需要的话,比如说我们需要手动释放,因为一些资源可能要保存到日志等原因,所以我们就得实现释放资源函数比如说 DeleteInstance() 等等,下面的懒汉模式中会实现!

​ 单例模式有两种实现模式:

1、饿汉模式

​ 饿汉模式的宗旨就是说 不管你将来用不用,主程序启动时就创建一个唯一的实例对象。这就像一个饿汉一样,一旦遇到了食物,那么此时都是控制不住想直接去吃的,所以这种模式叫做饿汉模式!

  • 优点:
    • 控制简单
    • 因为是在执行主函数之前就生成了对象,所以 没有线程安全问题
    • 如果这个单例对象 在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,响应速度更好
  • 缺点:
    • 若单例对象的成员数据过多,那么会 导致整个程序启动变慢
    • 如果有多个单例类是相互依赖并且有初始化依赖顺序的,那么饿汉模式在创建的时候是控制不了这种依赖顺序。(可参考 Effective C++

实现方式:

​ 首先既然是单例模式,那么我们肯定要保证全局只能产生一个对象,那么我们想到的就是用静态变量,所以我们在 Singleton 类中定义一个静态变量 single_object,并且用一个静态成员函数 CreateObject() 返回该对象,而这个对象就是这个单例对象。

​ 接着为了防止生成一个栈对象、堆对象,我们得将拷贝构造和赋值重载封掉,并将构造函数私有化而且不实现!

// 饿汉模式
// 优点:简单
// 缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定。
class Singleton
{
public:static Singleton& CreateObject(){return single_object;}void Print(){cout << "饿汉模式::Print()" << endl;}
private:// 构造函数私有,并且不实现Singleton() {}// 拷贝构造以及赋值重载封掉Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton single_object; // 声明一个当前类的静态变量
};Singleton Singleton::single_object; // 类外初始化这个静态变量int main()
{// 第一种访问方法:通过CreateObject()直接调用相关接口Singleton::CreateObject().Print();// 第二种访问方法:可以使用引用接收CreateObject(),通过该对象调用相关接口Singleton& s = Singleton::CreateObject();s.Print();Singleton s1; // ❌无法通过编译Singleton* s2 = new Singleton; // ❌无法通过编译static Singleton s3; // ❌无法通过编译return 0;
}// 运行结果:
饿汉模式::Print()
饿汉模式::Print()

​ 💥注意:上面我们在实现饿汉模式以及后面的懒汉模式的时候,都采用 c++11delete 关键字进行防止拷贝发生,而不采用 c++98 的方式!

2、懒汉模式

​ 如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。

​ 但是懒汉模式的问题就是涉及到了多线程安全问题,所以实现起来当然会复杂许多。

  • 优点:
    • 因为对象在主程序之后才会创建,所以 程序启动比饿汉模式要快
    • 可以控制不同的单例类的依赖关系以及控制依赖顺序
  • 缺点:
    • 涉及到多线程安全问题,需要加锁,实现要复杂许多

第一种写法:

​ 这种写法涉及到了加锁的问题,所以会复杂一点。和饿汉模式一样,我们需要一个 静态成员函数 CreateObject() 用于获取这个单例对象,不同的是懒汉模式中我们不能直接在类内定义一个静态变量,因为我们要的效果是当我们调用 CreateObject() 的时候,单例对象才会被创建,而不是在程序启动之前就被创建了,所以我们在 类内定义的成员应该是一个静态指针 single_ptr,并且将其初始化为 nullptr,这样子当我们去调用 CreateObject() 的时候,如果判断 single_ptr 为空,则进行资源的初始化,否则说明已经被初始化过了,则不会再去初始化它,达到单例对象的目的!

​ 这个时候问题就来了,既然出现了判断以及对成员变量的操作,那么在多线程环境中就有可能会出现问题,所以我们就 需要加锁

​ 我们可以直接在类内定义一把 静态的锁 _mtx,然后在单例对象指针判空那个代码块前后分别上锁和解锁。但是这里其实还会涉及一个问题,因为我们的 single_ptr 是通过 new 出来的,那么 可能 new 还会抛异常导致死锁的问题,这个时候其实可以用异常捕获,但是我们一般不这么做,因为写法比较挫。

​ 一般我们都会用一个 守卫锁,在头文件 <mutex> 中就有一个函数模板 lock_guard 可以直接使用,这里为了便于理解,我们手动实现一个简易的守卫锁 LockGuard,具体看代码,其实不难,就是 在构造函数中上锁,在析构函数中解锁,所维护的就是一个锁对象!

​ 我们自行实现的守卫锁时候,可能会出现一些问题,比如我们在定义锁对象的时候,不能直接使用它对应的锁类型,因为我们在拷贝构造函数中初始化的时候,其实是通过拷贝一个锁对象来赋值的,但是问题来了,锁是不能拷贝的!那咋整❓❓❓

​ 这个时候我们就不能只是简单的定义一个锁对象,我们可以定义一个锁对象的引用或者指针,这里采用引用的方式!

​ 通过锁对象的引用,就必须在构造函数中进行初始化(C++ 语法规定),这样子的话我们引用的其实就是一个传过来的锁对象的别名,就能绕开锁不能赋值的问题了!

​ (搞不清楚这里在说什么的,可以看看下面代码中的守卫锁部分就懂了!)

​ 除此之外,我们会发现如果我们已经生成了一个单例对象,但是如果后续还有线程调用 CreateObject() 的时候,每次都会被我们的守卫锁卡住,这势必会导致我们程序的效率低下,所以这里我们 用两层 if 判空,减少对锁的消耗,虽说写起来比较冗余,但是这大大提高了程序的效率!

​ 另外,我们在上面提到过,单例模式一般来说是不需要释放的,但是还是避免不了有时候我们需要保存资源到日志啊等情况,那么我们就得对这个资源释放问题做一下处理,所以我们下面实现中多写了一个 静态成员函数 DeleteInstance() 用于处理资源释放问题,而我们可以在主程序或者其它函数中去手动释放它!

​ 但是如果我们想释放又忘记释放了呢❓❓❓所以为了保险,我们可以定义一个 自动回收资源类 GC 类(garbage control,实现并不难,我们可以将其定义在单例类里面,作为一个 内部类,这样子的话就能很方便的取到 Singleton 类中我们写的 DeleteInstance()

​ 而这个 GC 类实现的思想就是在析构函数中调用上述的 DeleteInstance(),要注意的是,因为有可能我们提前手动释放了这段空间,所以 我们需要判断 single_ptr 是否已经为空,是的话说明已经被释放,则我们不做任何动作,防止二次释放;如果不为空我们再去调用 DeleteInstance() 进行释放!

​ 这样子 GC 类就达到该目的:如果提前手动释放,则不会回收;如果没有提前手动释放,则会在这里自动释放!

​ 除此之外还有一个重点,就是我们定义的静态指针 single_ptr 得用 volatile 修饰,因为由于编译器可能会对代码进行优化,导致 重排序等问题,使用 volatile 关键字可以防止编译器优化,保证线程安全。

重排序的解释:

​ 重排序是指在编译器、处理器或者运行时系统中,由于优化等原因,指令执行的顺序可能会被改变,但是最终的执行结果与原本的代码保持一致。

在多线程编程中,重排序可能会导致线程安全问题,因为线程的执行顺序是不确定的,如果在代码中没有正确的同步措施,就有可能导致意想不到的结果。

​ 例如,在单例模式的实现中,如果不加同步措施,那么在多线程环境下,可能会出现多个实例被创建的情况。这是因为在创建实例的代码中,可能会发生指令重排序,导致另一个线程在检查实例是否为空之前,就已经获取到了一个未完成初始化的实例对象。

​ 为了避免这种情况,可以使用 volatile 关键字来修饰单例对象指针。volatile 关键字告诉编译器不要对这个变量进行重排序优化,从而保证了单例对象的正确创建。

// 这里单独写一个守卫锁是为了方便理解
template<class Lock>
class LockGuard
{
public:LockGuard(Lock& lock):_lock(lock){_lock.lock();}~LockGuard(){_lock.unlock();}
private:// 这里的_lock要用引用接收,不然如果只是一个Lock类型的对象,那么在构造函数中是不允许拷贝构造的(锁不允许拷贝)// 当然这里也可以用指针,只不过这里用引用更贴切c++的方式Lock& _lock; 
};// 懒汉模式
// 优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。
// 缺点:复杂
class Singleton
{
public:static Singleton& CreateObject(){// 涉及多线程,要加锁// 但是有可能new会抛异常导致死锁,所以我们可以用一个守卫锁// 除此之外,当前对象已经new出来之后,为了防止后面来的线程都会被锁住影响效率,我们可以用双层判断来防止这种情况if (single_ptr == nullptr){// std::lock_guard<mutex> lock(_mtx); // 当然也可以用库里的lock_guardLockGuard<mutex> lock(_mtx); // 使用守卫锁if (single_ptr == nullptr){single_ptr = new Singleton;}}return *single_ptr;}// 自动回收资源的管理类:// 如果提前手动释放,则不会回收;// 如果没有提前手动释放,则会在这里自动释放class GC{public:~GC(){// 如果没有被提前手动释放,则才会去释放,防止不小心多次释放if (single_ptr != nullptr){// 内部类是外部类的友元,可以直接调用DeleteInstance();}}};static GC _gc; // 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象// 一般我们不需要考虑释放// 但是如果我们想要保存资源的时候,就得处理一下static void DeleteInstance(){// 保存文件等操作,可自行添加// .......// 删除和保存的时候可能有多线程问题,要加锁LockGuard<mutex> lock(_mtx);if (single_ptr != nullptr){delete single_ptr;single_ptr = nullptr; // 记得置空,下一个线程进来的时候判断后就不会进入该代码块}cout << "资源处理完成,释放成功" << endl;}void Print(){cout << "懒汉模式::Print()" << endl;}
private:// 构造函数私有,并且不实现Singleton() {}// 拷贝构造以及赋值重载封掉Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;private:volatile static Singleton* single_ptr; // 单例对象指针,用volatile修饰,防止编译器过度优化static mutex _mtx;                     // 静态的互斥锁
};volatile Singleton* Singleton::single_ptr = nullptr; // 初始化为空
mutex Singleton::_mtx;
Singleton::GC Singleton::_gc;int main()
{// 第一种访问方法:通过CreateObject()直接调用相关接口Singleton::CreateObject().Print();// 第二种访问方法:可以使用引用接收CreateObject(),通过该对象调用相关接口Singleton& s = Singleton::CreateObject();s.Print();// s.DeleteInstance(); // 如果需要的话就提前手动释放一下//Singleton s1; // ❌//Singleton* s2 = new Singleton; // ❌//static Singleton s3; // ❌return 0;
}// 运行结果:
懒汉模式::Print()
懒汉模式::Print()
资源处理完成,释放成功

第二种写法:

​ 这种写法相比上面就简单多了,其实利用的是 C++11 的一个新特性:局部静态变量初始化是线程安全的!

​ 注意,这在 C++11 之前都是不保证的,所以这种方法不是通用的,但是也是很好用的一种!

​ 其实就是在 静态成员函数 CreateObject() 中直接创建一个局部静态变量,并且返回它的引用,我们都知道,因为局部静态变量对于这个静态成员函数来说只有一份,如果其已经先被初始化了,那么后续进来之后是不会有任何初始化工作的!并且依靠 C++11 更新的这个特性,我们 无需上锁

class Singleton
{
public:// 会不会有线程安全问题???// c++11之前,这里是不能保证single_object初始化是线程安全的!// c++11之后,这里是线程安全的!// 也就是说,c++11之后,局部静态变量初始化是线程安全的!// 所以这种写法不是通用的,比较少用,但是也是可以用的!static Singleton& CreateObject(){// 直接在CreateObject()创建一个静态单例类对象直接返回static Singleton single_object;return single_object;}void Print(){cout << "懒汉模式::Print()" << endl;}
private:// 构造函数私有,并且不实现Singleton() {}// 拷贝构造以及赋值重载封掉Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};int main()
{// 第一种访问方法:通过CreateObject()直接调用相关接口Singleton::CreateObject().Print();// 第二种访问方法:可以使用引用接收CreateObject(),通过该对象调用相关接口Singleton& s = Singleton::CreateObject();s.Print();//Singleton s1; // ❌//Singleton* s2 = new Singleton; // ❌//static Singleton s3; // ❌return 0;
}// 运行结果:
懒汉模式::Print()
懒汉模式::Print()

在这里插入图片描述

相关文章:

【C++】设计模式详解:单例模式

文章目录 Ⅰ. 设计一个类&#xff0c;不允许被拷贝Ⅱ. 请设计一个类&#xff0c;只能在堆上创建对象Ⅲ. 请设计一个类&#xff0c;只能在栈上创建对象Ⅳ. 请设计一个类&#xff0c;不能被继承Ⅴ. 请设计一个类&#xff0c;只能创建一个对象&#xff08;单例模式&#xff09;&am…...

在ubuntu下一键安装 Open WebUI

该脚本用于自动化安装 Open WebUI&#xff0c;并支持以下功能&#xff1a; 可选跳过 Ollama 安装&#xff1a;通过 --no-ollama 参数跳过 Ollama 的安装。自动清理旧目录&#xff1a;如果安装目录 (~/open-webui) 已存在&#xff0c;脚本会自动删除旧目录并重新安装。完整的依…...

【某大厂一面】数组和链表区别

在 Java 中&#xff0c;数组&#xff08;Array&#xff09;和链表&#xff08;LinkedList&#xff09;是两种常见的数据结构&#xff0c;它们在存储和操作方式上有显著的区别。了解它们的差异有助于选择适合特定应用场景的结构。下面是数组和链表之间的详细比较。 1. 存储结构…...

MySQL常用数据类型和表的操作

文章目录 (一)常用数据类型1.数值类2.字符串类型3.二进制类型4.日期类型 (二)表的操作1查看指定库中所有表2.创建表3.查看表结构和查看表的创建语句4.修改表5.删除表 (三)总代码 (一)常用数据类型 1.数值类 BIT([M]) 大小:bit M表示每个数的位数&#xff0c;取值范围为1~64,若…...

深入 Rollup:从入门到精通(三)Rollup CLI命令行实战

准备阶段&#xff1a;初始化项目 初始化项目&#xff0c;这里使用的是pnpm&#xff0c;也可以使用yarn或者npm # npm npm init -y # yarn yarn init -y # pnpm pnpm init安装rollup # npm npm install rollup -D # yarn yarn add rollup -D # pnpm pnpm install rollup -D在…...

3.日常英语笔记

screening discrepancies 筛选差异 The team found some screening discrepancies in the data. 团队在数据筛选中发现了些差异。 Don’t tug at it ,or it will fall over and crush you. tug 拉&#xff0c;拽&#xff0c;拖 He tugged the door open with all his might…...

sqlite3 学习笔记

文章目录 前言SQL的概念与表格相关的操作i.创建表格&#xff08;增&#xff09;ii 删除表格&#xff08;删&#xff09;iii 更改表格&#xff08;改&#xff09;iv 查询表格&#xff08;查&#xff09; 与记录相关的操作i 插入记录ii 删除记录iii 查询记录iv 修改记录 Linux中使…...

C++ | 红黑树

前言 本篇博客讲解c中数据结构红黑树&#xff0c;看这篇博客之前请先去看&#xff1a; C | AVL树_c avl树能有重复节点吗-CSDN博客 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青…...

使用Ollama 在Ubuntu运行deepseek大模型:以DeepSeek-coder为例

DeepSeek大模型这几天冲上热搜啦&#xff01; 咱们来亲身感受下DeepSeek模型的魅力吧&#xff01; 整个操作流程非常简单方便&#xff0c;只需要2步&#xff0c;先安装Ollama&#xff0c;然后执行大模型即可。 安装Ollama 在Ubuntu下安装Ollama非常简单&#xff0c;直接sna…...

詳細講一下RN(React Native)中的列表組件FlatList和SectionList

1. FlatList 基礎使用 import React from react; import { View, Text, FlatList, StyleSheet } from react-native;export const SimpleListDemo: React.FC () > {// 1. 準備數據const data [{ id: 1, title: 項目 1 },{ id: 2, title: 項目 2 },{ id: 3, title: 項目 3…...

《深度揭秘:TPU张量计算架构如何重塑深度学习运算》

在深度学习领域&#xff0c;计算性能始终是推动技术发展的关键因素。从传统CPU到GPU&#xff0c;再到如今大放异彩的TPU&#xff08;张量处理单元&#xff09;&#xff0c;每一次硬件架构的革新都为深度学习带来了质的飞跃。今天&#xff0c;就让我们深入探讨TPU的张量计算架构…...

QT使用eigen

QT使用eigen 1. 下载eigen https://eigen.tuxfamily.org/index.php?titleMain_Page#Download 下载后解压 2. QT引入eigen eigen源码好像只有头文件&#xff0c;因此只需要引入头文件就好了 qt新建项目后。修改pro文件. INCLUDEPATH E:\222078\qt\eigen-3.4.0\eigen-3.…...

工业“MCU+AI”

随着工业4.0的推进&#xff0c;传统工业设备正向智能化和自动化方向转型。这要求设备具备更高的算力、更强的实时处理能力以及支持AI算法的能力&#xff0c;以应对工业机器人、电机控制、预测性维护等复杂应用场景。 近年来越来越多的芯片厂商纷纷推出工业“MCUAI”产品&#…...

【Linux】Linux C判断两个IPv6地址是否有包含关系

功能说明 要判断两个 IPv6 地址是否具有包含关系&#xff0c;包括前缀的比较&#xff0c;可以通过以下步骤实现&#xff1a; 解析 IPv6 地址和前缀&#xff1a;将两个 IPv6 地址和它们的前缀长度解析为二进制形式。生成掩码&#xff1a;根据前缀长度生成掩码。按位比较&#…...

多模态论文笔记——TECO

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细解读多模态论文TECO&#xff08;Temporally Consistent Transformer&#xff09;&#xff0c;即时间一致变换器&#xff0c;是一种用于视频生成的创新模型&…...

AI学习(vscode+deepseek+cline)

1、网页生成不成功时&#xff0c;直接根据提示让模型替你解决问题 2、http://localhost:3000 拒绝链接时&#xff0c;cmd输入命令InetMgr&#xff0c;网站右键新建-配置你的网页代码物理地址&#xff0c;这里我还输入本机登录名及密码了&#xff0c;并把端口地址由默认80修改为…...

物业软件推动物业行业数字化转型 实现高效管理和优质客户体验

内容概要 在当今高速发展的数字化时代&#xff0c;物业软件的出现不仅使物业管理变得更加高效&#xff0c;也为行业转型提供了强大的支持。通过整合多种功能&#xff0c;物业软件显著提升了管理效率和客户体验。例如&#xff0c;在线收费和停车管理功能&#xff0c;让业主享受…...

WGCLOUD使用手册 - 登录验证码如何设置

登录页面默认是不用输入验证码的&#xff0c;但是我们也可以根据自己的实际场景&#xff0c;配置登录页面显示验证码&#xff0c;要求用户输入 提示&#xff1a;您需要需要升级到v3.5.3或以上版本&#xff0c;才可以支持此功能 我们在server配置文件里找到配置项vercodeCheck&…...

C# 9.0记录类型:解锁开发效率的魔法密码

一、引言&#xff1a;记录类型的神奇登场 在 C# 的编程世界中&#xff0c;数据结构就像是构建软件大厦的基石&#xff0c;其重要性不言而喻。然而&#xff0c;传统的数据结构定义方式&#xff0c;尤其是在处理简单的数据承载对象时&#xff0c;常常显得繁琐复杂。例如&#xf…...

Python 函数魔法书:基础、范例、避坑、测验与项目实战

Python 函数魔法书&#xff1a;基础、范例、避坑、测验与项目实战 内容简介 本系列文章是为 Python3 学习者精心设计的一套全面、实用的学习指南&#xff0c;旨在帮助读者从基础入门到项目实战&#xff0c;全面提升编程能力。文章结构由 5 个版块组成&#xff0c;内容层层递进…...

Unbutu虚拟机+eclipse+CDT编译调试环境搭建

问题1: 安装CDT&#xff0c;直接Help->eclipse Market space-> 搜cdt , install&#xff0c;等待重启即可. 问题2&#xff1a;C变量不识别vector ’could not be resolved 这是库的头文件没加好&#xff0c;右键Properties->C Build->Enviroment&#xff0c;增加…...

项目部署(springboot项目)

1、安装Nginx&#xff0c;并开启 2、前端项目打包&#xff1a;npm run build:prod--->dist 3、后端项目打包&#xff1a;install--->xxx.jar 4、开放需要的端口号&#xff1a;比如我的后端项目端口号为8282&#xff0c;则需要防火墙和服务器同时开发8282端口 5、将di…...

Spring MVC拦截器

文章目录 1. 拦截器(interceptor)的作用2. 拦截器和过滤器区别3. 拦截器是快速入门 1. 拦截器(interceptor)的作用 Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter&#xff0c;用于对处理器进行预处理和后处理。 将拦截器按一定的顺序联结成一条链&#xff0c;这条…...

Nginx 路由匹配(Nginx Route Matching)

从小白到高手&#xff1a;深入Nginx 路由匹配 在现代互联网应用中&#xff0c;Nginx 作为一款高性能的 Web 服务器&#xff0c;因其灵活性和高效性而广泛应用于各类网站和服务。Nginx 的路由匹配规则是其核心功能之一&#xff0c;负责决定如何处理传入的请求。通过这些规则&am…...

基于RIP的MGRE实验

实验拓扑 实验要求 按照图示配置IP地址配置静态路由协议&#xff0c;搞通公网配置MGRE VPNNHRP的配置配置RIP路由协议来传递两端私网路由测试全网通 实验配置 1、配置IP地址 [R1]int g0/0/0 [R1-GigabitEthernet0/0/0]ip add 15.0.0.1 24 [R1]int LoopBack 0 [R1-LoopBack0]i…...

Spring Boot 中的事件发布与监听:深入理解 ApplicationEventPublisher(附Demo)

目录 前言1. 基本知识2. Demo3. 实战代码 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 基本的Java知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&am…...

【Java基础-41.5】深入解析Java异常链:构建清晰的错误追踪体系

在Java编程中&#xff0c;异常处理是保证程序健壮性和可维护性的重要部分。然而&#xff0c;在实际开发中&#xff0c;异常往往不是孤立发生的&#xff0c;而是由一系列相关的异常引发的。为了更好地理解和处理这种复杂的异常场景&#xff0c;Java引入了 异常链&#xff08;Exc…...

STM32使用VScode开发

文章目录 Makefile形式创建项目新建stm项目下载stm32cubemx新建项目IED makefile保存到本地arm gcc是编译的工具链G++配置编译Cmake +vscode +MSYS2方式bilibiliMSYS2 统一环境配置mingw32-make -> makewindows环境变量Cmake CmakeListnijia 编译输出elfCMAKE_GENERATOR查询…...

特权模式docker逃逸

目录 1.环境 2.上线哥斯拉 3.特权模式逃逸 1.判断是否为docker环境 2.判断是否为特权模式 3.挂载宿主机磁盘到docker 4.计划任务反弹shell 1.环境 ubuntu部署一个存在CVE-2017-12615的docker: (ip:192.168.117.147) kali(ip:192.168.117.128) 哥斯拉 2.上线哥斯拉…...

装出字符串中国第一个匹配项的下标

hello 大家好&#xff01;今天开写一个新章节&#xff0c;每一天一道算法题。让我们一起来学习算法思维吧&#xff01; function strStr(haystack, needle) {return haystack.indexOf(needle); }// 测试示例 const haystack "sadbutsad"; const needle "sad&q…...

从腾讯云数据仓库TCHouse安全地转移数据到AWS Redshift

实现从AWS Direct Connect连接到腾讯云数据仓库TCHouse-P、TCHouse-C或TCHouse-D&#xff0c;然后使用AWS Glue读取数据并在AWS Redshift中创建对应表并复制数据&#xff0c;需要按照以下步骤进行操作&#xff1a; 网络连接设置 AWS Direct Connect配置&#xff1a; 在AWS管理…...

DataComp:探索下一代多模态数据集

目录 一、TL;DR 二、方法 2.1 为什么要单独研究数据质量&#xff1f; 2.2 数据质量的研究范式 三、其他的工作&#xff08;related work&#xff09; 3.1 传统的做法 3.2 数据剪枝和去重&#xff08;paper直接翻译&#xff09; 四、DataComp的benchmark 4.1 竞赛条件限…...

【linux】Linux 常见目录特性、权限和功能

目录特性默认权限主要功能/用途/根目录&#xff0c;所有目录的起点755文件系统的顶层目录&#xff0c;包含所有其他子目录和文件/bin基础二进制命令目录&#xff08;系统启动和修复必需的命令&#xff09;755存放所有用户可用的基本命令&#xff08;如 ls, cp, bash 等&#xf…...

基于SpringBoot电脑组装系统平台系统功能实现六

一、前言介绍&#xff1a; 1.1 项目摘要 随着科技的进步&#xff0c;计算机硬件技术日新月异&#xff0c;包括处理器&#xff08;CPU&#xff09;、主板、内存、显卡等关键部件的性能不断提升&#xff0c;为电脑组装提供了更多的选择和可能性。不同的硬件组合可以构建出不同类…...

Direct2D 极速教程(1) —— 画图形

极速导航 Direct2D 简介创建新项目&#xff1a;001-DrawGraphics弄一个白窗口在窗口上画图 Direct2D 简介 大家在学 WINAPI 的时候的时候有没有想过&#xff0c;怎么在一副窗口上画图呢&#xff1f;大家知道 Windows 系统是 GUI 图形用户界面 系统&#xff0c;以 Graphics 图形…...

DF 开发1

https://www.bilibili.com/video/BV1RFChYxEhJ/ 多个 workspace 图片上传 S3 上传大量文档 https://www.bilibili.com/video/BV1ySsEeUE6i 解决方案 返回 metadata https://www.bilibili.com/video/BV1t3e5eaENo 给出内容引用出处 模型负载均衡 可以以 ollama 在不同端口起服…...

[Computer Vision]实验二:图像特征点提取

目录 一、实验内容 二、实验过程及结果 2.1 Harris角点检测 2.2 SIFT算法 三、实验小结 一、实验内容 采用Harris与SIFT分别提取特征点及对应的描述子&#xff0c;对比两者的区别&#xff08;特征点数量、分布、描述子维度、图像变化对二者的影响等&#xff09;利用特征匹…...

在做题中学习(82):最小覆盖子串

解法&#xff1a;同向双指针——>滑动窗口 思路&#xff1a;题目要求找到s里包含t所有字符的最小子串&#xff0c;这就需要记录在s中每次查找并扩大范围时所包含进去的字符种类是否和t的相同&#xff0c;并且&#xff1a;题目提示t中会有重复字符&#xff0c;因此不能简单认…...

< OS 有关> BaiduPCS-Go 程序的 菜单脚本 Script: BaiduPCS-Go.Menu.sh (bdgo.sh)

目标&#xff1a; 使用 日本阿里云的 VPM 传输文件。 暂时方案&#xff1a; 使用 主机JPN 下载 https://huggingface.co/ 上模型从 JPN 放到 度狗上在家里从狗度下载 为了减少编程&#xff0c;尽量使用现在软件 &#xff0c;就找到 GitHub - qjfoidnh/BaiduPCS-Go: iikira…...

redis缓存和springboot缓存包冲突怎么办

如果Redis缓存与Spring Boot缓存包发生冲突&#xff0c;可以采取以下几种解决方案&#xff1a; 排除Spring Boot缓存包&#xff1a;在pom.xml文件中排除Spring Boot的缓存依赖&#xff0c;以避免与Redis缓存冲突。例如&#xff1a; <dependency><groupId>org.spr…...

云计算技术深度解析与代码使用案例

云计算技术深度解析与代码使用案例 引言 随着信息技术的飞速发展,云计算作为一种革命性的技术,正在逐步改变我们的生活和工作方式。云计算不仅提供了前所未有的计算能力和存储资源,还以其灵活性和可扩展性,成为现代企业数字化转型的重要支撑。本文将深入探讨云计算的核心…...

【教学类-89-01】20250127新年篇01—— 蛇年红包(WORD模版)

祈愿在2025蛇年里&#xff0c; 伟大的祖国风调雨顺、国泰民安、每个人齐心协力&#xff0c;共同经历这百年未有之大变局时代&#xff08;国际政治、AI技术……&#xff09; 祝福亲友同事孩子们平安健康&#xff08;安全、安全、安全&#xff09;、巳巳如意&#xff01; 背景需…...

React Router v6配置路由守卫

首先准备好以下页面 登录页&#xff1a;用户可以在此页面登录。 受保护页&#xff1a;只有登录的用户可以访问&#xff0c;否则会重定向到登录页。 公共页面&#xff1a;不需要鉴权&#xff0c;任何人都可以访问。 1. 安装依赖 首先&#xff0c;我们需要安装 react-router-do…...

双层Git管理项目,github托管显示正常

双层Git管理项目&#xff0c;github托管显示正常 背景 在写React项目时&#xff0c;使用Next.js,该项目默认由git托管。但是我有在项目代码外层记笔记的习惯&#xff0c;我就在外层使用了git托管。 目录如下 code 层内也有.git 文件&#xff0c;对其托管。 我没太在意&…...

Linux--权限

Linux系统的权限管理是保障系统安全的重要机制&#xff0c;以下详细讲解权限相关概念及操作指令&#xff1a; 一、基础权限机制 1. 权限的三元组&#xff0c;读&#xff08;r&#xff09;、写&#xff08;w&#xff09;、执行&#xff08;x&#xff09; 每个文件或目录有三组…...

第25章 项目启航前的密谈

在那弥漫着严谨与专注气息的会议室里&#xff0c;苏睿所长端坐在会议桌前&#xff0c;宛如一座沉稳的山峰&#xff0c;散发着一种让人安心的力量。他的神情认真而庄重&#xff0c;目光中透着几分感慨&#xff0c;仿佛在时光的长河中回溯着项目的点点滴滴。微微侧身看向东方艾艾…...

ModernBERT 为我们带来了哪些启示?

当谷歌在 2018 年推出 BERT 模型时&#xff0c;恐怕没有料到这个 3.4 亿参数的模型会成为自然语言处理领域的奠基之作。 六年后的今天&#xff0c;面对动辄千亿参数的大语言模型浪潮&#xff0c;Answer.AI、LightOn与 HuggingFace 联手打造的 ModernBERT 却选择了一条返璞归真的…...

【MySQL】--- 复合查询 内外连接

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; MySQL &#x1f3e0; 基本查询回顾 假设有以下表结构&#xff1a; 查询工资高于500或岗位为MANAGER的雇员&#xff0c;同时还要满足他们的姓名首字母为…...

Android Studio打包APK

1.导出APK安装包 如果是首次打包&#xff0c;Create new 单击蓝色对话框右边文件夹&#x1f4c2;图标 &#xff0c;选择密钥保存路径&#xff0c;然后在下方File name对话框中填写您想要名称&#xff0c;再点击OK回到密钥创建对话框。 在此对话框中填写密码&#xff08;Passwo…...

RKNN_C++版本-YOLOV5

1.背景 为了实现低延时&#xff0c;所以开始看看C版本的rknn的使用&#xff0c;确实有不足的地方&#xff0c;请指正&#xff08;代码借鉴了rk官方的仓库文件&#xff09;。 2.基本的操作流程 1.读取模型初始化 // 设置基本信息 // 在postprocess.h文件中定义&#xff0c;详见…...