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

01.让自己习惯C++

让自己习惯C++

条款1:视C++为一个语言联邦

条款1中提到了将C++看作为一个“语言联邦”的概念。具体来说,“语言联邦”是指将C++看作由多种不同的子语言组成的联邦。每种子语言都有自己的惯用法、工具和库,可以用来解决特定的问题。因此,C++程序员应该了解这些子语言,并选择最适合解决特定问题的子语言。 这个概念的含义可以从以下几个方面来解释:

  1. 多种子语言:C++由多种子语言组成,每种子语言都有自己的规则、习惯和约定。例如,面向对象编程(OOP)子语言、模板元编程(TMP)子语言等。这些子语言都有自己的语法和语义,可以用来解决特定的问题。
  2. 惯用法和工具:每种子语言都有自己的惯用法和工具。例如,OOP中常用的类、继承、多态等概念,以及与之对应的工具和库如STL、Boost等。熟悉这些惯用法和工具可以提高程序员的开发效率和代码质量。
  3. 选择最适合的子语言:C++程序员应该了解这些子语言,并选择最适合解决特定问题的子语言。例如,如果要处理大量的数值计算,可以选择使用TMP子语言中的模板元编程技术,来提高程序的性能如果要实现一些复杂的数据结构和算法,可以使用STL等库来简化代码

总的来说,可以将C++视为一个由4个次语言组成的联邦而非单一语言:

  1. C,说到底C++仍是以C为基础。
  2. object-oriented C++,包括封装、继承、多态等面向对象设计。
  3. template C++,泛型编程,衍生出模板元编程(在各个新标准中逐步完善)。
  4. STL,包括容器、迭代器、算法与函数对象。

条款2:尽量以const、enum、inline替换#define

条款2中提到了尽量使用constenuminline来替代#define的概念。具体来说,#define是一种预处理指令,可以将一个标识符定义为一个值或一个字符串。而constenuminline都是C++语言中的关键字,也可以用于定义常量和函数。以下是对这个条款的一些解释:

  1. #define的缺点:使用#define定义常量存在一些缺点,例如它不会进行类型检查,容易引起意外的副作用,也不会被语法检查工具正确地处理
  2. const的优点:使用const定义常量可以避免#define的缺点。const定义的常量有类型,可以被编译器检查和优化,也可以被调试器和其他工具正确地处理。
  3. enum的优点:如果要定义一系列相关的常量,可以使用enum枚举类型。enum定义的常量有类型,可以被编译器检查和优化,同时也可以提高代码的可读性和可维护性。
  4. inline的优点:如果要定义一个简单的函数或者函数模板,可以使用inline关键字。inline函数在编译时会被展开,从而避免了函数调用的开销。同时,inline函数也可以提高代码的可读性和可维护性。

#define可以用来定义一些变量、函数,但它只是一方面单纯的文本替换,并且没有任何类型检查,导致容易引起莫名其妙的问题,另一方面预处理后已经消失,编译链接过程中没有其符号信息,出问题时无法定位到它。

#define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b))int a=5,b=0;
CALL_WITH_MAX(++a,b);
CALL_WITH_MAX(++a,b+10);

即使上文的宏已经仔细地为所有参数添加小括号,仍然出现了问题:第一次调用中a被累加两次,第二次调用中a被累加一次。

CALL_WITH_MAX(++a,b)在展开后变成了f((++a)>(b)?(++a):(b)),其中a的值被多次递增。

CALL_WITH_MAX(++a,b+10)在展开后变成了f((++a)>(b+10)?(++a):(b+10)),其中a的值也被多次递增。

因此,这两个调用会导致a的值被递增多次,结果可能不是我们所期望的。

为了避免这个问题,更加可预测并且类型安全的写法是,可以使用函数模板来替代#define宏。使用const对象(对于一系列常量,使用枚举或枚举类,而不是一系列#define)

例如,可以定义一个template<typename T> inline void callWithMax(const T& a, const T& b)函数来替代CALL_WITH_MAX宏。

这样做不仅可以避免上述问题,还可以提高代码的可读性和可维护性。例如:

