突破编程_C++_C++11新特性(lambda表达式的实战应用)

1 Lambda 表达式的调用与操作

1.1 Lambda 表达式作为函数参数传递

Lambda 表达式可以像普通函数或函数对象一样被传递作为函数的参数。这种灵活性使得 Lambda 表达式在 C++ 的算法库和函数式编程风格中特别有用。当需要将一个小的、匿名的函数作为参数传递给另一个函数时,Lambda 表达式是一个很好的选择。

当 Lambda 表达式作为参数传递时,它会被视为一个函数对象,其类型是一个独特的匿名类,该类重载了调用运算符 operator()。

下面是一个详细的例子,展示了如何将 Lambda 表达式作为参数传递给一个函数:

#include <iostream>  
#include <vector>  
#include <algorithm>  // 一个接受函数对象作为参数的函数模板  
template <typename Func>  
void apply_to_elements(std::vector<int>& v, Func func) {  for (auto& elem : v) {  elem = func(elem);  }  
}  int main() 
{  std::vector<int> v = {1, 2, 3, 4, 5};  // 创建一个 Lambda 表达式,它将元素乘以 2  auto multiply_by_two = [](int x) { return x * 2; };  // 将 Lambda 表达式作为参数传递给 apply_to_elements 函数  apply_to_elements(v, multiply_by_two);  // 输出结果  for (int x : v) {  std::cout << x << ' ';  }  return 0;  
}

上面的代码输出为:

2 4 6 8 10

这个例子定义了一个模板函数 apply_to_elements,它接受一个 std::vector<int> 和一个函数对象 func 作为参数。函数对象 func 被应用于向量的每一个元素。然后,创建了一个 Lambda 表达式 multiply_by_two,它接受一个整数参数并返回该整数的两倍。最后将这个 Lambda 表达式作为参数传递给 apply_to_elements 函数,以便将向量 v 中的每个元素乘以 2。

Lambda 表达式作为参数传递时,其类型会被自动推导,这样就不需要显式地指定其类型。编译器会根据 Lambda 表达式的捕获子句、参数列表和返回类型来生成一个唯一的匿名类类型。

Lambda 表达式还可以捕获其所在作用域中的变量,这使得它们能够在被传递的函数中使用这些变量。例如:

int threshold = 3;  
auto is_above_threshold = [threshold](int x) { return x > threshold; };  std::vector<int> filtered_v;  
std::copy_if(v.begin(), v.end(), std::back_inserter(filtered_v), is_above_threshold);

在这个例子中,Lambda 表达式 is_above_threshold 捕获了外部变量 threshold 的值,并用于比较函数。然后,std::copy_if 算法使用这个 Lambda 表达式来决定哪些元素应该被复制到 filtered_v 向量中。

1.2 Lambda 表达式作为函数返回值

在 C++11 中,Lambda 表达式不仅可以作为函数参数传递,还可以作为函数的返回值。这种能力使得 Lambda 表达式在构建高阶函数和实现更复杂的算法时非常有用。高阶函数是指那些接受或返回其他函数的函数。

当 Lambda 表达式作为函数的返回值时,它会被视为一个函数对象,即一个可以像函数一样被调用的对象。Lambda 表达式的类型是一个独特的匿名类,这个类重载了调用运算符 operator(),使得我们可以像调用普通函数一样调用 Lambda 表达式。

下面是一个详细的例子,展示了如何将 Lambda 表达式作为函数的返回值:

#include <iostream>  
#include <vector>  
#include <algorithm>  // 一个返回函数对象的函数  
auto create_multiplier(int factor) {  return [factor](int x) { return x * factor; };  
}  int main() {  // 创建一个将元素乘以 2 的函数对象  auto multiply_by_two = create_multiplier(2);  // 使用返回的 Lambda 表达式(函数对象)  std::vector<int> v = {1, 2, 3, 4, 5};  for (auto& elem : v) {  elem = multiply_by_two(elem);  }  // 输出结果  for (int x : v) {  std::cout << x << ' ';  }  // 创建一个将元素乘以 3 的函数对象  auto multiply_by_three = create_multiplier(3);  // 重置向量 v  v = {1, 2, 3, 4, 5};  // 使用新的 Lambda 表达式(函数对象)  for (auto& elem : v) {  elem = multiply_by_three(elem);  }  // 输出结果  std::cout << std::endl;  for (int x : v) {  std::cout << x << ' ';  }  return 0;  
}

