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

c++从入门到精通(六)--特殊工具与技术-完结篇

文章目录

  • 特殊工具与技术-完结篇
    • 控制内存分配
    • 运行时类型识别
    • 成员指针
    • 嵌套类
    • 局部类
    • 固有的不可抑制特性
      • 位域
        • volatile限定符
        • 链接指示 extern "C"

特殊工具与技术-完结篇

控制内存分配

重载new和delete:

在这里插入图片描述

​ ==如果应用程序希望控制内存分配的过程,则它们需要定义自己的operator new函数和operator delete函数。==当自定义了全局的operator new函数和operator delete函数后,我们就担负起了控制动态内存分配的职责。这两个函数必须是正确的:因为它们是程序整个处理过程中至关重要的一部分。

​ 下面是标准库中定义的4个operator new和4个operator delete。我们可以自定义下面8个中的任意一个,当我们将运算符函数定义成类的成员时,他们是隐式静态的。当我们重载这些运算符时(3-8),必须使用noexcept异常说明符指定其不抛出异常。
在这里插入图片描述

​ 对于operator new函数或者operator new[]函数来说,它的返回类型必须是void*,第一个形参的类型必须是size_t且该形参不能含有默认实参。当编译器调用operator new时,把存储指定类型对象所需的字节数传给size_t形参;当调用operator new[]时,传入函数的则是存储数组中所有元素所需的空间。

​ 尽管在一般情况下,我们可以自定义具有任何形参的operator new,注意下面这种形式不能被用用户重载:

void *operator new (size_t,void*);

​ 对于operator delete函数或者operator delete[]函数来说,它们的返回类型必须是void,第一个形参的类型必须是void*。执行一条delete表达式将调用相应的operator函数,并用指向待释放内存的指针来初始化void*形参。

​ 当我们将operator delete或operator delete[]定义成类的成员时,该函数可以包含另外一个类型为size_t的形参。此时,该形参的初始值是第一个形参所指对象的字节数。size_t形参可用于删除继承体系中的对象。如果基类有一个虚析构函数(参见15.7.1节,第552页),则传递给operator delete的字节数将因待删除指针所指对象的动态类型不同而有所区别。而且,实际运行的operator delete函数版本也由对象的动态类型决定

​ 我们提供新的operator new函数和operator delete函数的目的在于改变内存分配的方式,但是不管怎样,我们都不能改变new运算符和delete运算符的基本含义。

​ **malloc函数与free函数:**当你定义了自己的全局operator new和operator delete后,这两个函数必须以某种方式执行分配内存与释放内存的操作。也许你的初衷仅仅是使用一个特殊定制的内存分配器,但是这两个函数还应该同时满足某些测试的目的,即检验其分配内存的方式是否与常规方式类似。

​ malloc函数接受一个表示待分配字节数的size_t,返回指向分配空间的指针或者返回0以表示分配失败。free函数接受一个void*,它是malloc返回的指针的副本,free将相关内存返回给系统。调用free(0)没有任何意义。

​ 下面是用malloc与free重载operator new和operator delete的一种简单方式