template<typename T>
inline void callWithMax(const T& a, const T& b)
{
f(a > b ? a : b);
}
int a = 5, b = 0;
callWithMax(++a, b);
callWithMax(++a, b + 10);
// 这段代码中,a的值只会被递增一次,符合我们的预期。
// 不过inline目前主要指多重定义而非内联

条款3:尽可能使用const

条款3中提到了尽可能使用const的概念。具体来说,const是C++语言中的关键字,用于定义常量。以下是对这个条款的一些解释:

  1. const的作用:使用const可以将变量定义为常量,即不能被修改。常量可以提高代码的可读性和可维护性,同时也可以避免意外的修改导致的错误。
  2. const的使用场景:在C++中,const可以用于定义常量、函数参数和函数返回值等。使用const定义常量时,可以使用const关键字加上变量的类型,例如const int MAX_SIZE = 1024;。使用const定义函数参数时,可以在参数类型前加上const关键字,例如void foo(const std::string& str);。使用const定义函数返回值时,可以在函数声明和定义中返回类型前加上const关键字,例如const std::string& foo() const;
  3. const的作用域:在C++中,const变量和const函数的作用域与普通变量和函数的作用域相同。如果const变量或const函数在某个作用域内定义,那么它们只能在该作用域内使用。
  4. const和指针:使用指针时,const可以用于限定指针本身或指针所指向的内容是否可修改。例如,const int* p表示指向const int类型的指针,即指针所指向的内容不能被修改;int* const p表示指向int类型的const指针,即指针本身不能被修改。另外,const还可以同时限定指针本身和指针所指向的内容是否可修改,例如const int* const p表示指向const int类型的const指针。
char greeting[] = "Hello";
char* p1 = greeting;
const char* p2 = greeting;       //被指物不可修改
char* const p3 = greeting        //指针不可修改
const char* const p4 = greeting; //皆不可修改

真正威力强大的用法是面对函数声明时,const可以和函数返回值、各参数、成员函数自身产生关联。例如令函数返回const,往往可以降低因用户错误而造成的意外,又不至于放弃安全性和高效性。

class Rational{...};
const Rational operator*(const Rational& lhs,const Rational& rhs);
//上述写法可以避免用户写出 a*b = c

对于成员函数自身的const,编译器强制实施bitwise const,即强制不能修改任何成员变量。**这意味着,在const成员函数中,即使我们使用了mutable关键字,也不能修改任何非mutable成员变量。**但实际上很多情况下我们需要的是logical const,即const成员函数也应该可以修改某些客户不可见的数据,这时可以用mutable成员变量来绕过const成员函数的限制。

例如对于一个文本块的对象而言,其内部很可能存在高速缓存;对于查询文本块长度这样的const操作,仍然需要更新高速缓存:

class TextBlock{
public:std::size_t length() const;
private:char *pText;mutable std::size_t text_length;mutable bool length_is_valid;
};std::size_t TextBlock::length() const{if(!length_is_valid){text_length = std::strlen(pText);length_is_valid = true;}return text_length;
};

这是一个名为TextBlock的类,其中包含一个私有成员变量char *pText,表示一个C风格的字符串。该类还包含了两个mutable类型的私有成员变量std::size_t text_lengthbool length_is_valid,用于缓存字符串长度和标记长度是否已经被计算。该类还定义了一个公有成员函数std::size_t length() const,用于获取字符串的长度。下面是对该类的解释:

  1. TextBlock类中的char *pText表示一个C风格的字符串,但是没有提供构造函数或析构函数来管理字符串的内存,这样会存在内存泄漏的风险,需要在类中添加构造函数和析构函数来管理字符串的内存。
  2. **TextBlock类中的text_lengthlength_is_valid成员变量被声明为mutable类型,表示即使在const函数中也可以被修改。**这是因为length()函数需要计算字符串的长度,如果多次调用该函数,每次都重新计算字符串长度会浪费时间,因此使用mutable类型的成员变量缓存计算结果,避免重复计算。
  3. TextBlock类中的length()函数是一个const函数,表示该函数不会修改类的成员变量,因此可以在const对象中调用。在函数中使用!length_is_valid判断是否需要重新计算字符串长度,如果需要计算,则调用std::strlen(pText)计算字符串长度,再将计算结果缓存到text_length中,并将length_is_valid标记为true。最后,返回缓存的字符串长度。
  4. 由于TextBlock类中的pText变量是一个C风格的字符串,并且没有提供构造函数和析构函数来管理内存,因此在使用该类时需要特别注意内存泄漏的问题。可以通过使用std::string等C++标准库提供的字符串类型来避免这个问题。