上面的代码输出为:

2 4 6 8 10
3 6 9 12 15

在这个例子中,create_multiplier 函数接受一个整数 factor 作为参数,并返回一个 Lambda 表达式,该表达式接受另一个整数 x 并返回 x 与 factor 的乘积。这个 Lambda 表达式作为 create_multiplier 函数的返回值,实际上返回了一个函数对象。

然后,在 main 函数中调用 create_multiplier 来创建两个函数对象:multiply_by_two 和 multiply_by_three。这两个函数对象分别用于将向量 v 中的元素乘以 2 和 3。

值得注意的是,由于 Lambda 表达式的类型是唯一的匿名类,所以不能直接指定其类型作为返回类型。因此,在 create_multiplier 函数的声明中,使用了 auto 关键字来让编译器自动推导返回类型。编译器会根据 Lambda 表达式的捕获子句、参数列表和返回类型来生成一个唯一的匿名类类型,并将其作为 create_multiplier 函数的返回类型。

1.3 Lambda 表达式在 STL 算法中的应用

Lambda 表达式在 C++ STL(标准模板库)算法中的应用非常广泛,它们提供了一种简洁、直观的方式来定义临时的函数行为,使得程序员能够更灵活、更直观地编写代码。Lambda 表达式在 STL 算法中常用于定义排序准则、执行特定操作等。

首先,我们需要理解 Lambda 表达式的基本结构。一个 Lambda 表达式通常包括捕获子句、参数列表、返回类型(可选)和函数体。捕获子句决定了哪些变量可以从包含 Lambda 的作用域中捕获;参数列表则定义了Lambda 函数的参数;函数体则是 Lambda 函数执行的具体操作。

在 STL 算法中,Lambda 表达式常常作为谓词(predicate)或函数对象(functor)使用。谓词是一个返回 bool 值的函数或函数对象,用于在算法中定义条件或比较操作。例如,在 std::find_if 算法中,可以使用 Lambda 表达式作为搜索条件来查找容器中满足特定条件的元素。

下面是一个使用Lambda表达式在std::find_if算法中查找向量中大于3的元素的例子:

#include <iostream>  
#include <vector>  
#include <algorithm>  int main() 
{  std::vector<int> vec = {3, 1, 4, 1, 5, 9};  auto it = std::find_if(vec.begin(), vec.end(), [](int x) { return x > 3; });  if (it != vec.end()) {  std::cout << "Found an element greater than 3: " << *it << std::endl;  } else {  std::cout << "No element greater than 3 found." << std::endl;  }  return 0;  
}

上面的代码输出为:

Found an element greater than 3: 4

在这个例子中,Lambda 表达式 [](int x) { return x > 3; }定义了一个匿名函数,它接受一个整数参数 x 并返回一个布尔值,表示 x 是否大于 3。这个 Lambda 表达式被传递给 std::find_if 算法作为搜索条件。算法遍历向量 vec 中的元素,直到找到第一个满足 Lambda 表达式条件的元素为止。

除了 std::find_if,Lambda 表达式还可以用于其他 STL 算法,如 std::remove_if、std::count_if 等。这些算法接受谓词作为参数,用于定义元素的移除条件或计数条件。通过 Lambda 表达式,可以轻松地为这些算法提供自定义的条件函数。

此外,Lambda 表达式还可以用于定义 STL 排序算法(如std::sort)中的比较函数。例如,可以使用 Lambda 表达式来定义自定义的排序准则,以便按照特定的顺序对容器中的元素进行排序。

2 Lambda 表达式的闭包特性

2.1 闭包的概念与实现

在 C++ 中,闭包(Closure)是一个可以记住并访问其词法作用域(lexical scope)的变量(即使在其函数体之外)的函数对象或 Lambda 表达式。闭包通常用于封装与某个特定上下文相关的代码块,并且可以作为一个值传递和存储。

