深度解析C++异常处理机制:分类、处理方式、常见错误及11新增功能
C++ 基础知识 八 异常处理 上篇
- 一、基础
- 1. 异常的概念
- 2. 异常的分类
- 2.1 内置异常
- 2.2 自定义异常
- 3. 异常的处理方式
- 3.1 try-catch 语句
- 3.2 throw 语句
- 3.3 noexcept 修饰符
- 3.4 finally 语句块
- 二、 异常处理机制
- 1 try-catch 语句块
- 2 异常处理流程
- 3 标准异常类
- 三、 抛出异常
- 1 throw语句
- 2 异常类型
- 3 异常传递
- 四、 捕获异常
- 1 catch语句
- 2 多个catch语句的顺序与匹配规则
- 3 异常处理机制的使用示例
- 五、 C++11 新增异常功能
- 1 noexcept操作符
- 2 异常列表(function try-block)
- 六、常见错误和异常处理
- 1 空指针异常
- 2 内存泄漏异常
- 3 数组越界异常
- 4 死锁异常
一、基础
1. 异常的概念
异常是程序在运行过程中出现非正常情况的处理机制。当出现异常时程序会停止运行并调用异常处理程序。
2. 异常的分类
异常可以分为内置异常和自定义异常
2.1 内置异常
C++ 标准库提供了许多预定义的异常类,称为内置异常,包括以下几种:
std::exception
:所有标准异常类的基类。std::logic_error
:表示程序逻辑错误。std::runtime_error
:表示运行时错误。
2.2 自定义异常
除了使用内置异常,我们还可以创建自定义异常类来处理特定错误。自定义异常类可以继承自内置异常类以实现异常的精细控制。
3. 异常的处理方式
C++ 提供了以下几种处理异常的方式:
3.1 try-catch 语句
try {// 可能会抛出异常的代码块
} catch (exception1_type exception1_var) {// 处理异常类型1
} catch (exception2_type exception2_var) {// 处理异常类型2
}
使用 try
代码块来包含可能抛出异常的代码,紧跟 catch
块来处理捕获到的异常。当抛出异常后,程序会自动匹配 catch
块中与对应异常相同类型的代码块执行,保证程序正常执行。
3.2 throw 语句
throw exception_object;
使用 throw
语句抛出一个异常对象,使程序进入异常处理模式。 exception_object
可以是基本类型或对象,甚至可以是自定义类型的实例。
3.3 noexcept 修饰符
void function_name() noexcept {// 不会抛出异常的函数
}
noexcept 修饰符指示函数不抛出异常。使用 noexcept
可以优化程序性能。当程序遇到一个没有 noexcept
修饰符的函数,会假设这个函数可能抛出异常,导致额外的代码执行。
3.4 finally 语句块
try{// 可能抛出异常的代码块
} catch(...) {// 处理异常
} finally {// 无论有无异常都执行
}
finally 语句在 try-catch 语句的末尾执行,无论异常是否抛出。通常用于释放资源等程序收尾工作。
综上所述异常处理是程序设计中重要而必不可少的一部分。了解常见的异常处理方式,可以让我们更加高效地处理程序中的错误,并确保程序的正常运行。
二、 异常处理机制
C++中的异常处理机制用于处理程序运行过程中的异常情况。异常可以是程序中的一种错误或者突发事件,可能会导致程序崩溃,但是正常情况下我们希望程序可以平稳地运行下去,去处理这些异常情况。在这样的情况下, C++的异常处理机制发挥了巨大的作用。
1 try-catch 语句块
try-catch 是处理 C++ 异常的关键工具。它的主要作用是将异常处理分离出代码,将异常在运行时捕获并处理。
try {// 可能引发异常的代码块
} catch (Type1 arg1) {// 处理Type1类型的异常
} catch (Type2 arg2) {// 处理Type2类型的异常
} catch (Type3 arg3) {// 处理Type3类型的异常
}
当一个异常被抛出的时候(通常是使用 throw 语句),与抛出异常的类型相匹配的 catch 块会被调用,它会处理异常并从这个异常中恢复程序执行。
2 异常处理流程
异常处理的整个过程是一种顺序执行模型,以下是它的基本流程:
- 程序执行到可能抛出异常的代码时,这段代码必须嵌入到 try 块中。
- 如果在 try 块中的代码引发了异常,程序会跳转到与抛出异常类型匹配的 catch 块中,catch 块负责处理异常。
- 最后程序会从 catch 块中退出,向下执行任何后续代码。
简单来说,我们可以将异常处理机制的处理过程看作是程序运行时一条流程线,它沿着 try-catch 块执行,遇到异常时跳转 catch 块那里处理异常,最后退出 catch 块。
3 标准异常类
C++ 标准库中定义了一些异常类,这些异常类是所有 C++ 应用程序都可以使用的。由于这些异常类是预定义的,因此它们都是放在 std 命名空间之下。
C++ 标准库提供的异常类:
std::exception
—— 所有标准异常类的基类。std::bad_alloc
—— 在申请内存失败时抛出。std::bad_cast
—— 将一个指向派生类的基类指针强制转换为派生类指针时,如果类不是目标类型,则抛出。std::ios_base::failure
—— I/O 操作失败时抛出。std::out_of_range
—— 数组访问越界时抛出。std::invalid_argument
—— 提供无效参数时抛出。std::length_error
—— 尝试创建一个超出可分配内存大小的vector、string等时发生。std::logic_error
—— 人为 bug,如出现未在程序中考虑到的条件等,通常还有一些 derived class 总结不同的情况(此类异常可以在编译环境中静态检查出来)。std::runtime_error
—— 运行时错误,一般情况下是在单个文件运行时出错。(常常由文件、网络等外部原因引起)
以上这些异常类是为了解决常见的情况而设计的,它们能够支持很多常见的内部错误,如果我们想要精细控制异常,我们还可以创建自定义异常。
通过使用异常处理机制,程序员可以保证程序的正常运行,在发生异常时捕获并处理它们,从而防止程序崩溃。同时使用标准异常类,也可以避免一些常见的错误和异常。
三、 抛出异常
在C++中可以使用异常处理机制来处理程序中的异常情况。当程序出现错误或突发事件时,异常处理机制可以让程序正常运行下去,而不会导致程序崩溃。那么如何抛出异常呢,我们一起来看看
1 throw语句
使用throw语句可以抛出异常,throw语句必须跟上一个表达式该表达式是抛出的异常对象,如下所示:
throw someException; // 抛出异常
我们可以用任何类型的值做为异常对象,不过通常我们会把异常对象设置为标准库的异常类之一
2 异常类型
异常类型是某种类型的值,它可以用于标识需要通知程序时发生了什么错误。异常类型可以是任意类型,但为了能够与 catch 块中的异常参数类型匹配,通常使用异常类的对象或指针。
下面是一个简单的示例,在函数中抛出一个异常:
// 声明一个自定义的异常类
class MyException : public exception {
public:// 重写 what() 函数,返回异常信息const char* what() const noexcept override {return "MyException occurred";}
};void myFunction() {throw MyException(); // 抛出自定义异常
}
在抛出异常时可以使用任何类型的值,但是为了能够被 catch 块所匹配,一般使用异常类的对象或指针,也可以自定义异常类
3 异常传递
如果在函数中抛出了异常,那么异常会被抛到调用该函数的代码中。如果这个函数也没有捕获这个异常,那么异常就会继续传递到更高的层次,直到被捕获为止。
下面是一个示例代码,展示了异常是如何传递的:
void functionC() {cout << "Starting function C" << endl;throw MyException(); // 抛出自定义异常cout << "Ending function C" << endl;
}void functionB() {cout << "Starting function B" << endl;functionC(); // 调用functionCcout << "Ending function B" << endl;
}void functionA() {cout << "Starting function A" << endl;try {functionB(); // 调用functionB} catch (const exception& e) {cerr << e.what() << endl; // 捕获并处理异常}cout << "Ending function A" << endl;
}int main() {cout << "Starting main function" << endl;functionA(); // 调用functionAcout << "Ending main function" << endl;return 0;
}
输出结果为:
Starting main function
Starting function A
Starting function B
Starting function C
MyException occurred
Ending function A
Ending main function
首先main函数调用 functionA。functionA 内部调用 functionB,并且包含一个 try 块,用来捕获异常。functionB 内部调用 functionC并抛出了一个异常,这个异常传递到了 functionA 中被 catch 块捕获并处理。
这里需要注意的是一旦抛出了一个异常,函数就会终止。因此functionC 中的 cout 语句不会被执行到。
总结起来异常处理机制是 C++ 中重要的一部分,它可以帮助程序处理错误和突发事件,并保证程序的正常运行。在抛出异常时需要考虑使用什么类型的异常对象,并养成良好的习惯在适当的地方捕获异常。
四、 捕获异常
在C++中捕获异常是指捕获并处理由 throw 语句抛出的异常。在异常处理机制中,try 块用于捕获异常并处理它们,而 catch 块则用于处理 try 块中抛出的异常。下面我们来看看如何使用 catch 块来捕获和处理异常
1 catch语句
catch 块用于捕获和处理由 try 块抛出的异常。catch 块必须跟上一个括号,括号中是一个参数,它是 catch 块的异常参数,用来接收抛出的异常对象
如下所示:
try {// 可能会发生异常的代码
} catch (exceptionType& e) {// 处理异常的代码
}
这里的 exceptionType 是异常类型的名字,使用与 throw 语句中抛出的一致的类型或基类类型。&e 表示将异常对象的引用传递给 catch 块中的代码,从而使得 catch 块能够访问并处理该异常对象。需要注意的是,&e 表示对异常对象的只读访问不能对传递过来的异常对象进行修改。
我们可以使用多个 catch 块来处理不同类型的异常,这样可以将异常处理代码与常规代码分离,更好地管理程序错误和异常。下面我们来看看多个 catch 块的顺序和匹配规则
2 多个catch语句的顺序与匹配规则
当由 try 块抛出一个异常时,程序会按照由上到下的顺序遍历 catch 块,直到找到一个与抛出的异常匹配的 catch 块为止。这里的匹配指的是异常参数类型与抛出的异常对象类型一致,或者是该异常的基类类型。如果找不到合适的 catch 块,则程序将异常传递到更高层次的代码中。
需要注意的是如果有多个 catch 块可以匹配抛出的异常,C++ 编译器将使用第一个合适的 catch 块进行处理,而不是使用最具体的 catch 块。因此在编写多个 catch 块时,应该将最具体的 catch 块放在最前面
下面是一个示例,它展示了多个 catch 块的顺序和匹配规则:
try {// 可能会发生异常的代码
} catch (const Exception1& e) {// 处理异常1的代码
} catch (const Exception2& e) {// 处理异常2的代码
} catch (const Exception3& e) {// 处理异常3的代码
} catch (const exception& e) {// 处理其他异常的代码
}
在这个示例中当由 try 块抛出 Exception1 类型的异常时,程序会执行第一个 catch 块。当抛出 Exception2 类型的异常时,程序会执行第二个 catch 块。当抛出 Exception3 类型的异常时,程序会执行第三个 catch 块。当抛出其他异常时程序会执行最后一个 catch 块。
3 异常处理机制的使用示例
下面是一个简单的示例,它展示了异常处理机制的使用。我们自定义一个异常类 DivideByZeroException用于抛出在除法运算中除数为零的异常。在该程序中,我们使用 try 块和 catch 块来捕获和处理异常,并且为了更好地管理程序错误和异常,将业务逻辑和异常处理代码分离开来。
#include <iostream>
#include <exception>
using namespace std;// 自定义一个异常类
class DivideByZeroException : public exception {
public:// 重写 what() 函数,返回异常信息const char* what() const noexcept override {return "Attempt to divide by zero";}
};// 除法函数,在该函数中可能会抛出一个 DivideByZeroException 异常
double divide(double a, double b) {if (b == 0) {throw DivideByZeroException();}return a / b;
}int main() {double a = 42, b = 0, result;try {result = divide(a, b);cout << "Result is: " << result << endl;} catch (const DivideByZeroException& e) {cerr << "Exception caught: " << e.what() << endl;}cout << "Program continues to run" << endl;return 0;
}
在该示例中定义了一个 除法函数 divide,该函数接收两个 double 类型的参数 a 和 b,如果除数 b 为零,则抛出一个 DivideByZeroException 异常。在程序中我们在 try 块中调用 divide 函数,并通过 catch 块来捕获并处理抛出的异常。我们在 catch 块中打印出异常信息并继续执行程序。最后输出的结果应该是:
Exception caught: Attempt to divide by zero
Program continues to run
以上就是关于 catch 块的使用和异常处理机制的一个简单示例,希望可以帮助您更好地掌握 C++ 中的异常处理机制。
五、 C++11 新增异常功能
在C++11中增加了一些异常的功能,让我们来看看
1 noexcept操作符
noexcept是一个C++11新增的操作符,它用于指明一个函数是否可能抛出异常。当一个函数有可能抛出异常时,我们可以在其声明或定义前使用 noexcept 关键字告知编译器这一信息。这个操作符的作用是帮助编译器进行优化,提高代码的效率。
一个使用 noexcept 的函数可以被认为是“抛出异常不影响程序正确性”的,这意味着该函数不会抛出异常,或者抛出异常后程序可以优雅地进行终止。
下面是一个使用 noexcept 关键字的示例:
#include <iostream>
using namespace std;void func1() noexcept {cout << "func1: No exceptions here!" << endl;
}void func2() {throw runtime_error("Exception in func2");
}int main() {cout << boolalpha;cout << "func1 is noexcept: " << noexcept(func1()) << endl; // 输出 truecout << "func2 is noexcept: " << noexcept(func2()) << endl; // 输出 false
}
在这个示例中定义了两个函数 func1 和 func2,其中 func1 使用了 noexcept,并且没有抛出任何异常。而 func2 则可能会抛出一个 runtime_error 异常。在主函数中,我们使用 noexcept 来检查 func1 和 func2 是否使用了 noexcept 进行声明或定义,从而判断它们是否可能会抛出异常。
需要注意的是noexcept 操作符只能用于函数声明或定义的末尾,这个末尾必须是分号或花括号。对于类的成员函数,可以在函数名后的括号内使用它,如下所示:
class MyClass {
public:void func1() noexcept;void func2() noexcept(true) { // 或者把true换成falsethrow runtime_error("Exception in func2");}
};
在类的成员函数声明或定义中也可以使用 noexcept 进行限定,但有一个细微的差别,可以将其放在括号内来表示类作为一个新环境。括号内的布尔值指定了该函数是否可能抛出异常。
2 异常列表(function try-block)
在 C++11 中还新增了异常列表,也叫函数 try 块。这个功能允许我们在函数定义中捕获异常并处理,与在函数体中进行异常处理不同,这让我们可以将所有异常处理代码放在同一个位置,提高代码的可读性和可维护性。
在函数体开始之前,在函数参数列表后立即使用 try 关键字并紧跟着花括号,在花括号中包含函数体,需要同时声明和捕获异常。需要注意的是,如果一个函数既有函数 try 块,又有普通的 try-catch 块,它们的处理顺序是不一样的,函数 try 块中的异常处理将先于普通的 try-catch 块执行。
下面是一个函数 try 块的示例代码:
#include <iostream>
#include <stdexcept>
using namespace std;class MyClass {
public:MyClass() : num(42) {cout << "Constructing MyClass" << endl;}~MyClass() noexcept(false) {cout << "Destructing MyClass" << endl;throw runtime_error("Exception in destructor");}void DoSomething() noexcept(false) {cout << "Doing something" << endl;throw runtime_error("Exception in DoSomething");}private:int num;
};void f(MyClass& mc) try {mc.DoSomething();
} catch (const exception& e) {cerr << "Caught exception in f(): " << e.what() << endl;
}int main() {MyClass mc;f(mc);return 0;
}
在这个示例中定义了一个 MyClass 类,该类包含了一个有副作用的默认构造函数和一个有副作用的析构函数,它们都可能会抛出异常。MyClass 类还包含一个成员函数 DoSomething,这个函数也可能会抛出异常。我们使用了函数 try 块来定义了一个函数 f,该函数调用了成员函数 DoSomething,并在函数名后面使用了 try 来声明和捕获异常。在 catch 块中打印出异常信息。
在主函数中创建了一个 MyClass 对象,然后调用函数 f 来演示函数 try 块的使用。
以上就是 C++11 中新增的两个异常功能:noexcept 操作符和异常列表(function try-block)。这些新功能使我们可以更好地处理异常,写出更健壮、高效的代码。
六、常见错误和异常处理
在编写代码时,我们难免会遇到一些错误与异常。这些错误与异常可能会导致我们的程序崩溃或者出现一些意想不到的行为。因此在编写代码的过程中,我们应该注意一些常见的错误和异常,以便及时解决它们或者避免它们的发生。
1 空指针异常
指针是我们编程过程中经常使用的一个概念,空指针异常指当我们使用一个空指针时,会出现意想不到的行为或意外的程序崩溃。
下面是一个关于空指针异常的代码示例:
int* p = nullptr; // 定义一个空指针
int a = *p; // 这里会发生空指针异常
在代码示例中定义了一个空指针 p
,然后试图去访问 p
指向的内存空间中的值,并将其赋值给变量 a
,这里就会发生空指针异常。
在C++ 中我们可以通过以下方式来避免空指针异常的发生:
- 在使用指针之前要进行判断,确保指针不为空。
- 在给指针分配内存空间时,要使用 new 操作符,并进行异常处理。
2 内存泄漏异常
内存泄漏指程序在分配了内存空间后,没有合适的方式来释放它。内存泄漏会导致程序内存空间的消耗过大,从而影响程序性能。
下面是一个内存泄漏的代码示例:
int* p = new int; // 分配了一个动态内存空间
p = nullptr; // 将指针指向空
在代码示例中通过 new 操作符动态地分配了一段内存空间,但是在之后将指针置为空时,我们并没有使用 delete 来释放所分配的内存空间,从而导致了内存泄漏。
在C++ 中应该避免内存泄漏的发生。一种常见的做法是,在分配内存空间时使用智能指针(smart pointer),它们会在指针不再需要时自动释放所分配的内存空间。
3 数组越界异常
数组越界是指访问数组的时候,访问一个超出了数组范围的索引,其结果是未定义的行为。访问越界的错误有时可能看起来没有任何影响,但是在某些情况下,它们可能会对程序的运行时行为产生严重的影响。
下面是一个数组越界的代码示例:
int arr[5] = {1, 2, 3, 4, 5};
int n = 6;
int a = arr[n]; // 这里会发生数组越界
在代码示例中定义了一个长度为 5 的数组 arr
,然后试图访问数组中不存在的索引 n
,这里就会发生数组越界异常。
在C++ 中我们可以通过以下方式来避免数组越界异常的发生:
- 在访问数组元素时,要确保访问的索引在有效范围内。
- 在使用数组之前要进行初始化。
4 死锁异常
死锁是指两个或多个进程(线程)相互等待对方释放共享资源,从而导致进程(线程)阻塞的情况。死锁是多线程编程中比较常见的一个问题,一旦发生,会导致程序的挂起,从而影响程序的性能。
下面是一个死锁的代码示例:
#include <mutex>
#include <thread>void func(std::mutex& m1, std::mutex& m2) {m1.lock();m2.lock(); // 这里会导致死锁// ...m2.unlock();m1.unlock();
}int main() {std::mutex m1, m2;std::thread t1(func, std::ref(m1), std::ref(m2));std::thread t2(func, std::ref(m2), std::ref(m1));t1.join();t2.join();return 0;
}
在代码示例中定义了两个线程 t1
和 t2
,它们分别执行函数 func
。在函数中,我们使用了两个互斥量 m1
和 m2
来保证在访问共享资源前线程的同步,但是在执行线程 t1
和 t2
的时候,如果它们同时试图获取 m1
和 m2
的互斥锁,就会导致死锁异常的发生。
在 C++ 中可以通过以下方式来避免死锁异常的发生:
- 避免使用多个互斥量进行同步。
- 在使用互斥量时,谨慎使用 lock 和 unlock
- 使用 RAII 实现自动加锁和解锁,在 C++11 中,我们可以使用
std::lock_guard
和std::unique_lock
来实现在构造函数中加锁,在析构函数中解锁的操作
相关文章:

深度解析C++异常处理机制:分类、处理方式、常见错误及11新增功能
C 基础知识 八 异常处理 上篇 一、基础1. 异常的概念2. 异常的分类2.1 内置异常2.2 自定义异常 3. 异常的处理方式3.1 try-catch 语句3.2 throw 语句3.3 noexcept 修饰符3.4 finally 语句块 二、 异常处理机制1 try-catch 语句块2 异常处理流程3 标准异常类 三、 抛出异常1 thr…...

FPGA时序约束(四)主时钟、虚拟时钟和时钟特性的约束
系列文章目录 FPGA时序约束(一)基本概念入门及简单语法 FPGA时序约束(二)利用Quartus18对Altera进行时序约束 FPGA时序约束(三)时序约束基本路径的深入分析 文章目录 系列文章目录前言主时钟约束跨时钟域…...

JNI开发
文件结构(选中的为生成的) CMake构建不需要执行命令,会自动生成so文件打包进apk Android mk构建需要执行命令生成so文件,再打包进apk。命令如下。 # 在jni目录下执行 # 生成com_demo_cppproject_OtherNdkTest.h头文件 javac -h .…...

JAVA有哪些特点?
JAVA有以下特点: 综上所述,Java作为一种先进的面向对象编程语言,具有简单、可移植、健壮、高性能、多线程、动态性、跨平台、开放性和安全性等众多特点,已经成为广泛使用的编程语言之一。 简单易学:JAVA语言的语法与C语…...

使用读写锁提高并发
我们想要的是:允许多个线程同时读,但只要有一个线程在写,其他线程就必须等待。 ReadWriteLock ReadWriteLock的作用: 只允许一个线程写入(其他线程既不能写入也不能读取);没有写入时…...

使用@PropertySource加载配置文件
1.PropertySource和PropertySources注解 1.1.PropertySource注解概述 PropertySource注解是Spring 3.1开始引入的配置类注解。通过**PropertySource注解可以将properties配置文件中的key/value存储到Spring的Environment中,Environment接口提供了方法去读取配置文…...

事务及分布式事务解决方案
基础概念 1.1.事务 事务可以看做是一次大的活动,它由不同的小活动组成,这些活动要么全部成功,要么全部失败。 1.2.本地事务 在计算机系统中,更多的是通过关系型数据库来控制事务,利用数据库本身的事务特性来实现&a…...

【思科、华为、华三、锐捷网络设备巡检命令】
华三 screen-1ength disable 取消分页 displayversion 查看版本 displayclock 查看日期时钟 displayfan 查看风扇状态 displaypower 查看电源信息 displaycpu-usage 查看CPU利用率 displaymemory 查看内存利用率 display environment 查看温度信息 display device 查看设备信息…...

代码随想录算法训练营第五十二天
代码随想录算法训练营第五十二天| 300.最长递增子序列,674. 最长连续递增序列,718. 最长重复子数组 300.最长递增子序列674. 最长连续递增序列718. 最长重复子数组 300.最长递增子序列 题目链接:最长递增子序列 这里是不用处理if nums[i] &l…...

【Linux网络】传输层中UDP和TCP协议
文章目录 1、再谈端口号2、UDP协议3、TCP协议3.1 TCP协议段格式3.2 TCP的三次握手和四次挥手(连接管理机制)3.3 TCP的滑动窗口3.4 TCP的流量控制3.5 拥塞控制3.6 延迟应答和捎带应答3.7 面向字节流和粘包问题3.8 TCP总结 1、再谈端口号 端口号port标识一…...

工具︱ Web3加密浏览器Brave有什么特别之处?
使用浏览器来上网访问和获取各种信息和资源已经成为传统互联网民的普遍活动,下一代互联网协议Web3的核心特点是去中心化,即不依赖于中心化的服务器和数据中心,而是通过分布式的网络节点来实现数据存储和传输。 浏览器承载着信息网络与用户需求…...

绝对不能错过这份沃尔玛实用插件工具大全
龙哥最近发现很多跨境卖家都比较少运营沃尔玛这个平台。沃尔玛除了是世界500强之外,它的线上商城也弄得很好。它的电商平台主要是售卖自营的,然后你也可以入驻来卖自己的产品,就像是我们国内的京东一样。今天龙哥就给大家分享一些沃尔玛专用插…...

【Java】字符串模板拼接的方法
引 在Java中,构建字符串是非常常见的操作。在很多时候,我们都需要使用变量或输入来定制一个文本输出,例如打印日志、生成HTML代码或构建错误消息。而当需要进行字符串连接时,字符串模板是一种常用的方法。在本篇博客中࿰…...

Vue3项目中使用ECharts图表并实现自适应效果
文章目录 一、Vue3项目安装ECharts二、引入、使用ECharts1.创建图表组件,并在父组件中引入使用2.引入ECharts3.ECharts图表自适应 总结 一、Vue3项目安装ECharts 在项目中输入如下代码: npm install echarts --save安装完成可以在package.json中看到&a…...

快速跑通环信IM Android Demo
1、以Android 4.0.0 Demo为例 https://www.easemob.com/download/demo (下载别的版本的demo 可以修改版本号直接下载就就可以) https://downloadsdk.easemob.com/downloads/easemob-sdk-4.0.0.zip 运行时遇到以下报错在项目build.gradle中添加运行时遇…...

leetcode解题思路分析(一百三十九)1190 - 1196 题
反转每对括号间的子串 给出一个字符串 s(仅含有小写英文字母和括号)。请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。注意,您的结果中 不应 包含任何括号。 可以简单的用栈保存当前层…...

PHP+vue基于web的小区物业管理管理系统1995a
小区物业管理系统主要是对小区物业以及居民信息进行管理,方便用户使用该资源的一种有效手段。能有效地对物业以及用户信息进行管理并为广大用户服务是该管理系统的基本要求,同时用户也可以及时了解最新的物业信息,方便地查询相关物业情况。基…...

区间预测 | MATLAB实现QRCNN卷积神经网络分位数回归时间序列区间预测
区间预测 | MATLAB实现QRCNN卷积神经网络分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRCNN卷积神经网络分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 区间预测 | MATLAB实现QRCNN卷积神经网络分位数回归时间序列区间预测…...

【AI 导航网站】为了更好的收集 AI 资源,我开发了一个 AI 导航网站
AI 导航网站 目前 AI 应用正呈迸发式增长,然而一个人获取资源的途径有限,对于目前存在的AI工具不能很好的收集总结,所以基于此,我开发了这个一个AI导航网站,希望通过它,收集出目前存在的热门的AI应用&…...

谈谈HMI 的自动化生成技术
人机界面(HMI)是自动化领域不可或缺重要组成部分。尽管人机界面系统的设计看上去并没有太大的技术门槛,但是设计一个HMI系统的工作量是巨大的。如果你没有足够的耐心便完成不了一个通用的HMI系统。构建UI控件库是一个似乎永远完不成的事情&am…...

docker安装elasticsearch
使用docker部署 部署elasticsearch # 拉取镜像 docker pull elasticsearch# 创建容器 docker run --name es -p 9200:9200 \-p 9300:9300 \-e "discovery.typesingle-node" \-e ES_JAVA_OPTS"-Xms64m -Xmx128m" \-v /home/es/conf/elasticsearch.yml:/…...

Docker:使用dockerFile创建镜像(war包和jar包)
1、使用war包打镜像 (1)在war的当前路径下,新建一个文件——Dockerfile (2)编辑Dockerfile文件 vim Dockerfile Dockerfile文件内容: FROM java:8 # 选择项目中要求的版本 MAINTAINER ylb …...

2.基础篇
目录 一、描述软件测试的生命周期(软件测试的流程) 二、如何描述一个bug 三、bug的级别(粗略划分) 四、bug的生命周期 五、因为一个bug和开发人员产生争执怎么办 六、如何设置弱网? 一、描述软件测试的生命周期&a…...

取代你的可能不是AI,而是比你更会使用AI的人
1、背景 从开始了解AI到现在已经1个月了,最明显的就是,产品层出不穷,以前只有技术人员才关系AI,现在各行各业都在关系AI,都希望通过它提高生产力和创造力; 在当今大数据和人工智能时代,职场和企…...

NECCS|全国大学生英语竞赛C类|词汇和语法|语法题|时态 非谓语动词 |19:00~20:15|完形填空·词性转化
14:35~14:45 15:45~16:2019:00~20:15 http://t.csdn.cn/XbsUy 目录 (一)时态 7. 将来进行时 8. 过去将来进行时 9. 现在完成时 10. 过去完成时编辑 11. 将来完成时 12. 现在完成时 13. 过去完成进行时 (…...

【高等数学笔记】Stolz定理
文章目录 Stolz定理 ∗ ∞ \cfrac{*}{\infty} ∞∗型 0 0 \cfrac{0}{0} 00型 例子1. 算术平均数的极限2. Stolz定理可以被理解为“数列的洛必达法则”,它揭示了两个数列之比的极限和相邻两项之差的比的极限的关系。 Stolz定理 ∗ ∞ \cfrac{*}{\infty} ∞∗型…...

【24】核心易中期刊推荐——图像处理研究大数据及智能处理研究
🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…...

Codeforces Round 870 (Div. 2)【A、B、C、D】
文章目录 A. Trust Nobody(暴力)B. Lunatic Never Content(数学)C. Dreaming of Freedom(数学、暴力)D. Running Miles(前缀、后缀) 传送门 A. Trust Nobody(暴力) 题意:给出n个人的陈述,每个人陈述至少有ai个人说谎,让你求出可能是说谎人数…...

BetaFlight统一硬件AOCODARC H7DUAL配置文件讨论
BetaFlight统一硬件AOCODARC H7DUAL配置文件讨论 1. 源由2. Review配置3. 分析整理3.1 生产商信息3.2 磁力计3.3 气压计3.4 陀螺仪3.5 串口RxTx3.6 板载Flash3.7 模拟OSD MAX74563.8 PPM接收机3.9 伺服器3.10 LED灯带3.11 蜂鸣器3.12 电机 X83.13 ADC(电压/电流/RSSI信号强度/空…...

力扣题库刷题笔记682-棒球比赛
1、题目如下: 2、个人Python代码实现如下: 代码如下: class Solution: def calPoints(self, operations: List[str]) -> int: i 0 #用于遍历元素的下标 while i < len(operations): …...