C++中两个函数如果只是常量性不同,也可以重载。当const成员函数与非const成员函数有着实质等价的实现时,为了避免冗余,可以令non-const版本调用const版本:

class TextBlock{
public:const char& operator[](std::size_t position) const{...}char& operator[](std::size_t position){return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);}
};
//后者首先将自身转换为const对象
//随后调用const成员函数,返回const引用
//最后转换为non-const引用

这是一个名为TextBlock的类,其中定义了两个下标运算符operator[],用于访问类中的字符数据。第一个下标运算符是一个const成员函数,返回一个const char&类型的引用,表示在指定位置的字符数据。第二个下标运算符是一个非const成员函数,返回一个char&类型的引用,表示在指定位置的字符数据。下面是对该代码的解释:

  1. 第一个下标运算符是一个const成员函数,表示该函数不会修改类的成员变量。在函数中,使用const关键字修饰函数的返回值,表示返回的是一个常量引用。该函数返回指定位置的字符数据,并且由于返回的是一个常量引用,因此客户端无法通过该函数修改类的成员变量。
  2. 第二个下标运算符是一个非const成员函数,表示该函数可以修改类的成员变量。在函数中,我们使用了const_caststatic_cast两个操作符,将该函数转换成了一个const成员函数的调用。具体来说,我们首先使用static_cast<const TextBlock&>(*this)将当前对象转换成一个const TextBlock&类型的对象,然后调用第一个下标运算符,返回在指定位置的字符数据的常量引用。接着,我们使用const_cast<char&>将常量引用转换为一个非常量引用,从而使得客户端可以通过该函数修改类的成员变量。需要注意的是,这种使用const_cast的方式是有风险的,因为它可以绕过函数的const限制,可能导致程序的未定义行为和内存安全问题。
  3. 如果我们希望在第二个下标运算符中修改一些客户端不可见的数据,可以使用mutable关键字修饰一个成员变量,避免使用const_cast绕过const限制。

条款4:确定对象被使用前已先被初始化

条款4的意思是,在使用一个对象之前,必须确保该对象已经被正确地初始化。如果一个对象没有被正确地初始化,那么它的行为是未定义的,可能会导致程序崩溃、数据损坏等不可预测的结果。 在C++中,对象的初始化方式有多种,包括默认初始化、值初始化、直接初始化、拷贝初始化等。不同的初始化方式会对对象的状态产生不同的影响。为了保证对象被正确地初始化,我们应该遵循以下几个原则:

  1. **明确对象的初始化方式。**在定义对象时,应该清楚地指定对象的初始化方式,避免使用未初始化的对象。
  2. **尽可能使用构造函数进行初始化。**构造函数是一种专门用于初始化对象的函数,可以保证对象的状态正确。因此,在定义对象时,应该尽可能使用构造函数进行初始化。
  3. **避免使用未定义的对象。**在使用对象之前,应该确保对象已经被正确地初始化。如果不确定对象是否已经被初始化,就应该避免使用该对象。
  4. **避免使用未定义的成员变量。**在定义类时,应该确保类的成员变量都被正确地初始化。如果一个成员变量没有被正确地初始化,那么该成员变量的行为也是未定义的,可能会导致程序崩溃、数据损坏等不可预测的结果。

C++中变量并非一定会进行初始化。最佳处理办法是:对于内置类型必须手动初始化,而对于用户定义的对象,在使用对象前将其初始化(责任落在构造函数上)。

构造函数包含成员初值列与函数体。

  1. 最好使用成员初始列的初始化而非函数体内的赋值,否则对象会在成员初始列的步骤中进行默认初始化,再在赋值的过程中进行拷贝,成本增高。
  2. 成员初始列的排列顺序应与在类中的声明次序一致,因为成员初始化顺序只与后者有关,前者若与后者不一致的话可能导致误解。