Lambda 表达式一种实现闭包的方式。Lambda 表达式可以捕获其所在作用域中的变量,并在其函数体中使用这些变量。这使得 Lambda 表达式能够在不同的上下文中保持对外部变量的引用,从而形成一个闭包。

下面是一个简单的 Lambda 表达式闭包的例子:

#include <iostream>  
#include <vector>  
#include <algorithm>  int main() 
{  int x = 10;  // 创建一个Lambda表达式闭包,捕获外部变量x  auto print_x_times = [x](int n) {  for (int i = 0; i < n; ++i) {  std::cout << x << ' ';  }  std::cout << std::endl;  };  // 使用闭包  print_x_times(5); // 输出:10 10 10 10 10  return 0;  
}

在这个例子中,Lambda 表达式 [x](int n) {…}捕获了外部变量 x,并在其函数体中使用了这个变量。由于 Lambda 表达式捕获了 x,它形成了一个闭包,可以在其定义的作用域之外被调用,并且仍然能够访问 x 的值。

2.2 Lambda 表达式的生命周期与闭包的关系

Lambda 表达式的生命周期与闭包的关系是 C++ 中一个非常核心且有趣的概念。这两者紧密相连,对于理解 Lambda 表达式在 C++ 中的行为和用法至关重要。

首先,再回顾一下 Lambda 表达式和闭包的基本概念。Lambda 表达式允许定义一个匿名函数对象,即 Lambda 函数。而闭包则是一个可以记住并访问其词法作用域(lexical scope)的变量的函数对象或 Lambda 表达式。简而言之,闭包是 Lambda 表达式的一个核心特性,它使得 Lambda 表达式能够捕获并保留其定义时的环境信息。

接下来,再探讨一下 Lambda 表达式的生命周期。Lambda 表达式在创建时会被分配内存,并存储相关的捕获变量和函数体等信息。这个 Lambda 表达式对象可以在其创建的作用域内被传递和使用,就像任何其他对象一样。当 Lambda 表达式对象不再被引用时,其生命周期结束,相关的内存会被释放。

然而,Lambda 表达式的生命周期并不仅仅与其自身相关,还与其捕获的变量有着密切的关系。这正是闭包发挥作用的地方。当 Lambda 表达式按值捕获外部变量时,它会创建这些变量的副本,并在其生命周期内持有这些副本。这意味着即使外部变量在 Lambda 表达式被创建之后发生了变化,Lambda 表达式内部使用的仍然是捕获时的值。另一方面,如果 Lambda 表达式按引用捕获外部变量,则它会持有对这些变量的引用,而不是副本。这意味着 Lambda 表达式内部可以直接访问和修改这些外部变量的值,但这些变量的生命周期必须至少与 Lambda 表达式一样长,否则会出现悬挂引用的问题。

因此,Lambda 表达式的生命周期与闭包的关系主要体现在以下几个方面:

  • Lambda 表达式的生命周期决定了其内部捕获的变量的有效期。只有当 Lambda 表达式对象存在时,其捕获的变量才是有效的。
  • 闭包使得 Lambda 表达式能够记住其定义时的环境信息,包括捕获的变量。这使得Lambda表达式能够在不同的上下文中保持对外部变量的引用或值。
  • Lambda 表达式的捕获方式(按值或按引用)会影响其内部对捕获变量的访问方式和变量的生命周期要求。按值捕获会创建变量副本,而按引用捕获会持有变量引用,要求外部变量至少与 Lambda 表达式一样长命。

综上所述,Lambda 表达式的生命周期与闭包紧密相关。闭包使得 Lambda 表达式能够捕获并保留其定义时的环境信息,而 Lambda 表达式的生命周期则决定了其内部捕获的变量的有效期和访问方式。在使用 Lambda 表达式时,我们需要仔细考虑其捕获方式和外部变量的生命周期,以避免潜在的问题和错误。

2.3 Lambda 表达式在并发编程中的应用

Lambda 表达式与并发编程结合使用,能够大大简化多线程编程的复杂性。C++11 引入了 <thread> 和 <future> 等头文件,为并发编程提供了原生的支持,而 Lambda 表达式则提供了简洁的函数对象定义方式,两者结合使得编写并发代码更加直观和方便。