void *operator new (size_t size)
{if (void* mem = malloc(size))return mem;else throw bad_alloc();
void operator delete(void *mem) noexcept {free(mem);}

定位new表达式:我们可以使用alloctor类把内存分配和初始化分离(allocate和dealocate)。我们也可以直接调用operator new函数来分配内存,但此时不能用construct函数构造对象。相反,我们应该使用new的定位new形式来构造对象。形式如下:new(&sval) string(s)

在这里插入图片描述

place_address必须是一个指针,同时在initializers中提供一个(可能为空的)以逗号分隔的初始值列表,该初始值列表将用于构造新分配的对象。当仅通过一个地址值调用时,==定位new使用operator new(size_t,void*)“分配”它的内存。这是一个我们无法自定义的operator new版本。==该函数不分配任何内存,它只是简单地返回指针实参;然后由new表达式负责在指定的地址初始化对象以完成整个工作。事实上,定位new允许我们在一个特定的、预先分配的内存地址上构造对象。

定位new和construct的一个重要区别:传递给construct的指针必须指向同一个allocator对象分配的空间。传递给定位new的指针无需指向operator new分配的内存,甚至不需要指向动态内存。

我们可以显式调用new表达式初始化对象的析构函数,注意,调用析构函数可以销毁给定的对象,但是不会释放该对象所在的空间

运行时类型识别

​ 运行时类型识别(run-time type identification,RTTI)由两个运算符实现:typeid(用于返回表达式的类型)。dynamic_cast(用于将基类的指针或引用安全地转换成派生类的指针或引用)。当我们将这两个运算符用于某种类型的指针或引用,并且该类型含有虚函数,运算符将使用指针或引用所绑定对象的动态类型。

当我们想使用基类对象的指针或引用执行某个派生类的非虚函数时,我们可以使用上述两个运算符

dynamic_cast

如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个bad_cast异常。

在条件部分执行dynamic_cast操作可以确保类型转换和结果检查在同一条表达式中完成。

dynamic_cast<type*>(e);//e是一个有效的指针
dynamic_cast<type&>(e);//e是左值
dynamic_cast<type&&>(e);//e不能是左值
//上述所有形式:e必须是共有派生类|e是目标type的共有基类|e的类型就是type//【【【我们可以对一个空指针执行dynamic_cast,结果是所需类型的空指针。】】】

typeid运算符:

​ typeid表达式的形式是typeid(e),其中e可以是任意表达式或类型的名字。typeid操作的结果是一个常量对象的引用,该对象的类型是标准库类型type_info或者type_info的公有派生类型
在这里插入图片描述

==当typeid作用于指针时(而非指针所指的对象),返回的结果是该指针的静态编译时类型。==例如上述例子中typeid(bp)返回的类型是指针的静态类型Base*。

typeid是否需要运行时检查决定了表达式是否会被求值。只有当类型含有虚函数时,编译器才会对表达式求值。反之,如果类型不含有虚函数,则typeid返回表达式的静态类型;编译器无须对表达式求值也能知道表达式的静态类型。

如果表达式的动态类型可能与静态类型不同,则必须在运行时对表达式求值以确定返回的类型。这条规则适用于typeid(*p)的情况。如果p所知类型不含有虚函数,p不必是一个有效指针,否则p必须是一个有效指针。如果p是一个空指针,会抛出bad_typeid的异常。

使用RTTI解决派生类比较问题:

如果我们把相等运算符定义为虚函数,用不同的派生类各自实现的虚函数来实现相等判断。这回有一个问题,虚函数的基类版本和派生类版本必须就有相同的形参。如果我们想定义一个虚函数equal,则形参必须是基类的引用,此时equal函数只能比较基类成员。

我们可以使用RTTI解决上述问题。我们定义的相等运算符的形参是基类的引用,然后使用typeid检查两个运算对象的类型是否一致。如果运算对象的类型不一致,则==返回false;类型一致才调用equal函数。每个类定义的equal函数负责比较类型自己的成员。这些运算符接受Base&形参,但是在进行比较操作前先把运算对象转换成运算符所属的类类型。

在这里插入图片描述

type_info类
在这里插入图片描述

除此之外,因为type_info类一般是作为一个基类出现,所以它还应该提供一个公有的虚析构函数。type_info类没有默认构造函数,而且它的拷贝和移动构造函数以及赋值运算符都被定义成删除的。创建type_info对象的唯一途径是使用typeid运算符。

type_info类的name成员函数返回一个C风格字符串,表示对象的类型名字。对于某种给定的类型来说,name的返回值因编译器而异,并且不一定与在程序中使用的名字一致。对于name返回值的唯一要求是,类型不同则返回的字符串必须有所区别。

成员指针

数据成员指针

是指可以指向类的非静态成员的指针。但是成员指针指示的是类的成员,而非类的对象。当初始化一个这样的指针时,我们令其指向类的某个成员,但是不指定该成员所属的对象;直到使用成员指针时,才提供成员所属的对象。const string classname::*name;

auto name=&classname::contentsname是指向classname类contents成员的成员指针。

读者必须清楚的一点是,当我们初始化一个成员指针或为成员指针赋值时,该指针并没有指向任何数据。成员指针指定了成员而非该成员所属的对象,只有当解引用成员指针时我们才提供对象的信息。

在这里插入图片描述

返回数据成员指针的函数:

类的数据成员一般都是私有的,因此我们无法直接获得数据成员指针。类可以定义一个函数,返回数据成员指针。

class Screen{
public:static const std::string Screen::*data(){ return &Screen::contents;}//data是函数名字,返回类型是const std::string Screen::* 返回指向Screen string类型的成员的指针。
}

成员函数指针

和普通的函数指针类似,如果成员存在重载的问题,则我们必须显式地声明函数类型以明确指出我们想要使用的是哪个函数。

和普通的指针不同,成员函数和指向该成员的指针之间不存在自动转换规则,我们必须在成员函数名前加上取值符。
在这里插入图片描述

用数组保存成员函数指针:

class Screen{
public:using Action =Screen& (Screen::*)();Screen& home();Screen& forward();Screen& back();Screen& up();Screen& down();enum Directions{HOME,FORWARD,BACK,UP,DOWN};Screen& move(Directions);
private:static Action Menu[];//假定数组Menu中依次保存了每个光标移动函数的指针。(成员函数指针)
}Screen& Screen::move(Directions cm)
{return(this->*Menu[cm])();//cm使用的时候可以当作int来用,因此可以作为数组的偏移量。
}int main{Screen myScreen;myScreen.move(Screen::HOME);//使用Screen类中定义的枚举类型成员
}

为成员函数指针生成可调用对象:

成员函数指针不是一个可调用对象,我们必须使用具体的类型对象才能调用成员函数指针所指向的成员函数。因此如下的写法会报错(我们定义一个指向string中empty成员函数的指针,然后将该指针作为find_if的可调用对象实参,显然编译器会报错。

在这里插入图片描述

我们可以使用function生成一个可调用对象。我们告诉function一个事实:即empty是一个接受string参数并返回bool值的函数。通常情况下,执行成员函数的对象将被传给隐式的this形参。当我们想要使用function为成员函数生成一个可调用对象时,必须首先“翻译”该代码,使得隐式的形参变成显式的。

在这里插入图片描述

如果vector中存储的是对象的指针,则我们必须指定function接受指针。const string*指明成员函数在以指针方式传递的对象上执行的。
在这里插入图片描述

**使用mem_fn生成可调用对象:**mem_fn可以根据成员指针的类型推断可调用对象的类型,而无须用户显式地指定。mem_fn生成的可调用对象可以通过对象调用,也可以通过指针调用。实际上,我们可以认为mem_fn生成的可调用对象含有一对重载的函数调用运算符:一个接受string*,另一个接受string&。

find_if(svec.begin(),svec.end(),mem_fn(&string::empty));

使用bind生成可调用对象

在这里插入图片描述

和mem_fn类似的地方是,bind生成的可调用对象的第一个实参既可以是string的指针,也可以是string的引用

嵌套类

嵌套类可以声明在类的内部,定义在类的外部。嵌套类的静态成员定义位于外层类的作用域之外。

尽管嵌套类定义在其外层类的作用域中,但是读者必须谨记外层类的对象和嵌套类的对象没有任何关系。嵌套类的对象只包含嵌套类定义的成员;同样,外层类的对象只包含外层类定义的成员,在外层类对象中不会有任何嵌套类的成员。

class TextQuery{
public:class QueryResult;//QueryResult是一个嵌套类
}class TestQuery::QueryResult{//外部定义嵌套类
}

局部类

类可以定义在某个函数的内部,我们称这样的类为局部类(localclass)。局部类定义的类型只在定义它的作用域内可见。和嵌套类不同,局部类的成员受到严格限制。局部类的所有成员(包括函数在内)都必须完整定义在类的内部。因此,局部类的作用与嵌套类相比相差很远。

局部类中不能定义静态数据成员。局部类只能访问外层作用域定义的类型名、静态变量以及枚举成员

在这里插入图片描述

外层函数对局部类的私有成员没有任何访问特权。当然,局部类可以将外层函数声明为友元;或者更常见的情况是局部类将其成员声明成公有的。

可以在局部类的内部再嵌套一个类。此时,嵌套类的定义可以出现在局部类之外。嵌套类必须定义在与局部类相同的作用域中。局部类内的嵌套类也是一个局部类,必须遵循局部类的各种规定。【a内有一个局部类b,b类又嵌套了一个嵌套类c,则c的定义可以出现在b类作用域内。而b的定义只能出现在b的作用域内,不能出现在b外a内的地方。此时c也是一个局部类】

固有的不可抑制特性

位域

介绍

类可以将其(非静态)数据成员定义成位域(bit-field),在一个位域中含有一定数量的二进制位。当一个程序需要向其他程序或硬件设备传递二进制数据时,通常会用到位域。位域在内存中的布局是与机器相关的

位域的类型必须是整型或枚举类型(参见19.3节,第736页)。因为带符号位域的行为是由具体实现确定的,所以在通常情况下我们使用无符号类型保存一个位域。

typedef unsigned int Bit;
class File{Bit mode:2;//位域,占2位enum modes {READ=01,WARITE=02};}

如果可能的话,在类的内部连续定义的位域压缩在同一整数的相邻位,从而提供存储压缩。这些二进制位是否能压缩到一个整数中以及如何压缩是与机器相关的。

取地址运算符(&)不能作用于位域,因此任何指针都无法指向类的位域。

使用位域
在这里插入图片描述

volatile限定符

volatile的确切含义与机器有关,只能通过阅读编译器文档来理解。要想让使用了volatile的程序在移植到新机器或新编译器后仍然有效,通常需要对该程序进行某些改变。

直接处理硬件的程序常常包含这样的数据元素,它们的值由程序直接控制之外的过程控制。例如,程序可能包含一个由系统时钟定时更新的变量。当对象的值可能在程序的控制或检测之外被改变时,应该将该对象声明为volatile。关键字volatile告诉编译器不应对这样的对象进行优化。

在这里插入图片描述

只有volatile的成员函数才能被volatile的对象调用。只有当某个引用是volatile的时,我们才能使用一个volatile对象初始化该引用。
在这里插入图片描述

合成的拷贝对volatile对象无效:不能把一个非volatile引用绑定到一个volatile对象上。

在这里插入图片描述

尽管我们可以为volatile对象定义拷贝和赋值操作,但是一个更深层次的问题是拷贝volatile对象是否有意义呢?不同程序使用volatile的目的各不相同,对上述问题的回答与具体的使用目的密切相关。

链接指示 extern “C”

C++程序有时需要调用其他语言编写的函数,最常见的是调用C语言编写的函数。像所有其他名字一样,其他语言中的函数名字也必须在C++中进行声明,并且该声明必须指定返回类型和形参列表。对于其他语言编写的函数来说,编译器检查其调用的方式与处理普通C++函数的方式相同,但是生成的代码有所区别。C++使用链接指示(linkagedirective)指出任意非C++函数所用的语言。

要想把C++代码和其他语言(包括C语言)编写的代码放在一起使用,要求我们必须有权访问该语言的编译器,并且这个编译器与当前的C++编译器是兼容的。

链接指示不能出现在类定义或函数定义的内部。同样的链接指示必须在函数的每个声明中都出现。

在这里插入图片描述

指向C函数的指针与指向C++函数的指针是不一样的类型。一个指向C函数的指针不能用在执行初始化或赋值操作后指向C++函数,反之亦然。

在这里插入图片描述

导出C++语言到其他语言

通过使用链接指示对函数进行定义,我们可以令一个C++函数在其他语言编写的程序中可用:

在这里插入图片描述

编译器将为该函数生成适合于指定语言的代码。值得注意的是,可被多种语言共享的函数的返回类型或形参类型受到很多限制。例如,我们不太可能把一个C++类的对象传给C程序,因为C程序根本无法理解构造函数、析构函数以及其他类特有的操作。

相关文章:

c++从入门到精通(六)--特殊工具与技术-完结篇

文章目录 特殊工具与技术-完结篇控制内存分配运行时类型识别成员指针嵌套类局部类固有的不可抑制特性位域volatile限定符链接指示 extern "C" 特殊工具与技术-完结篇 控制内存分配 重载new和delete&#xff1a; ​ 如果应用程序希望控制内存分配的过程&#xff0c;…...

JDK 1.8 全解析:从核心特性到企业实战的深度实践

引言 JDK 1.8 作为 Java 生态发展史上的里程碑版本&#xff0c;自 2014 年发布以来&#xff0c;凭借 Lambda 表达式、Stream API、新日期时间 API 三大核心特性&#xff0c;彻底重塑了 Java 编程范式。本文结合 Oracle 官方文档、蚂蚁集团、京东零售等企业级实战案例&#xff…...

MCP实战:在扣子空间用扣子工作流MCP,一句话生成儿童故事rap视频

扣子最近迎来重要更新&#xff0c;支持将扣子工作流一键发布成MCP&#xff0c;在扣子空间里使用。 这个功能非常有用&#xff0c;因为我有很多业务工作流是在扣子平台上做的&#xff0c;两者打通之后&#xff0c;就可以在扣子空间里直接通过对话方式调用扣子工作流了&#xff0…...

分布式微服务系统架构第134集:笔记1运维服务器经验,高并发,大数据量系统

加群联系作者vx&#xff1a;xiaoda0423 仓库地址&#xff1a;https://webvueblog.github.io/JavaPlusDoc/ https://1024bat.cn/ https://github.com/webVueBlog/fastapi_plus https://webvueblog.github.io/JavaPlusDoc/ ✅ 一、查看端口是否被占用的常用命令 1️⃣ lsof 命令&…...

【SSL证书系列】客户端如何验证https网站服务器发的证书是否由受信任的根证书签发机构签发

客户端验证HTTPS网站证书是否由受信任的根证书颁发机构&#xff08;CA&#xff09;签发&#xff0c;是一个多步骤的过程&#xff0c;涉及证书链验证、信任锚&#xff08;Trust Anchor&#xff09;检查、域名匹配和吊销状态验证等。以下是详细的验证流程&#xff1a; 1. 证书链的…...

SpringBoot基础项目搭建

资料链接&#xff1a;https://download.csdn.net/download/ly1h1/90855288?spm1001.2014.3001.5501 1.准备工作 1.1 安装IntelliJ IDEA 2023.3.4 (Ultimate Edition) 1.2 采用apache-maven-3.6.3 1.2.1 maven配置文件设置 1.2.2 IDEA配置maven 1.3 JDK采用17版本 2.手动创建…...

Rust 学习笔记:关于 HashMap 的练习题

Rust 学习笔记&#xff1a;关于 HashMap 的练习题 Rust 学习笔记&#xff1a;关于 HashMap 的练习题以下代码能否通过编译&#xff1f;若能&#xff0c;输出是&#xff1f;以下代码能否通过编译&#xff1f;若能&#xff0c;输出是&#xff1f; Rust 学习笔记&#xff1a;关于 …...

C语言-8.数组

8.1数组 8.1.1初试数组 如何写一个程序计算用户输入的数字的平均数? #include<stdio.h> int main() {int digit;//输入要求平均数的数字double sum=0;//记录输入数字的和int count=0;//记录输入数字的个数printf("请输入一组数字,用来求平均数,以-1结束\n&quo…...

Kotlin Android单元测试MockK指南

目录 MockK 简介环境配置基础用法高级用法Android 特有场景最佳实践 1. MockK 简介 MockK 是一个专为 Kotlin 设计的 Mocking 框架&#xff0c;支持协程、扩展函数、对象声明&#xff08;object&#xff09;等 Kotlin 特性。相比 Mockito&#xff0c;它提供更自然的 Kotlin A…...

C# lock

在C#中&#xff0c;lock关键字用于确保当一个线程位于给定实例的代码块中时&#xff0c;其他线程无法访问同一实例的该代码块。这是一种简单的同步机制&#xff0c;用来防止多个线程同时访问共享资源或执行需要独占访问的代码段&#xff08;临界区&#xff09;&#xff0c;从而…...

《算法导论(第4版)》阅读笔记:p83-p85

《算法导论(第4版)》学习第 18 天&#xff0c;p83-p85 总结&#xff0c;总计 3 页。 一、技术总结 1. Strassen algorithm(施特拉森算法) 2.矩阵 (1)矩阵表示法 If we wish to refer to matrices without specifically writing out all their entries, we will use upperc…...

Go 后端中双 token 的实现模板

下面是一个典型的 Go 后端双 Token 认证机制 实现模板&#xff0c;使用 Gin 框架 JWT Redis&#xff0c;结构清晰、可拓展&#xff0c;适合实战开发。 项目结构建议 /utils├── jwt.go // Access & Refresh token 的生成和解析├── claims.go // 从请求…...

【拥抱AI】Deer-Flow字节跳动开源的多智能体深度研究框架

最近发现一款可以对标甚至可能超越GPT-Researcher的AI深度研究应用&#xff0c;Deer-Flow&#xff08;Deep Exploration and Efficient Research Flow&#xff09;作为字节跳动近期开源的重量级项目&#xff0c;正以其模块化、灵活性和人机协同能力引发广泛关注。该项目基于 La…...

第六天——贪心算法——字符串分隔

1. 题目 给定一个字符串 s&#xff0c;我们需要将其划分为尽可能多的部分&#xff0c;使得同一字母最多出现在一个部分中。 例如&#xff1a;字符串 "ababcc" 可以划分为 ["abab", "cc"]&#xff0c;但要避免 ["aba", "bcc&quo…...

Python 条件语句详解

条件语句是编程中用于控制程序流程的基本结构&#xff0c;Python 提供了几种条件语句来实现不同的逻辑判断。 1. if 语句 最基本的条件语句形式&#xff1a; if 条件:# 条件为真时执行的代码块示例&#xff1a; age 18 if age > 18:print("你已经成年了")2. …...

前端获取用户的公网 IP 地址

可以使用免费的免费的公共服务网站 一&#xff1a;https://www.ipify.org/ 获取 JSON 格式的 IP 地址 // 旧地址不好使 // https://api.ipify.org/?formatjson // 新地址 https://api64.ipify.org/?formatjson 二&#xff1a;https://ipinfo.io/ https://ipinfo.io/ 三&a…...

在Maven中替换文件内容的插件和方法

在Maven中替换文件内容的插件和方法 Maven提供了几种方式来替换文件内容&#xff0c;以下是常用的插件和方法&#xff1a; 1. maven-replacer-plugin (推荐) 这是专门用于文件内容替换的插件&#xff0c;功能强大且灵活。 基本配置 <plugin><groupId>com.goog…...

符合Python风格的对象(再谈向量类)

再谈向量类 为了说明用于生成对象表示形式的众多方法&#xff0c;我们将使用一个 Vector2d 类&#xff0c;它与第 1 章中的类似。这一节和接下来的几节会不断实 现这个类。我们期望 Vector2d 实例具有的基本行为如示例 9-1 所示。 示例 9-1 Vector2d 实例有多种表示形式 &g…...

云电竞服务器 工作原理

云电竞服务器工作原理详解 一、核心架构原理 虚拟化资源池‌ 通过 ‌KVM/VMware‌ 等虚拟化技术将物理服务器&#xff08;含NVIDIA GPU集群&#xff09;抽象为可动态分配的算力资源池&#xff0c;每个用户独享独立虚拟机实例&#xff0c;实现硬件资源的按需分配与隔离运行。 …...

【数据结构】线性表--队列

【数据结构】线性表--队列 一.什么是队列二.队列的实现1.队列结构定义&#xff1a;2.队列初始化函数&#xff1a;3.队列销毁函数&#xff1a;4.入队列函数&#xff08;尾插&#xff09;&#xff1a;5.出队列函数&#xff08;头删&#xff09;&#xff1a;6.取队头元素&#xff…...

[Vue3]语法变动

Vue3的语法相对比Vue2有不少改变&#xff0c;这篇讲一下基础语法在Vue3里的形式。 创建Vue对象 在脚手架项目中&#xff0c;index.html等资源不再编写代码&#xff0c;只作为一个容器。所有的页面代码都在.vue相关文件中进行编写&#xff0c;由main.js引入各个.vue文件渲染出页…...

Ubuntu服务器开启SNMP服务 监控系统配置指南 -优雅草星云智控简易化操作

Ubuntu服务器开启SNMP服务 & 监控系统配置指南 -优雅草星云智控简易化操作 一、Ubuntu服务器开启SNMP服务 步骤1&#xff1a;安装SNMP服务 sudo apt update sudo apt install snmp snmpd snmp-mibs-downloader -y 步骤2&#xff1a;配置SNMP&#xff08;编辑配置文件&am…...

linux本地部署ollama+deepseek过程

1.Tags ollama/ollama GitHub 选择一个版本下载&#xff0c;我下的是0.5.12 2.tar解压该文件 3.尝试启动ollama ollama serve 4.查看ollama的版本 ollama -v 5.创建一个系统用户 ollama&#xff0c;不允许登录 shell&#xff0c;拥有一个主目录&#xff0c;并且用…...

从零开始实现大语言模型(十五):并行计算与分布式机器学习

1. 前言 并行计算与分布式机器学习是一种使用多机多卡加速大规模深度神经网络训练过程&#xff0c;以减少训练时间的方法。在工业界的训练大语言模型实践中&#xff0c;通常会使用并行计算与分布式机器学习方法来减少训练大语言模型所需的钟表时间。 本文介绍PyTorch中的一种…...

OpenCV进阶操作:指纹验证、识别

文章目录 前言一、指纹验证1、什么是指纹验证2、流程步骤 二、使用步骤&#xff08;案例&#xff09;三、指纹识别&#xff08;案例&#xff09;1、这是我们要识别的指纹库2、这是待识别的指纹图3、代码4、结果 总结 前言 指纹识别作为生物识别领域的核心技术之一&#xff0c;…...

网络安全-等级保护(等保) 2-5 GB/T 25070—2019《信息安全技术 网络安全等级保护安全设计技术要求》-2019-05-10发布【现行】

################################################################################ GB/T 22239-2019 《信息安全技术 网络安全等级保护基础要求》包含安全物理环境、安全通信网络、安全区域边界、安全计算环境、安全管理中心、安全管理制度、安全管理机构、安全管理人员、安…...

3D生成新突破:阶跃星辰Step1X-3D开源,可控性大幅提升

Step1X-3D 是由 StepFun 联合 LightIllusions 推出的新一代 高精度、高可控性 3D资产生成框架。基于严格的 数据清洗与标准化流程&#xff0c;我们从 500万 3D资产 中筛选出 200万高质量数据&#xff0c;构建了 标准化的几何与纹理属性数据集&#xff0c;为3D生成提供更可靠的训…...

MySQL数据类型之VARCHAR和CHAR使用详解

在设计数据库字段时&#xff0c;字符串类型算是最常见的数据类型之一了&#xff0c;这篇文章带大家深入探讨一下MySQL数据库中VARCHAR和CHAR数据类型的基本特性&#xff0c;以及它们之间的区别。 VARCHAR类型 VARCHAR&#xff08;Variable Character&#xff0c;可变长度字符…...

数字人 LAM 部署笔记

目录 windos踩坑 GitHub - aigc3d/LAM: [SIGGRAPH 2025] LAM: Large Avatar Model for One-shot Animatable Gaussian Head windos踩坑 nvidia-smi环境 cuda 11.8conda install -c "nvidia/label/cuda-11.8.0" cuda-toolkit conda create --name cuda11.8 -y pyth…...

《Docker 入门与进阶:架构剖析、隔离原理及安装实操》

1 docker 简介 1.1 Docker 的优点 Docker 是一款开放平台&#xff0c;用于应用程序的开发、交付与运行&#xff0c;能将应用和基础架构分离&#xff0c;实现软件快速交付 &#xff0c;还能以统一方式管理应用和基础架构&#xff0c;缩短代码从编写到上线的时间。其核心优势如…...