只剩最后一个难点:函数内的静态变量称为local静态变量,其他的都是non-local;而不同编译单元(一个编译单元指产出单一目标文件的源码们)内定义的non-local静态对象的初始化顺序并未规定。倘若存在这样的两个变量a和b,且b的初始化需要使用a,如果a尚未初始化就被b使用了,显然程序会出错。

local静态变量指的是函数内定义的静态变量,只在函数的作用域内可见;

而non-local静态变量指的是在全局作用域或命名空间内定义的静态变量,可以被多个函数使用。

在C++中,对于non-local静态变量的初始化顺序并没有严格的规定。这意味着,如果存在两个non-local静态变量a和b,且b的初始化需要使用a,那么如果a尚未初始化就被b使用了,就会导致程序出错。这是因为,如果a尚未初始化,那么它的值是不确定的,可能是一个随机值,也可能是0或其他默认值。如果b在使用a之前被初始化,那么它使用的a的值是不确定的,这可能会导致程序出错。

为了避免这种问题,我们可以采用一些编程技巧和约定来确保non-local静态变量的正确初始化顺序。例如,可以使用单例模式等设计模式来确保对象的初始化顺序;或者可以将non-local静态变量的初始化工作放在函数内部,以确保它们在第一次使用之前被正确地初始化。此外,我们还可以使用编译器提供的一些选项来控制non-local静态变量的初始化顺序,但这种方法并不是跨平台的,可能会导致代码的可移植性问题。

解决方法也很简单:将每个non-local静态变量移到自己的专属函数内,这些函数返回该静态变量的引用,用户使用这些函数而非直接使用变量(类似单例模式)。至此,non-local静态变量被local静态变量取代。

class FileSystem{...};
FileSystem& tfs(){static FileSystem fs;return fs;
}
class Directory{...};
Directory::Directory(...){...std::size_t disks = tfs().num_disks();...
}

这段代码定义了一个名为FileSystem的类和一个名为tfs()的函数,以及另一个名为Directory的类和它的一个构造函数。

tfs()函数内部,定义了一个名为fs的静态对象,它是FileSystem类的一个实例,并且返回了这个静态对象的引用。

Directory类的构造函数内部,首先执行了一些初始化工作,然后通过调用tfs()函数获取到了FileSystem对象的引用,并通过该引用调用了num_disks()函数,将返回值存储在了一个名为disks的变量中。

由于tfs()函数内部定义的fs对象是一个静态对象,因此它在程序运行期间只会被创建一次,并且在整个程序的生命周期内都存在。

每次调用tfs()函数时,都会返回同一个静态对象的引用。这种方式可以保证FileSystem类的实例只有一个,并且可以在全局范围内被访问。

Directory类的构造函数内部,通过调用tfs()函数获取到了FileSystem对象的引用,并且调用了它的num_disks()函数,这种方式可以确保Directory类的实例可以访问到全局唯一的FileSystem对象,并且可以获取到该对象的属性和方法。

总之,这段代码通过使用静态变量和函数,实现了一个全局唯一的FileSystem对象,并且可以在其他类的构造函数中使用该对象,从而避免了对象的多次创建和初始化,提高了程序的效率和可读性。同时,该代码还展示了C++中静态变量和静态函数的用法,可以作为学习C++语言的参考。

相关文章:

01.让自己习惯C++

让自己习惯C 条款1&#xff1a;视C为一个语言联邦 条款1中提到了将C看作为一个“语言联邦”的概念。具体来说&#xff0c;“语言联邦”是指将C看作由多种不同的子语言组成的联邦。每种子语言都有自己的惯用法、工具和库&#xff0c;可以用来解决特定的问题。因此&#xff0c;…...

ElementUI table+dialog实现一个简单的可编辑的表格

table组件如何实现可编辑呢&#xff1f; 我的需求是把table组件那样的表格&#xff0c;实现它点击可以弹出一个框&#xff0c;然后在这个框里面输入你的东西&#xff0c;然后将他回显回去&#xff0c;当然&#xff0c;输入的有可能是时间啥的。 为什么要弹出弹层不在框上直接…...

Rust语言精讲:数据类型全解析