(1)Lambda 表达式与 std::thread

std::thread 是 C++11 引入的一个类,用于表示和管理线程。可以使用 Lambda 表达式作为 std::thread 的构造参数,从而在新线程中执行 Lambda 表达式定义的任务。

示例:

#include <iostream>  
#include <thread>  
#include <chrono>  int main() {  // 使用 Lambda 表达式创建线程  std::thread t([&]() {  std::this_thread::sleep_for(std::chrono::seconds(1));  std::cout << "Hello from thread!\n";  });  // 等待线程完成  t.join();  std::cout << "Main thread continues...\n";  return 0;  
}

上面的代码输出为:

Hello from thread!
Main thread continues...

这个例子创建了一个新线程 t,并传递了一个 Lambda 表达式作为参数。Lambda 表达式捕获了外部作用域的所有变量(通过 [&]),并在新线程中休眠一秒后输出一条消息。主线程通过调用 t.join() 等待新线程完成。

(2)Lambda 表达式与 std::async

std::async 是 C++11 中另一个用于并发编程的工具,它返回一个 std::future 对象,该对象表示一个异步操作的结果。你可以使用 Lambda 表达式作为 std::async 的参数,从而异步执行某个任务。

示例:

#include <iostream>  
#include <future>  
#include <chrono>  int main() 
{  // 使用 Lambda 表达式异步执行任务  std::future<void> fut = std::async(std::launch::async, [&]() {  std::this_thread::sleep_for(std::chrono::seconds(1));  std::cout << "Task completed asynchronously!\n";  });  // 主线程可以继续执行其他任务...  std::cout << "Main thread doing other work...\n";  std::this_thread::sleep_for(std::chrono::seconds(2));  // 获取异步操作的结果(如果有的话)  fut.get(); // 这会阻塞,直到异步操作完成  std::cout << "Main thread continues after asynchronous task...\n";  return 0;  
}

上面的代码输出为:

Main thread doing other work...
Task completed asynchronously!
Main thread continues after asynchronous task...

这个例子使用 std::async 异步执行一个 Lambda 表达式。Lambda 表达式同样休眠一秒后输出一条消息。主线程继续执行其他任务,并通过调用 fut.get() 等待异步任务完成。注意,std::async 的第一个参数 std::launch::async 表示希望异步执行任务,而不是简单地在当前线程中同步执行。

(3)注意事项

  • 在使用 Lambda 表达式进行并发编程时,需要特别注意数据竞争和线程安全的问题。确保共享数据被正确同步,避免竞态条件。
  • 当 Lambda 表达式捕获外部变量时,要仔细考虑捕获方式(值捕获 = 或引用捕获 &)。值捕获会复制变量的值,而引用捕获则会在 Lambda 表达式中直接使用变量的引用。在并发上下文中,引用捕获可能导致悬挂引用或数据竞争,除非你能确保引用的对象在 Lambda 执行期间一直有效。
  • 使用 std::thread 和 std::async 时,要确保正确管理线程的生命周期,避免线程泄露或过早销毁线程对象。

3 Lambda 表达式在模板编程中的应用

在 C++11 中,Lambda 表达式本身并不是模板类型参数的一部分,因为 Lambda 表达式在编译时生成一个唯一的匿名类类型。然而,我们可以将 Lambda 表达式作为模板函数的参数,这个模板函数可以接受任意可调用的对象,包括 Lambda 表达式。

通过使用 std::function,我们可以将 Lambda 表达式作为模板函数的参数,因为 std::function 可以存储、复制和调用任何可调用的目标,包括函数、函数对象以及 Lambda 表达式。这样,Lambda 表达式就可以在模板函数的上下文中使用了。

下面是一个示例,展示了如何在模板函数中使用 std::function 来接受 Lambda 表达式作为参数:

#include <iostream>  
#include <vector>  
#include <functional> // for std::function  // 一个模板函数,接受一个容器和一个 std::function 对象作为参数  
template <typename Container, typename Func>
void processContainer(Container& c, Func func) {for (const auto& item : c) {func(item); // 调用传入的函数对象  }
}int main() {std::vector<int> numbers = { 1, 2, 3, 4, 5 };// 创建一个 Lambda 表达式,并传递给模板函数  processContainer(numbers, [](int n) {std::cout << n * 2 << ' '; // 输出每个元素的两倍  });std::cout << std::endl;return 0;
}

上面的代码输出为:

2 4 6 8 10

在这个例子中,processContainer 是一个模板函数,它接受一个容器和一个 std::function 对象作为参数。std::function 对象在这里被用作一个可调用对象的包装器,它可以是函数、函数对象或者 Lambda 表达式。在 main 函数中,我们创建了一个 Lambda 表达式,并将其作为第二个参数传递给 processContainer。Lambda 表达式在模板函数中被调用,并输出容器中每个元素的两倍。

虽然 Lambda 表达式本身不是模板类型参数,但是通过使用 std::function,可以在模板函数中接受 Lambda 表达式作为参数,并在运行时调用它们。这支持编写更加通用和灵活的代码,因为 Lambda 表达式提供了定义匿名函数对象的简洁方式。

值得注意的是,使用 std::function 可能会引入一些运行时开销,因为它是一个类型擦除的包装器,这意味着它在内部可能使用了虚函数或其他机制来实现多态性。在性能敏感的代码中,可能需要考虑使用其他方法,比如模板特化和显式函数对象,来避免这种开销。然而,在大多数应用中,std::function 提供的灵活性和易用性通常是可以接受的。

4 Lambda 表达式中的异常处理

Lambda 表达式本质上是一个匿名函数对象,因此它也可以像普通函数一样抛出异常。当 Lambda 表达式内部执行时,如果发生了任何异常,该异常将按照正常的异常处理机制传播到调用者。

Lambda 表达式中的异常处理主要涉及到两个方面:

Lambda 表达式内部抛出异常:如果 Lambda 表达式的主体中有代码抛出了异常,并且该异常没有被 Lambda 表达式内部的任何 catch 块捕获,那么该异常会传播到调用 Lambda 表达式的上下文。

调用 Lambda 表达式的上下文处理异常:调用 Lambda 表达式的代码应该准备好处理由 Lambda 表达式抛出的任何异常。这通常意味着使用 try/catch 块来捕获并处理这些异常。

下面是一个简单的示例,展示了 Lambda 表达式中的异常处理:

#include <iostream>  
#include <vector>  
#include <algorithm>  int main() 
{  std::vector<int> numbers = {1, 2, 3, 4, 5};  // 使用 Lambda 表达式作为算法参数  try {  std::for_each(numbers.begin(), numbers.end(), [](int n) {  if (n % 2 == 0) {  // 假设这是一个可能会失败的操作  throw std::runtime_error("Even number encountered");  }  std::cout << n << ' ';  });  } catch (const std::runtime_error& e) {  // 捕获并处理异常  std::cerr << "Caught an exception: " << e.what() << std::endl;  }  return 0;  
}

上面的代码输出为:

1 Caught an exception: Even number encountered

这个例子定义了一个 Lambda 表达式,它遍历 numbers 向量中的每个元素。如果元素是偶数,Lambda 表达式会抛出一个 std::runtime_error 异常。我们在调用 std::for_each 算法时使用了 try/catch 块来捕获这个异常。

当执行到偶数时(在这个例子中是 2 和 4),Lambda 表达式会抛出异常,该异常被外部的 catch 块捕获,并打印出错误消息。

需要注意以下几点:

  • Lambda 表达式内部抛出的异常类型可以是任何可以从 Lambda 表达式中抛出的类型。
  • 异常处理的责任在于调用 Lambda 表达式的代码。Lambda 表达式本身不会处理其抛出的异常。
  • 如果 Lambda 表达式被用作一个异步操作(比如通过线程或异步任务队列),那么异常处理将变得更加复杂,因为异常不会直接传播到调用线程。在这种情况下,可能需要使用特殊的机制(如异常指针或错误码)来传递和处理异常。

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

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

相关文章

时间对比投资:衡量5天与10天六西格玛绿带培训的价值

六西格玛绿带培训专为希望提高其业务流程改进技能的专业人员设计。绿带培训通常涵盖六西格玛的基础知识、DMAIC(定义、测量、分析、改进、控制)方法论、以及各种质量管理工具和技巧。绿带受训者通常在他们的工作职责中负责领导小型项目或作为黑带项目团队的成员&#xff0c;下面…

小兴教你做平衡小车-蓝牙模块JDY-31介绍

文章目录 1 前言2 模块资料下载3 模块介绍3.1 模块特点3.2 模块相关指令介绍3.3 指令学习3.3.1 查看版本号3.3.2 软复位3.3.3 查看模块的波特率3.3.4 修改模块的波特率3.3.5 蓝牙配对密码查看3.3.6 修改蓝牙配对密码3.3.7 广播名查询3.3.8 广播名修改3.3.7 恢复出厂配置3.3.8 串…

游戏学(Ludology)探秘

游戏学&#xff08;Ludology&#xff09;探秘 李升伟 李昱均 常秀琼 1. 游戏学&#xff1a;概念 Ludology&#xff08;游戏学&#xff09;是研究游戏设计、游戏行为和游戏文化的一个领域。它涉及对游戏结构、规则、玩法、设计原则和游戏体验的研究&#xff0c;旨在深入理解…

人工智能的春天:改变已然发生

以下文章来源&#xff1a;青岛日报 某种意义上说&#xff0c;这个春天属于人工智能&#xff08;AI&#xff09;。 继一年多前ChatGPT惊艳全球后&#xff0c;OpenAI再次放出“王炸”成果——视频大模型Sora&#xff1b;苹果放弃布局多年的造车计划&#xff0c;将ALL in AI&#…

MySQL数据库的事务

目录 1、事务的概念 2、事务的ACID特点 2.1 原子性 2.2 一致性 2.3 隔离性 2.3.1MySQL事务隔离级别 2.3.2事务隔离级别的作用范围 2.3.3 查询事务的隔离级别 2.3.4 设置事务的隔离级别 ​编辑 2.4 持久性 3、事务控制语句 3.1测试begin和commit&#xff08;开始…

【Semidrive X9HP】硬件投屏设置仪表图层层级

一、问题描述 仪表屏的弹窗会被中控的投屏内容覆盖&#xff0c;导致在投屏的时候看不到仪表的弹窗内容&#xff0c;不符合实际使用需求&#xff0c;需要弹窗显示在投屏内容的上层。 二、问题分析与解决 1. 打入硬件投屏补丁&#xff08;补丁如附件&#xff09;&#xff0c;仪…

SOC子模块---RTC and watchdog

RTC RTC大致执行过程&#xff1a; 对SOC 中的锁相环或者外部晶振的时钟进行计数&#xff1b;产生时&#xff0c;分&#xff0c;秒的中断&#xff1b;送给中断控制器&#xff1b;中断控制器进行优先权选择后送给cpu&#xff1b;Cpu执行中断服务程序&#xff1b;在中断服务程序…

随机生成用户名、密码、注册时间【Excel】

1.1简介 最近想虚拟一些数据&#xff0c;看下有没有自动生成的工具。百度看了下&#xff0c;大概有这么几种方法 1.excel内置公式函数处理 2.使用使用VBA宏生成随机 3.下载方方格子&#xff0c;emm工具是个好工具&#xff0c;蛮多功能的&#xff0c;每月8块 4.Java函数实现…

python程序打包

目录 1. 命令2. 安装2.1 PyInstaller2.2 cx_Freeze(笔者未用过) 3. 打包示例3.1 在 pycharm 中执行3.2 若使用打包命令时报错3.3 路径问题 python打包成可执行文件&#xff0c;用于在没有Python环境的地方运行该程序&#xff0c;与qt打包类似。&#xff08;笔者写的qt打包地址&…

鸿蒙实战开发:【7日天气预报】

先来看一下效果 本项目界面搭建基于ArkUI中TS扩展的声明式开发范式&#xff0c; 数据接口是[和风&#xff08;天气预报&#xff09;]&#xff0c; 使用ArkUI自带的网络请求调用接口。 我想要实现的一个功能是&#xff0c;查询当前城市的实时天气&#xff0c; 目前已实现的功…

聚类算法之高斯混合模型聚类 (Gaussian Mixture Model, GMM)

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 高斯混合模型&#xff08;GMM&#xff09;是统计模型中的一颗璀璨之星&#xff0c;它为数据提供了一种复杂而又强大的表示方法。在机器学习的许多…

9. Linux 信号详解

Hi, 大家好! 本篇开始讲解Linux中信号的基本知识。 一、信号基本概念 信号是事件发生时对进程的通知机制,也可以把它称为软件中断。信号与硬件中断的相似之处在于能够打断程序当前执行的正常流程, 其实是在软件层次上对中断机制的一种模拟。 信号编号: 每个信号都有一个唯一…

美易官方:“巴菲特指标”创两年新高,拉响股市泡沫警报

近年来&#xff0c;随着全球经济的不断发展和资本市场的日益成熟&#xff0c;股市成为了越来越多人关注和投资的领域。然而&#xff0c;股市波动的不确定性也让许多投资者倍感焦虑。最近&#xff0c;“巴菲特指标”创两年新高&#xff0c;引发了市场对于股市泡沫的担忧。 “巴菲…

高性能计算——指令表

指令表 文章目录 指令表吞吐量计算示例一般情况在数字电子学中,执行阶段的交错是一个通用概念,不仅应用于主CPU流水线,还应用于独立指令和内存的层面。大多数执行单元都有自己的小流水线,可以在前一个指令之后一到两个周期内接收另一个指令。 在这种情况下,使用两种不同的…

并查集|1971. 寻找图中是否存在路径、684.冗余连接、685.冗余连接II

目录 并查集基础 1971. 寻找图中是否存在路径 684.冗余连接 685.冗余连接II 并查集基础 并查集主要有三个功能。 寻找根节点&#xff0c;函数&#xff1a;find(int u)&#xff0c;也就是判断这个节点的祖先节点是哪个将两个节点接入到同一个集合&#xff0c;函数&#xf…

【深度学习】一文搞懂 如何计算图像数据集的RGB均值和方差(超详细的哦~)

计算图像数据集的RGB均值和方差 1、引言2、RGB均值和方差2.1 计算RGB均值和方差原因2.2 计算RGB均值和方差步骤2.3 代码实现2.3.1 TensorFlow计算RGB均值和方差2.3.2 PyTorch计算RGB均值和方差 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c;帮个忙呀 小鱼&#xff1a;在…

了解Spring:Java开发的利器

Spring是一款开源的轻量级Java开发框架&#xff0c;旨在提高开发人员的效率和系统的可维护性。本文将介绍Spring的基本概念、使用优势、设计模式以及与Spring MVC和Spring Boot的关联。 什么是Spring&#xff1f; Spring是一款开源的轻量级Java开发框架&#xff0c;它由多个模…

Flink中流式的各种聚合

11.1 MiniBatch 聚合 针对无界聚合算子&#xff0c;说简单点就是把一组输入的数据放到缓存里&#xff0c;减少吞吐的开销 默认情况下&#xff0c;对于无界聚合算子来说&#xff0c;mini-batch 优化是被禁用的。开启这项优化&#xff0c;需要设置选项 TableConfig configurat…

STM32之HAL开发——HAL库框架介绍

HAL库外设设计思想 HAL库借鉴面向对象的设计思想&#xff0c;将外设驱动封装为对象。 HAL库使用主线 HAL使用的主要用在俩个地方&#xff0c;无外乎外设初始化以及外设的使用。想用好这两个功能&#xff0c;我们首先得对外设的封装有一定的了解。 句柄结构体 xx_HandleTypeDef…

【吾爱破解】Android初级题(二)的解题思路 _

拿到apk&#xff0c;我们模拟器打开看一下 好好&#xff0c;抽卡模拟器是吧&#x1f600; jadx反编译看一下源码 找到生成flag的地方&#xff0c;大概逻辑就是 java signatureArr getPackageManager().getPackageInfo(getPackageName(), 64).signaturesfor (int i 0; i &l…