大家好&#xff01;我是lincyang。 今天&#xff0c;我们将深入探讨Rust语言中的数据类型&#xff0c;这是理解和掌握Rust的基础。 Rust语言数据类型概览 Rust是静态类型语言&#xff0c;所有变量类型在编译时确定。Rust的数据类型分为两类&#xff1a;标量类型和复合类型。…...

《数据结构、算法与应用C++语言描述》-代码实现散列表(线性探查与链式散列)

散列表 完整可编译运行代码&#xff1a;Github:Data-Structures-Algorithms-and-Applications/_22hash/ 定义 字典的另一种表示方法是散列&#xff08;hashing&#xff09;。它用一个散列函数&#xff08;也称哈希函数&#xff09;把字典的数对映射到一个散列表&#xff08…...

Hadoop学习笔记:运行wordcount对文件字符串进行统计案例

文/朱季谦 我最近使用四台Centos虚拟机搭建了一套分布式hadoop环境&#xff0c;简单模拟了线上上的hadoop真实分布式集群&#xff0c;主要用于业余学习大数据相关体系。 其中&#xff0c;一台服务器作为NameNode&#xff0c;一台作为Secondary NameNode&#xff0c;剩下两台当…...

python编写简单登录系统(密码混淆加密)

输入非123的数字会显示输入123选项&#xff0c;输入空格或者回车会报错&#xff0c;因为choice设置成int型先输入2个正常账户进去预防了用户名为空&#xff0c;密码为空或者小于3个&#xff0c;用户名已存在3种情况只有用户名和对应的密码都输入正确才能登录成功输入选项3退出代…...

UVA1025 城市里的间谍 A Spy in the Metro

UVA1025 城市里的间谍 A Spy in the Metro 题面翻译 题目大意 某城市地铁是一条直线&#xff0c;有 n n n&#xff08; 2 ≤ n ≤ 50 2\leq n\leq 50 2≤n≤50&#xff09;个车站&#xff0c;从左到右编号 1 … n 1\ldots n 1…n。有 M 1 M_1 M1​ 辆列车从第 1 1 1 站开…...

【科普知识】什么是步进电机?

德国百格拉公司于1973年发明了五相混合式步进电机及其驱动器&#xff0c;1993年又推出了性能更加优越的三相混合式步进电机。我国在80年代以前&#xff0c;一直是反应式步进电机占统治地位&#xff0c;混合式步进电机是80年代后期才开始发展。 步进电机是一种用电脉冲信号进行…...

AWS云服务器EC2实例实现ByConity快速部署

1. 前言 亚马逊是全球最大的在线零售商和云计算服务提供商。AWS云服务器在全球范围内都备受推崇&#xff0c;被众多业内人士誉为“云计算服务的行业标准”。在国内&#xff0c;亚马逊AWS也以其卓越的性能和服务满足了众多用户的需求&#xff0c;拥有着较高的市场份额和竞争力。…...

Docker的项目资源参考

Docker的项目资源包括以下内容&#xff1a; Docker官方网站&#xff1a;https://www.docker.com/ Docker Hub&#xff1a;https://hub.docker.com/ Docker文档&#xff1a;https://docs.docker.com/ Docker GitHub仓库&#xff1a;https://github.com/docker Docker官方博客…...

wsl-ubuntu 系统端口总被主机端口占用问题解决

wsl-ubuntu 系统端口总被主机端口占用问题解决 0. 问题描述1. 解决方法 0. 问题描述 wsl-ubuntu 子系统中的服务&#xff0c;总是启动失败&#xff0c;错误信息是端口被占用。 用一些命令查看&#xff0c;被占用的端口也没有用服务启动。 1. 解决方法 运行&#xff0c; ne…...

详解自动化之单元测试工具Junit

目录 1.注解 1.1 Test 1.2 BeforeEach 1.3 BeforeAll 1.4 AfterEach 1.5 AfterAll 2. 用例的执行顺序 通过 order() 注解来排序 3. 参数化 3.1 单参数 3.2 多参数 3.3 多参数(从第三方csv文件读取数据源) 3.4 动态参数ParameterizedTest MethodSource() 4. 测试…...

超声波雪深传感器冬季里的科技魔法

在冬季的某个清晨&#xff0c;当你打开大门&#xff0c;被厚厚的积雪覆盖的大地映入眼帘&#xff0c;你是否曾想过&#xff0c;这片雪地的深度是多少&#xff1f;它又如何影响着我们的生活和环境&#xff1f;今天&#xff0c;我们将为你揭开这个谜团&#xff0c;介绍一款神秘的…...

2023年【熔化焊接与热切割】免费试题及熔化焊接与热切割模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 熔化焊接与热切割免费试题是安全生产模拟考试一点通生成的&#xff0c;熔化焊接与热切割证模拟考试题库是根据熔化焊接与热切割最新版教材汇编出熔化焊接与热切割仿真模拟考试。2023年【熔化焊接与热切割】免费试题及…...

【数据结构】—搜索二叉树(C++实现,超详细!)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;消えてしまいそうです—真夜中 1:15━━━━━━️&#x1f49f;──────── 4:18 &#x1f504; ◀️ ⏸ ▶️…...

机器人算法—ROS TF坐标变换

1.TF基本概念 &#xff08;1&#xff09;什么是TF&#xff1f; TF是Transformations Frames的缩写。在ROS中&#xff0c;是一个工具包&#xff0c;提供了坐标转换等方面的功能。 tf工具包&#xff0c;底层实现采用的是一种树状数据结构&#xff0c;根据时间缓冲并维护多个参考…...

路由VRRP配置例子

拓朴如下&#xff1a; 主要配置如下&#xff1a; [R1] interface GigabitEthernet0/0/0ip address 10.1.1.1 255.255.255.0 vrrp vrid 1 virtual-ip 10.1.1.254vrrp vrid 1 priority 200vrrp vrid 1 preempt-mode timer delay 20 # interface GigabitEthernet0/0/1ip address …...

OpenGL 绘制点与三角形(Qt)

文章目录 一、简介二、实现代码三、实现效果一、简介 这里对OpenGL中点与三角形相关绘制操作进行封装,方便后续点云数据与模型数据的渲染。 二、实现代码 这里我们先创建一个基类Drawable,后续的点、线、面等,均会继承该类: Drawable.h #ifndef DRAWABLE_H #define DRAWABL…...

究竟什么是阻塞与非阻塞、同步与异步

文章目录 前言阻塞与非阻塞同步与异步复杂的网络IO真正的异步IOIO分类与示例总结 前言 这几个名词在程序开发时经常听到&#xff0c;但是突然问起来各个词的含义一时间还真是说不清楚&#xff0c;貌似这几个词都是翻译过来的&#xff0c;每个人的解释都不太一样&#xff0c;我…...

Openlayer【三】—— 绘制多边形GeoJson边界绘制

1.1、绘制多边形 在绘制多边形和前面绘制线有异曲同工之妙&#xff0c;多边形本质上就是由多个点组成的线然后连接组成的面&#xff0c;这个面就是最终的结果&#xff0c;那么这里使用到的是Polygon对象&#xff0c;而传给这个对象的值也是多个坐标&#xff0c;坐标会一个个的…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

ui框架-文件列表展示

ui框架-文件列表展示 介绍 UI框架的文件列表展示组件&#xff0c;可以展示文件夹&#xff0c;支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项&#xff0c;适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...

规则与人性的天平——由高考迟到事件引发的思考

当那位身着校服的考生在考场关闭1分钟后狂奔而至&#xff0c;他涨红的脸上写满绝望。铁门内秒针划过的弧度&#xff0c;成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定"&#xff0c;构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...

对象回调初步研究

_OBJECT_TYPE结构分析 在介绍什么是对象回调前&#xff0c;首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例&#xff0c;用_OBJECT_TYPE这个结构来解析它&#xff0c;0x80处就是今天要介绍的回调链表&#xff0c;但是先不着急&#xff0c;先把目光…...

SQL进阶之旅 Day 22:批处理与游标优化

【SQL进阶之旅 Day 22】批处理与游标优化 文章简述&#xff08;300字左右&#xff09; 在数据库开发中&#xff0c;面对大量数据的处理任务时&#xff0c;单条SQL语句往往无法满足性能需求。本篇文章聚焦“批处理与游标优化”&#xff0c;深入探讨如何通过批量操作和游标技术提…...