网站管理系统排行榜住房和城乡建设部网站评估

diannao/2026/1/20 10:06:40/文章来源:
网站管理系统排行榜,住房和城乡建设部网站评估,做网站必须托管服务器吗,医疗网站建设网站目录 C11的由来 命名趣事 统一的列表初始化 统一的列表初始化的一些关键点和特性#xff1a; 简单测试代码示例#xff1a; 示例 1#xff1a;初始化内置类型和数组 示例 2#xff1a;初始化类和结构体 示例 3#xff1a;初始化标准库容器 声明 auto关键字 auto…目录 C11的由来 命名趣事 统一的列表初始化 统一的列表初始化的一些关键点和特性 简单测试代码示例 示例 1初始化内置类型和数组 示例 2初始化类和结构体 示例 3初始化标准库容器 声明 auto关键字 auto 关键字的特点 注意事项 测试代码示例 示例 1基本类型推导 示例 2复杂类型推导如 STL 容器 示例 3与引用和指针的结合使用 decltype关键字 decltype 的基本用法 decltype 的特点 注意事项 测试代码示例 示例 1获取变量的类型 示例 2获取表达式的类型 示例 3处理引用和指针 nullptr nullptr 的特点 测试代码示例 范围for 范围for循环的基本语法 关键点 示例代码 示例 1遍历数组 示例 2遍历向量vector 示例 3遍历其他STL容器 注意事项 修改容器元素的示例 智能指针 1. std::unique_ptr 2. std::shared_ptr 3. std::weak_ptr 测试代码示例 示例 1使用 std::unique_ptr 示例 2使用 std::shared_ptr 示例 3使用 std::weak_ptr 解决循环引用问题 注意事项 总结 STL中一些变化 1. 容器初始化 2. 无序容器 3. range-based for loop 4. auto 类型推导 5. 新的算法 6. lambda 表达式 7. 右值引用和移动语义 右值引用和移动语义 右值引用 移动语义 移动构造函数 移动赋值运算符 std::move 示例代码 可变参数模板 可变参数模板的基本结构 递归分解模板参数包 完美转发 简单的测试代码 lambda表达式 示例 1无捕获和无参数的 lambda 示例 2捕获外部变量的 lambda 示例 3按引用捕获外部变量的 lambda 示例 4带有返回类型的 lambda 包装器 function包装器 std::function 的特点 使用 std::function 的简单测试代码 bind函数适配器 std::bind 的特点 使用 std::bind 的简单测试代码 线程库 C11 线程库的主要特性 线程创建 简单的测试代码 注意事项 线程同步 1. std::mutex互斥锁 2. std::condition_variable条件变量 3. std::atomic原子操作 注意事项 线程安全的数据结构 std::lock_guard std::unique_lock 简单的测试代码 注意事项 C11的由来 在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。不过由于C03(TC1)主要是对C98标准中的漏洞进行修复语言的核心部分则没有改动因此人们习惯性的把两个标准合并称为C98/03标准。从C0x到C11C标准10年磨一剑第二个真正意义上的标准珊珊来迟。相比于C98/03C11则带来了数量可观的变化其中包含了约140个新特性以及对C03标准中约600个缺陷的修正这使得C11更像是从C98/03中孕育出的一种新语言。相比较而言C11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全不仅功能更强大而且能提升程序员的开发效率公司实际项目开发中也用得比较多所以我们要作为一个重点去学习。C11增加的语法特性非常篇幅非常多我们这里没办法一 一讲解所以本节主要讲解实际中比较实用的语法 C11的全部参考文档 C11详细内容 命名趣事 1998年是C标准委员会成立的第一年本来计划以后每5年视实际需要更新一次标准C国际 标准委员会在研究C 03的下一个版本的时候一开始计划是2007年发布所以最初这个标准叫 C 07。但是到06年的时候官方觉得2007年肯定完不成C 07而且官方觉得2008年可能也 完不成。最后干脆叫C 0x。x的意思是不知道到底能在07还是08还是09年完成。结果2010年的 时候也没完成最后在2011年终于完成了C标准。所以最终定名为C11 统一的列表初始化 C11 引入了统一的列表初始化uniform initialization这是一种新的初始化语法它使用花括号 {} 来初始化对象。统一的列表初始化提供了一种更为一致和灵活的初始化方式不仅适用于自定义类型也适用于内置类型。 统一的列表初始化的一些关键点和特性 语法一致性不论对象类型如何都可以使用 {} 来进行初始化。 灵活性它可以用来初始化数组、类对象、聚合体如结构体和联合体甚至是标准库容器。 避免最窄匹配在函数重载时使用列表初始化可以避免最窄匹配的问题因为列表初始化不会触发类型转换。 初始化器的嵌套可以嵌套使用初始化器列表例如初始化多维数组或包含其他容器的容器。 简单测试代码示例 示例 1初始化内置类型和数组 #include iostream #include vectorint main() {// 初始化内置类型int x  {42}; // 与 int x  42; 等价double y{3.14}; // 使用花括号进行初始化// 初始化数组int arr1[3]  {1, 2, 3}; // 使用花括号初始化数组int arr2[]  {4, 5, 6}; // 编译器根据初始化器列表的大小自动确定数组大小// 输出数组元素for (int i  0; i  3; i) {std::cout  arr1[  i  ]:   arr1[i]  std::endl;std::cout  arr2[  i  ]:   arr2[i]  std::endl;}return 0; }示例 2初始化类和结构体 #include iostreamstruct Point {int x, y; };class MyClass { public:MyClass(int val) : value(val) {}int value; };int main() {// 初始化结构体Point p1{1, 2}; // 结构体成员按照声明的顺序初始化Point p2  {3, 4}; // 等价于上面的初始化方式// 初始化类对象MyClass obj1{10}; // 调用构造函数进行初始化// 输出值std::cout  p1: (  p1.x  ,   p1.y  )  std::endl;std::cout  p2: (  p2.x  ,   p2.y  )  std::endl;std::cout  obj1.value:   obj1.value  std::endl;return 0; }示例 3初始化标准库容器 #include iostream #include vector #include listint main() {// 初始化 vectorstd::vectorint vec{1, 2, 3, 4, 5};// 初始化 liststd::listint lst{5, 4, 3, 2, 1};// 输出容器元素for (int i : vec) {std::cout  i   ;}std::cout  std::endl;for (int i : lst) {std::cout  i   ;}std::cout  std::endl;return 0; }在以上示例中你可以看到统一的列表初始化如何为不同的数据类型提供了一致的初始化语法。这种语法不仅提高了代码的可读性而且减少了在初始化时可能发生的错误。注意虽然统一的列表初始化在大多数情况下都很方便但也有一些情况下它可能并不适用例如初始化非聚合类对象时如果该类没有合适的构造函数接受一个初始化器列表那么就会编译失败。 声明 c11提供了多种简化声明的方式 auto关键字 在C98中auto是一个存储类型的说明符表明变量是局部自动存储类型但是局部域中定义局部的变量默认就是自动存储类型所以auto就没什么价值了。C11中废弃auto原来的用法将其用于实现自动类型腿断。这样要求必须进行显示初始化让编译器将定义对象的类型设置为初始化值的类型。 auto 关键字是 C11 引入的一个非常有用的特性它允许编译器自动推断变量的类型。这大大简化了代码编写特别是在处理复杂类型或模板时。使用 auto 可以让程序员不必显式地指定变量的类型编译器会根据初始化的表达式自动确定变量的类型。 auto 关键字的特点 自动类型推导编译器根据初始化表达式自动推断 auto 变量的类型。 简化代码特别是在处理复杂类型时使用 auto 可以使代码更加简洁。 与引用和指针的结合auto 可以与引用和指针*结合使用自动推导引用或指针的类型。 初始化要求使用 auto 声明的变量必须立即初始化否则编译会报错。 注意事项 虽然 auto 可以简化代码但过度使用可能会降低代码的可读性。因此在使用 auto 时应确保代码的可读性和可维护性。 auto 不能用于函数参数或返回类型的推导C14 引入了 auto 类型的函数返回类型但那是另外的话题。 测试代码示例 示例 1基本类型推导 #include iostreamint main() {auto x  42; // x 被推导为 int 类型auto y  3.14; // y 被推导为 double 类型std::cout  x:   x  , type:   typeid(x).name()  std::endl;std::cout  y:   y  , type:   typeid(y).name()  std::endl;return 0; }示例 2复杂类型推导如 STL 容器 #include iostream #include vectorint main() {std::vectorint vec  {1, 2, 3, 4, 5};auto it  vec.begin(); // it 被推导为 std::vectorint::iterator 类型std::cout  First element:   *it  std::endl;return 0; }示例 3与引用和指针的结合使用 #include iostream #include vectorint main() {int a  10;auto ref  a; // ref 被推导为 int 类型即 a 的引用auto* ptr  a; // ptr 被推导为 int* 类型即指向 a 的指针ref  20; // 修改 ref实际上修改了 astd::cout  a:   a  std::endl; // 输出 20*ptr  30; // 修改 ptr 指向的值实际上也修改了 astd::cout  a:   a  std::endl; // 输出 30return 0; }在上述示例中auto 关键字使得程序员不必显式声明变量 x、y、it、ref 和 ptr 的类型编译器会根据初始化的表达式自动推导出它们的类型。这不仅简化了代码还提高了代码的可读性和可维护性。当然在使用 auto 时应确保初始化的表达式是明确的以便编译器能够准确地推导出变量的类型。 decltype关键字 decltype 是 C11 引入的一个关键字它用于在编译时查询表达式的类型。decltype 提供了一种方式使得程序员能够明确地获取一个表达式或变量的类型并在需要的时候使用这个类型信息。 decltype 的基本用法 获取变量的类型decltype 可以直接用于变量以获取其类型。 获取表达式的类型decltype 也可以用于更复杂的表达式以获取该表达式的类型。 引用和指针的处理如果表达式的结果是一个左值例如变量或数组元素则 decltype 会产生对该类型的引用如果表达式的结果是一个右值例如字面量或临时对象则 decltype 会产生该类型的非引用。 decltype 的特点 类型推导编译器会根据 decltype 后面的表达式自动推导类型。 与 auto 的区别auto 用于变量声明时的类型推导而 decltype 用于在编译时查询任意表达式的类型。 灵活性decltype 可以处理复杂的表达式和类型包括函数指针、成员函数指针等。 注意事项 decltype 主要用于模板元编程和高级类型操作对于一般的应用程序开发可能并不常用。 使用 decltype 时应确保表达式的含义是明确的以避免类型推导错误。 测试代码示例 示例 1获取变量的类型 #include iostream #include type_traits // 用于 std::is_same 检查类型是否相同int main() {int x  10;decltype(x) y  20; // y 的类型与 x 相同即 intstd::cout  typeid(y).name()  std::endl; // 输出 y 的类型return 0; }示例 2获取表达式的类型 #include iostream #include type_traitsint main() {int a  5, b  10;decltype(a  b) sum  a  b; // sum 的类型与 a  b 的结果类型相同即 intstd::cout  typeid(sum).name()  std::endl; // 输出 sum 的类型return 0; }示例 3处理引用和指针 #include iostream #include type_traitsint main() {int a  5;decltype((a)) ref  a; // ref 是 int因为 a 是左值decltype(10) val  10; // val 是 int因为 10 是右值std::cout  std::boolalpha;std::cout  ref is a reference:   std::is_referencedecltype(ref)::value  std::endl; // 输出 truestd::cout  val is a reference:   std::is_referencedecltype(val)::value  std::endl; // 输出 falsereturn 0; }在上面的示例中decltype 用于推导变量的类型以及表达式的类型。同时通过使用 std::is_reference 和 std::is_same 等类型特性我们可以检查推导出的类型是否符合预期。这些特性通常定义在 type_traits 头文件中。 nullptr nullptr 是 C11 中引入的一个新关键字用于表示空指针常量。在 C11 之前通常使用 NULL 或 0 来表示空指针但是这两个选择都存在一些问题。NULL 通常是定义为 0 或 (void*)0 的宏这导致了类型的不一致性而直接使用 0 作为指针类型虽然大多数情况下可以工作但在模板编程中可能会引发问题。 nullptr 解决了这些问题它是一个类型安全的空指针常量其类型为 std::nullptr_t。它不能隐式转换为整数类型只能转换为指针类型这使得它在模板编程中更为安全和方便。 nullptr 的特点 类型安全nullptr 的类型是 std::nullptr_t这确保了它只能被赋给指针类型的变量从而避免了与整数类型的混淆。 明确性nullptr 的使用比 NULL 或 0 更明确它清晰地表示一个空指针。 与 NULL 的兼容性nullptr 可以与接受 NULL 的代码兼容因为 nullptr 可以隐式转换为 void*。 测试代码示例 #include iostreamint main() {int* ptr1  nullptr; // 使用 nullptr 初始化一个空指针int* ptr2  0; // 使用 0 初始化一个空指针在 C11 中仍然有效但不推荐int* ptr3  NULL; // 使用 NULL 初始化一个空指针在 C11 中仍然有效但不推荐if (ptr1  nullptr) {std::cout  ptr1 is nullptr  std::endl;}if (ptr2  nullptr) {std::cout  ptr2 is nullptr  std::endl;}if (ptr3  nullptr) {std::cout  ptr3 is nullptr  std::endl;}// 尝试将 nullptr 赋给非指针类型这将导致编译错误// int nonPointer  nullptr; // 错误不能将 nullptr 赋给非指针类型return 0; }在这个示例中我们创建了三个指针 ptr1、ptr2 和 ptr3并分别使用 nullptr、0 和 NULL 来初始化它们。然后我们检查这些指针是否等于 nullptr并打印相应的消息。注意尝试将 nullptr 赋给非指针类型的变量会导致编译错误这展示了 nullptr 的类型安全性。 范围for C11 引入的范围for循环Range-based for loop是一种简化遍历容器如数组、向量、列表等或任何支持迭代器的序列的语法。范围for循环通过隐藏迭代器细节使得遍历容器变得更加直观和简洁。 范围for循环的基本语法 for (declaration : expression) {// 循环体 }declaration定义了循环变量该变量会在每次迭代时接收容器中的一个元素。 expression表示一个容器或序列它必须支持 begin() 和 end() 成员函数或类似的全局函数用于获取迭代器。 关键点 迭代器隐藏范围for循环内部处理了迭代器的细节程序员无需显式使用迭代器。 自动类型推导循环变量 declaration 的类型通常由 expression 中的元素类型自动推导得出。 效率范围for循环在性能上与使用迭代器的手动循环相当没有额外的开销。 示例代码 示例 1遍历数组 #include iostreamint main() {int arr[]  {1, 2, 3, 4, 5};// 使用范围for循环遍历数组for (int num : arr) {std::cout  num   ;}std::cout  std::endl;return 0; }示例 2遍历向量vector #include iostream #include vectorint main() {std::vectorint vec  {1, 2, 3, 4, 5};// 使用范围for循环遍历向量for (int num : vec) {std::cout  num   ;}std::cout  std::endl;return 0; }示例 3遍历其他STL容器 #include iostream #include list #include setint main() {std::listint lst  {1, 2, 3, 4, 5};std::setint st  {5, 4, 3, 2, 1};// 遍历链表for (int num : lst) {std::cout  num   ;}std::cout  std::endl;// 遍历集合for (int num : st) {std::cout  num   ;}std::cout  std::endl;return 0; }注意事项 如果 expression 不支持 begin() 和 end() 函数范围for循环将无法使用。 在循环体内循环变量 declaration 是只读的对于常量表达式并且每个迭代都会得到一个新的元素副本对于非引用类型。如果需要修改容器中的元素应使用引用类型。 修改容器元素的示例 #include iostream #include vectorint main() {std::vectorint vec  {1, 2, 3, 4, 5};// 使用引用遍历向量并修改元素for (int num : vec) {num * 2; // 修改容器中的元素}// 输出修改后的向量for (int num : vec) {std::cout  num   ;}std::cout  std::endl;return 0; }在这个例子中我们使用 int整数引用作为循环变量的类型以便在循环体内直接修改向量 vec 中的元素。每个 num 都是向量中元素的引用所以当我们改变 num 的值时实际上是改变了向量中对应元素的值。 智能指针 C11 引入了三种智能指针std::unique_ptr、std::shared_ptr 和 std::weak_ptr它们旨在自动管理动态分配的内存以避免常见的内存泄漏和悬挂指针问题。这些智能指针通过自动释放它们所指向的对象简化了内存管理。 1. std::unique_ptr std::unique_ptr 表示对动态分配对象的独占所有权。同一时间只能有一个 unique_ptr 指向一个对象。当 unique_ptr 被销毁时例如超出作用域它所指向的对象也会被自动删除。 2. std::shared_ptr std::shared_ptr 实现共享所有权语义。多个 shared_ptr 可以指向同一个对象并且当最后一个指向该对象的 shared_ptr 被销毁时对象才会被删除。这通过引用计数来实现每个 shared_ptr 都持有一个指向控制块的指针该控制块包含对对象的引用计数。 3. std::weak_ptr std::weak_ptr 是对 shared_ptr 所管理对象的弱引用不会影响对象的生命周期。它主要是为了解决 shared_ptr 之间的循环引用问题。 测试代码示例 示例 1使用 std::unique_ptr #include iostream #include memoryclass MyClass { public:MyClass(int value) : value_(value) {}~MyClass() { std::cout  Destroying MyClass with value   value_  std::endl; }void printValue() const { std::cout  Value:   value_  std::endl; }private:int value_; };int main() {std::unique_ptrMyClass ptr(new MyClass(42)); // 使用 new 创建对象并用 unique_ptr 管理ptr-printValue(); // 输出对象的值// 当 ptr 离开作用域时它所指向的对象也会被自动删除return 0; }示例 2使用 std::shared_ptr #include iostream #include memoryclass MyClass { public:MyClass(int value) : value_(value) {std::cout  Creating MyClass with value   value_  std::endl;}~MyClass() {std::cout  Destroying MyClass with value   value_  std::endl;}void printValue() const { std::cout  Value:   value_  std::endl; }private:int value_; };int main() {std::shared_ptrMyClass ptr1  std::make_sharedMyClass(42); // 使用 make_shared 创建对象并用 shared_ptr 管理std::shared_ptrMyClass ptr2  ptr1; // ptr2 现在也指向同一个对象ptr1-printValue(); // 输出对象的值ptr2-printValue(); // 再次输出对象的值// 当 ptr1 和 ptr2 都离开作用域时对象才会被删除return 0; }示例 3使用 std::weak_ptr 解决循环引用问题 #include iostream #include memoryclass B;class A { public:std::shared_ptrB b_ptr;~A() { std::cout  Destroying A\n; } };class B { public:std::weak_ptrA a_ptr; // 使用 weak_ptr 避免循环引用~B() { std::cout  Destroying B\n; } };int main() {{std::shared_ptrA a  std::make_sharedA();std::shared_ptrB b  std::make_sharedB();a-b_ptr  b;b-a_ptr  a;// 此时即使 A 和 B 相互引用也不会导致循环引用问题因为 B 使用的是 weak_ptr} // a 和 b 离开作用域它们指向的对象会被正确销毁return 0; }在上述示例中std::unique_ptr 用于管理单个对象的生命周期确保对象在 unique_ptr 销毁时也被销毁。std::shared_ptr 用于共享对象的所有权当最后一个指向对象的 shared_ptr 被销毁时对象才会被删除。而 std::weak_ptr 解决了 shared_ptr 之间的循环引用问题它不会延长对象的生命周期只是提供了一个观察 shared_ptr 所管理对象的手段。 注意事项 使用智能指针时通常应避免直接使用 new 和 delete 来管理动态内存因为智能指针会自动处理这些操作。 std::make_shared 是创建 shared_ptr 的推荐方式因为它比直接使用 new 和 shared_ptr 构造函数更高效因为它只分配一次内存同时分配控制块和对象本身。 小心使用 std::shared_ptr以避免不必要的共享所有权和潜在的性能开销。在确实需要共享所有权的情况下才使用它。 当处理智能指针时注意避免野指针dangling pointers和悬挂指针dangling references即不要保留指向已删除对象的智能指针或引用。 总结 C11 的智能指针通过自动管理内存极大地简化了动态内存管理并减少了内存泄漏和悬挂指针的风险。在实际编程中应优先使用智能指针来管理动态分配的内存并谨慎处理智能指针之间的关系以避免循环引用等问题。 STL中一些变化 C11 为 STLStandard Template Library标准模板库带来了许多重要的改进和新增功能这些变化使得 STL 更加灵活、高效和易于使用。下面是一些 C11 中 STL 的主要变化以及相应的简单测试代码 1. 容器初始化 C11 提供了列表初始化List Initialization的方式初始化容器这使得代码更加简洁。 #include iostream #include vector #include list #include initializer_listint main() {// 使用初始化列表初始化 vectorstd::vectorint vec  {1, 2, 3, 4, 5};for (int i : vec) {std::cout  i   ;}std::cout  std::endl;// 使用初始化列表初始化 liststd::liststd::string lst  {apple, banana, cherry};for (const std::string s : lst) {std::cout  s   ;}std::cout  std::endl;return 0; }2. 无序容器 C11 引入了新的无序容器包括 unordered_map、unordered_multimap、unordered_set 和 unordered_multiset它们基于哈希表实现提供了常数平均时间复杂度的查找操作。 #include iostream #include unordered_mapint main() {std::unordered_mapstd::string, int umap;umap[apple]  1;umap[banana]  2;umap[cherry]  3;for (const auto pair : umap) {std::cout  pair.first  :   pair.second  std::endl;}return 0; }3. range-based for loop 基于范围的 for循环range-based for loop使得遍历容器变得更加简单。 #include iostream #include vectorint main() {std::vectorint vec  {1, 2, 3, 4, 5};// 使用基于范围的for循环遍历 vectorfor (const auto elem : vec) {std::cout  elem   ;}std::cout  std::endl;return 0; }4. auto 类型推导 在 C11 中auto 关键字用于自动推导变量类型这特别适用于迭代器和复杂的 STL 类型。 #include iostream #include vectorint main() {std::vectorint vec  {1, 2, 3, 4, 5};// 使用 auto 推导迭代器类型for (auto it  vec.begin(); it ! vec.end(); it) {std::cout  *it   ;}std::cout  std::endl;return 0; }5. 新的算法 C11 为 STL 算法库增加了一些新算法例如 std::copy_n、std::all_of、std::any_of 和 std::none_of 等。 #include iostream #include vector #include algorithmint main() {std::vectorint vec  {1, 2, 3, 4, 5};// 使用 std::all_of 检查所有元素是否都大于 0bool all_positive  std::all_of(vec.begin(), vec.end(), [](int i) { return i  0; });std::cout  std::boolalpha  All elements are positive:   all_positive  std::endl;return 0; }6. lambda 表达式 C11 引入了 lambda 表达式这使得在 STL 算法中使用匿名函数变得更加容易。 #include iostream #include vector #include algorithmint main() {std::vectorint vec  {1, 2, 3, 4, 5};// 使用 lambda表达式与 std::for_each 算法遍历并打印 vector 中的每个元素std::for_each(vec.begin(), vec.end(), [](int i) {std::cout  i   ;});std::cout  std::endl;// 使用 lambda 表达式与 std::remove_if 算法移除 vector 中所有的偶数元素vec.erase(std::remove_if(vec.begin(), vec.end(), [](int i) {return i % 2  0;}), vec.end());// 打印修改后的 vectorfor (int i : vec) {std::cout  i   ;}std::cout  std::endl;return 0; }7. 右值引用和移动语义 C11 引入了右值引用和移动语义允许资源在对象之间高效地转移这显著提高了 STL 容器的性能特别是在插入和删除元素时。 #include iostream #include vector #include stringint main() {std::string str  Hello, World!;std::vectorstd::string vec;// 使用 push_back 和移动语义添加元素到 vectorvec.push_back(std::move(str)); // str 的资源被移动到 vector 中的元素// 打印 vector 中的元素for (const auto s : vec) {std::cout  s  std::endl;}return 0; }以上只是 C11 中 STL 变化的一部分。实际上C11 对 STL 进行了许多改进和扩展包括性能优化、错误处理的改进、新算法和容器的增加等。这些变化使得 C 的标准库更加现代、高效和易用。 右值引用和移动语义 C11 引入了右值引用和移动语义这两个特性极大地提高了 C 的性能特别是在处理资源密集型对象时如大数组、大字符串或自定义的复杂数据结构。 右值引用 右值引用是对一个将要被销毁的对象的引用。它使用 符号表示并且只能绑定到右值。右值通常是临时对象或不再使用的对象。 移动语义 移动语义允许我们从一个对象“窃取”资源如内存、文件句柄等而不是复制它们。这通常通过重载移动构造函数和移动赋值运算符来实现。移动操作通常比复制操作更快因为它避免了资源的复制只是简单地重新指向原有资源。 移动构造函数 移动构造函数接受一个右值引用参数并用于初始化对象同时确保源对象在移动操作后处于有效但未定义的状态。 移动赋值运算符 移动赋值运算符也接受一个右值引用参数并用于将资源从一个对象移动到另一个已存在的对象。 std::move std::move 是一个标准库函数它将其参数转换为右值引用。它实际上并不移动任何东西但它允许我们将左值当作右值来处理从而可以调用移动构造函数或移动赋值运算符。 示例代码 #include iostream #include cstringclass ArrayWrapper { private:int* data;size_t size;public:// 构造函数ArrayWrapper(size_t s) : size(s) {data  new int[size];std::cout  Allocated   size   integers at   (void*)data  std::endl;}// 移动构造函数ArrayWrapper(ArrayWrapper other) noexcept : data(other.data), size(other.size) {other.data  nullptr;other.size  0;std::cout  Moved   size   integers from   (void*)other.data   to   (void*)data  std::endl;}// 析构函数~ArrayWrapper() {if (data) {delete[] data;std::cout  Deallocated   size   integers at   (void*)data  std::endl;}}// 移动赋值运算符ArrayWrapper operator(ArrayWrapper other) noexcept {if (this ! other) {delete[] data;data  other.data;size  other.size;other.data  nullptr;other.size  0;std::cout  Moved   size   integers from   (void*)other.data   to   (void*)data  std::endl;}return *this;}// 禁用复制构造函数和复制赋值运算符ArrayWrapper(const ArrayWrapper)  delete;ArrayWrapper operator(const ArrayWrapper)  delete; };int main() {{ArrayWrapper a(5); // 使用构造函数创建一个 ArrayWrapper 对象ArrayWrapper b  std::move(a); // 使用移动构造函数创建另一个对象资源从 a移动到b// 此时a的data指针被置为nullptr不应该再访问a} // a和b的析构函数被调用但由于a的资源已经被移动它不会尝试删除空指针ArrayWrapper c(10);ArrayWrapper d(5);d  std::move(c); // 使用移动赋值运算符将c的资源移动到d// 此时c的data指针被置为nullptr不应该再访问creturn 0; }在这个示例中ArrayWrapper 类管理一个动态分配的整数数组。它有一个移动构造函数和一个移动赋值运算符这两个函数都允许我们从一个 ArrayWrapper 对象窃取资源并“移动”到另一个对象而不是复制它们。注意我们禁用了复制构造函数和复制赋值运算符以防止不小心进行深拷贝。 std::move 函数用于将左值转换为右值引用从而允许我们调用移动构造函数或移动赋值运算符。 请注意在移动操作后源对象在这个例子中是 a 和 c处于有效但未定义的状态这意味着它们仍然是一个有效的 ArrayWrapper 对象但其内部数据在这个例子中是 data 指针不再指向有效的资源 可变参数模板 C11 引入了可变参数模板variadic templates它允许模板接受任意数量和类型的参数。这大大增强了模板的灵活性使得我们可以编写更通用和可复用的代码。可变参数模板使用模板参数包template parameter packs来实现它们是以省略号...结尾的模板参数。 可变参数模板的基本结构 template typename... Args class MyClass {// ... };template typename... Args void myFunction(Args... args) {// ... }在上面的代码中Args... 是一个模板参数包它可以代表任意类型和数量的参数。 递归分解模板参数包 处理模板参数包时通常需要使用递归模板特化或者递归函数来“解开”这个包对每一个参数进行处理。C11 提供了一种更简单的方式即使用 std::initializer_list 和 std::forward 与完美转发结合来展开参数包。 完美转发 完美转发Perfect Forwarding是 C11 引入的一个特性它允许我们将参数以原有的形式包括左值或右值转发给另一个函数。这通常与可变参数模板一起使用以实现对任意数量和类型的参数进行转发。 简单的测试代码 以下是一个简单的示例演示了如何使用可变参数模板和完美转发来创建一个通用的打印函数该函数可以接受任意数量和类型的参数并将它们打印到标准输出。 #include iostream #include utility // for std::forward// 辅助函数用于递归地打印参数 template typename Arg, typename... Args void print(Arg arg, Args... args) {std::cout  std::forwardArg(arg)   ;print(std::forwardArgs(args)...); // 递归调用 }// 终止递归的基例 void print() {std::cout  std::endl; }// 封装函数接受任意数量和类型的参数 template typename... Args void print_all(Args... args) {print(std::forwardArgs(args)...); // 展开参数包 }int main() {print_all(Hello, 42, 3.14, c); // 输出: Hello 42 3.14 cprint_all(1, world, 2.718);      // 输出: 1 world 2.718return 0; }在这个例子中print 函数是一个递归模板函数它接受一个参数 arg 和任意数量的额外参数 args...。它首先打印 arg然后递归地调用自身来打印剩余的参数。print_all 函数是一个封装函数它接受任意数量和类型的参数并使用 std::forward 将它们转发给 print 函数。 std::forward 用于完美转发参数确保左值保持为左值右值保持为右值这样我们可以保持原始参数的类别lvalue 或 rvalue这对于性能优化如移动语义至关重要。 通过可变参数模板和完美转发我们可以编写非常通用和灵活的代码以适应各种不同的使用场景。 lambda表达式 C11 中的 lambda 表达式是一种创建匿名函数对象的方式它可以捕获其所在作用域的变量并且可以在需要函数对象的地方使用。Lambda 表达式提供了一种简洁的方式来定义小型函数它们经常与 STL 算法一同使用以提供自定义的行为。 Lambda 表达式的基本语法如下 [capture](parameters) - return_type {body_of_lambda}capture捕获子句用于指定哪些外部变量可以在 lambda 体内被访问。捕获可以是按值或按引用。 parameters参数列表与常规函数参数列表相似。 return_type返回类型。如果 lambda 体中的代码不包含 return 语句或者所有路径都返回同一类型则编译器可以推导出返回类型此时 - return_type 是可选的。 body_of_lambdalambda 函数的主体包含要执行的代码。 下面是一些使用 lambda 表达式的简单示例 示例 1无捕获和无参数的 lambda #include iostream #include vector #include algorithmint main() {std::vectorint numbers  {1, 2, 3, 4, 5};// 使用无捕获和无参数的 lambda 打印每个元素std::for_each(numbers.begin(), numbers.end(), [](int n) {std::cout  n   ;});std::cout  std::endl;return 0; }示例 2捕获外部变量的 lambda #include iostream #include vector #include algorithmint main() {int threshold  3;std::vectorint numbers  {1, 2, 3, 4, 5};// 使用按值捕获外部变量 threshold 的 lambda 过滤出大于 threshold 的元素auto filtered  std::copy_if(numbers.begin(), numbers.end(),std::ostream_iteratorint(std::cout,  ),[threshold](int n) { return n  threshold; });std::cout  std::endl;return 0; }示例 3按引用捕获外部变量的 lambda #include iostream #include vector #include algorithmint main() {int sum  0;std::vectorint numbers  {1, 2, 3, 4, 5};// 使用按引用捕获外部变量 sum 的 lambda 累加 vector 中的所有元素std::for_each(numbers.begin(), numbers.end(), [sum](int n) {sum  n;});std::cout  Sum:   sum  std::endl;return 0; }示例 4带有返回类型的 lambda #include iostream #include vector #include algorithmint main() {std::vectorint numbers  {1, 2, 3, 4, 5};int max_value  0;// 使用带有返回类型的 lambda 找出 vector 中的最大值auto max_finder  [](int a, int b) - int { return (a  b) ? a : b; };max_value  std::accumulate(numbers.begin(), numbers.end(), 0, max_finder);std::cout  Max value:   max_value  std::endl;return 0; }在这些示例中lambda 表达式被用作算法如 std::for_each、std::copy_if 和 std::accumulate的参数以提供自定义的行为。Lambda 表达式让代码更加简洁和灵活因为它们允许在需要的地方直接定义小型函数而无需创建单独的函数或函数对象。 包装器 function包装器 C11 引入了 std::function它是一个通用的、多态的函数包装器。std::function 可以将任何可调用的目标函数、lambda 表达式、bind 表达式或其他函数对象封装成统一的接口。这使得函数可以作为参数传递也可以赋值给变量甚至存储在容器中。 std::function 的特点 类型擦除std::function 内部使用类型擦除技术使得你可以存储不同类型的可调用对象而无需关心其具体的类型。 通用性它可以封装任何可调用的对象包括普通函数、成员函数、lambda 表达式、bind 表达式等。 可调用性你可以像调用普通函数一样调用 std::function 对象。 使用 std::function 的简单测试代码 #include iostream #include functional // 引入 std::function// 普通函数 void normal_function(int x) {std::cout  Normal function called with:   x  std::endl; }// Lambda 表达式 auto lambda_function  [](int x) {std::cout  Lambda function called with:   x  std::endl; };// 使用 std::function 的例子 int main() {// 创建一个 std::function 对象它可以存储接受 int 参数且没有返回值的任何可调用对象std::functionvoid(int) func;// 将普通函数赋值给 std::function 对象func  normal_function;func(42); // 输出: Normal function called with: 42// 将 lambda 表达式赋值给 std::function 对象func  lambda_function;func(100); // 输出: Lambda function called with: 100// 也可以直接将 lambda 表达式构造 std::function 对象std::functionvoid(int) another_func  [](int x) {std::cout  Another lambda function called with:   x  std::endl;};another_func(200); // 输出: Another lambda function called with: 200return 0; }在上面的代码中我们首先定义了一个普通函数 normal_function 和一个 lambda 表达式 lambda_function。然后我们创建了一个 std::function 对象 func它可以接受一个 int 类型的参数并且没有返回值。我们首先将 normal_function 赋值给 func 并调用它然后将 lambda_function 赋值给 func 并调用它。最后我们还展示了如何直接用一个 lambda 表达式来构造 std::function 对象。 std::function 的一个常见用途是作为回调函数因为它允许你传递任何可调用的对象作为参数增加了代码的灵活性和可复用性。此外std::function 还可以与 std::bind 或 lambda 表达式结合使用以实现更复杂的函数调用逻辑。 bind函数适配器 C11 的 std::bind 是一个功能强大的函数适配器它可以将一个可调用对象如函数、成员函数、函数对象或 lambda 表达式与一组参数绑定在一起生成一个新的可调用对象。这个新的可调用对象可以像普通函数一样被调用且会调用原始的可调用对象并传递给它绑定的参数。 std::bind 的特点 参数绑定你可以使用 std::bind 来绑定可调用对象的参数从而在后续调用时无需再次提供这些参数。 占位符std::bind 提供了占位符 _1、_2 等用于表示绑定后的新函数对象参数的位置。 成员函数绑定你可以使用 std::bind 来绑定类的成员函数并指定要操作的对象实例。 使用 std::bind 的简单测试代码 #include iostream #include functional // 引入 std::bind// 普通函数 void print_sum(int a, int b) {std::cout  Sum:   a  b  std::endl; }// 类的成员函数 class MyClass { public:void print_hello(const std::string name) {std::cout  Hello,   name  !  std::endl;} };int main() {// 使用 std::bind 绑定普通函数的参数auto bound_print_sum  std::bind(print_sum, 10, std::placeholders::_1);bound_print_sum(20); // 输出: Sum: 30// 使用 std::bind 绑定成员函数的实例和参数MyClass obj;auto bound_member_func  std::bind(MyClass::print_hello, obj, std::placeholders::_1);bound_member_func(World); // 输出: Hello, World!// 使用 std::bind 绑定 lambda 表达式auto lambda  [](int x, int y) { return x * y; };auto bound_lambda  std::bind(lambda, 5, std::placeholders::_1);int product  bound_lambda(6); // product 现在是 30std::cout  Product:   product  std::endl; // 输出: Product: 30return 0; }在上面的代码中我们首先定义了一个普通函数 print_sum 和一个包含成员函数 print_hello 的类 MyClass。 然后我们使用 std::bind 来绑定 print_sum 函数的第一个参数为 10生成一个新的可调用对象 bound_print_sum。当我们调用 bound_print_sum(20) 时它实际上会调用 print_sum(10, 20)。 接着我们使用 std::bind 来绑定 MyClass 的实例 obj 和 print_hello 成员函数生成一个新的可调用对象 bound_member_func。当我们调用 bound_member_func(World) 时它实际上会调用 obj.print_hello(World)。 最后我们还展示了如何使用 std::bind 来绑定一个 lambda 表达式并调用它。 std::bind 的一个常见用途是生成回调函数或者将函数与特定参数绑定以生成新的行为。然而由于 lambda 表达式的灵活性和易用性在很多情况下lambda 表达式已经成为了 std::bind 的替代品。不过std::bind 仍然在某些特定场景下如绑定成员函数有其独特的用途。 线程库 C11 引入了对线程的原生支持通过 thread 头文件提供了一组用于创建和管理线程的类和函数。这使得 C 程序员能够更方便地在多核处理器上编写并发程序。 C11 线程库的主要特性 线程创建使用 std::thread 类创建新线程。 线程同步通过互斥锁std::mutex、条件变量std::condition_variable、原子操作std::atomic等实现线程同步。 C11 提供了多种工具来实现线程同步这些工具对于确保多线程环境下的数据完整性和程序正确性至关重要。 线程局部存储使用 thread_local 存储类为线程提供局部存储。 线程安全的数据结构例如 std::lock_guard、std::unique_lock、std::shared_mutex 等这些工具帮助程序员更安全地管理线程间的共享资源。 线程创建 简单的测试代码 下面是一个简单的示例展示了如何使用 C11 的线程库来创建两个线程并分别输出不同的信息。 #include iostream #include thread #include chrono // 用于休眠// 线程执行的函数 void thread_function(const std::string message) {for (int i  0; i  5; i) {std::cout  message     i  std::endl;// 休眠一段时间以便观察线程交替执行的情况std::this_thread::sleep_for(std::chrono::seconds(1));} }int main() {// 创建两个线程std::thread thread1(thread_function, Thread 1);std::thread thread2(thread_function, Thread 2);// 等待两个线程完成thread1.join();thread2.join();return 0; }在上面的代码中 std::thread 类用于创建新线程。构造函数接受一个可调用的对象例如函数、函数对象、lambda 表达式等以及任何所需的参数。 thread_function 是一个简单的函数它将一个字符串和一个整数作为参数并输出信息。 std::this_thread::sleep_for 用于使当前线程休眠一段时间。 join 成员函数用于等待线程完成执行。在 main 函数中我们调用 join 来确保 main 线程会等待 thread1 和 thread2 完成后才继续执行。 注意事项 当创建线程时请确保传递给 std::thread 构造函数的函数或 lambda 表达式是线程安全的即它们不会访问或修改没有适当同步的共享数据。 线程局部存储和原子操作是管理共享数据的重要工具它们可以确保数据的正确性和线程安全。 在多线程环境中应当特别注意资源的管理避免资源泄漏和竞争条件。 C11 的线程库为 C 程序员提供了一个强大的工具集使得编写高效且安全的并发程序变得更加容易。然而编写复杂的并发程序仍然需要深入理解和小心处理同步和通信问题。 线程同步 1. std::mutex互斥锁 std::mutex 是一个简单的互斥锁用于保护共享资源不被多个线程同时访问。当一个线程拥有互斥锁时其他尝试获取该互斥锁的线程将会被阻塞直到锁被释放。 测试代码 #include iostream #include thread #include mutex #include chronostd::mutex mtx; // 全局互斥锁 int counter  0; // 共享计数器void increment() {for (int i  0; i  1000; i) {std::lock_guardstd::mutex lock(mtx); // 使用 lock_guard 自动管理锁counter;} }int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout  Final counter value is   counter  std::endl;return 0; }在这个例子中我们使用 std::lock_guard 来自动管理锁的生命周期确保在离开作用域时锁被释放。increment 函数由两个线程 t1 和 t2 同时执行它们共同增加 counter 的值。如果没有互斥锁counter 的值可能小于 2000因为两个线程可能同时读取和写入 counter。 2. std::condition_variable条件变量 std::condition_variable 用于让线程等待某个条件成立。一个或多个线程可以在条件变量上等待而另一个线程可以在条件成立时通知这些等待的线程。 测试代码 #include iostream #include thread #include mutex #include condition_variablestd::mutex mtx; std::condition_variable cv; bool ready  false;void print_id(int id) {std::unique_lockstd::mutex lock(mtx);while (!ready) { // 等待条件成立cv.wait(lock); // 释放锁并等待通知}// ... 执行其他任务std::cout  thread   id  \n; }void go() {std::unique_lockstd::mutex lock(mtx);ready  true; // 设置条件为 truecv.notify_all(); // 通知所有等待的线程 }int main() {std::thread threads[10];// 创建并启动 10 个线程for (int i  0; i  10; i)threads[i]  std::thread(print_id, i);std::cout  10 threads ready to race...\n;go(); // 发送通知for (auto th : threads) th.join();return 0; }在这个例子中我们创建了 10 个线程它们都等待 ready 变量变为 true。主线程调用 go 函数该函数设置 ready 为 true 并使用 cv.notify_all() 通知所有等待的线程。 3. std::atomic原子操作 std::atomic 提供了对基本数据类型的原子操作这些操作在多线程环境中是安全的。原子操作不可分割即它们不会在执行过程中被其他线程打断。 测试代码 #include iostream #include thread #include atomicstd::atomicint counter(0); // 原子整数void increment() {for (int i  0; i  1000; i) {counter; // 原子增加} }int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout  Final counter value is   counter std::endl; return 0; }在这个例子中我们使用 std::atomicint 来定义 counter它是一个线程安全的整数。两个线程 t1 和 t2 同时增加 counter 的值。由于使用了原子操作最终 counter 的值将准确为 2000不会出现数据竞争或不一致的情况。 注意事项 std::mutex 提供了互斥访问共享资源的能力但过度使用可能导致性能下降和死锁。 std::condition_variable 应与互斥锁一起使用以安全地等待和通知条件变化。 std::atomic 是轻量级的适用于简单的原子操作但可能不支持所有类型的原子操作或复杂的复合操作。 在使用这些同步工具时应谨慎处理死锁和活锁问题确保线程能够正确、高效地协作。此外根据具体的应用场景和性能要求可能需要结合使用多种同步机制以达到最佳效果。 线程安全的数据结构 C11 引入了两种锁保护的数据结构std::lock_guard 和 std::unique_lock它们用于简化互斥量std::mutex的管理确保资源的正确同步访问。这两种锁类型都提供了 RAIIResource Acquisition Is Initialization风格的锁管理即锁的获取在构造时自动完成锁的释放则在对象销毁时自动完成。 std::lock_guard std::lock_guard 是一个简单的锁类型它在构造时自动锁定互斥量并在析构时自动解锁。它适用于简单的锁定/解锁场景其中不需要手动控制锁的获取和释放。 std::unique_lock std::unique_lock 是一个更灵活的锁类型它提供了比 std::lock_guard 更多的控制选项。你可以延迟锁定、尝试锁定、手动解锁等。它还允许与 std::condition_variable 一起使用以在特定条件下等待。 简单的测试代码 下面是一个简单的示例展示了如何使用 std::lock_guard 和 std::unique_lock 来保护共享资源。 #include iostream #include thread #include mutex #include chrono // 用于休眠// 共享资源 int shared_data  0; // 互斥量用于保护 shared_data std::mutex mtx;// 使用 std::lock_guard 的线程函数 void increment_with_lock_guard() {for (int i  0; i  5; i) {std::lock_guardstd::mutex lock(mtx); // 在构造时自动锁定 mtxshared_data;std::cout  shared_data incremented to   shared_data   by lock_guard\n;std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 休眠一段时间} }// 使用 std::unique_lock 的线程函数 void increment_with_unique_lock() {for (int i  0; i  5; i) {std::unique_lockstd::mutex lock(mtx); // 在构造时自动锁定 mtxshared_data;std::cout  shared_data incremented to   shared_data   by unique_lock\n;lock.unlock(); // 手动解锁std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 休眠一段时间lock.lock(); // 手动重新锁定} }int main() {// 创建两个线程分别使用 lock_guard 和 unique_lockstd::thread t1(increment_with_lock_guard);std::thread t2(increment_with_unique_lock);// 等待两个线程完成t1.join();t2.join();std::cout  Final shared_data value:   shared_data  std::endl;return 0; }在这个例子中 shared_data 是被多个线程访问的共享资源。 mtx 是一个互斥量用于保护 shared_data 的访问。 increment_with_lock_guard 函数使用 std::lock_guard 来自动管理锁。在函数体内部lock_guard 对象在构造时自动锁定 mtx并在函数返回时即 lock_guard 对象销毁时自动解锁。 increment_with_unique_lock 函数使用 std::unique_lock它提供了更多的灵活性。在这个例子中我们展示了如何手动解锁和重新锁定互斥量。 注意事项 当你使用 std::lock_guard 或 std::unique_lock 时你不需要显式调用 lock() 或 unlock() 方法除非你有特定的需求。 std::lock_guard 更适合简单的同步需求而 std::unique_lock 更适合需要更精细控制同步的场景。 使用锁时要特别注意避免死锁。死锁通常发生在两个或更多的线程无限期地等待一个资源而该资源又被另一个线程持有后者也在等待其他线程释放资源。 在多线程环境中使用锁来保护共享资源是一种常见的做法但也要注意锁的使用可能会引入性能瓶颈因此应该谨慎使用并考虑其他同步机制如条件变量、原子操作等。

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

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

相关文章

邯郸网站设计价格做花瓶的网站

QT VS环境安装后出现生成的程序can not start 问题原因: windows kit 没有配置到系统环境变量 解决方法: 添加环境变量

深圳 做网站 互联wordpress win调试

缩短JDK发布周期的原因之一是有可能推出更快的安全错误修复和增强功能。 在本文中,我们将简要回顾一下最新JDK版本中引入的主要安全增强功能。 由于这些增强功能中的大多数与TLS相关,因此必须了解TLS握手过程,如下图所示: JDK 9 …

做ppt网站大全为什么在百度搜不到我的网站

实例需求:产品清单如A列所示,现在如下统计词组词频。想必各位小伙伴都指定如何使用字典对象实现去重,进而实现单个单词的词频统计。 但是统计词组词频就没有那么简单了,为了便于演示,此处的词组只限于两个单词的组合。…

定制网站建设成本网络营销公司取名字大全

描述: 难点: 将[[‘a’,‘b’,‘c’],[‘d’,‘e’,‘f’]]输出为[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”]. 关键代码描述: 1.假设我们已经根据输入的数字得到了 rawArr [[‘a’,‘b’,‘c’],[‘d’,‘e’,‘f’]] 2. 下一步将rawArr[0…

网站主机与服务器安徽省两学一做网站专栏

2016年认证杯SPSSPRO杯数学建模 D题 NBA是否有必要设立四分线 原题再现: NBA 联盟从 1946 年成立到今天,一路上经历过无数次规则上的变迁。有顺应民意、皆大欢喜的,比如 1973 年在技术统计中增加了抢断和盖帽数据;有应运而生、力…

搭建网站运行环境网站建设企业 熊账号

手把手教你写专利申请书怎样申请专利摘要小前言(一)申请前的准备工作 1、申请前查询 2、其它方面的考虑 3、申请文件准备(二)填写专利申请系列文档 1、实际操作步骤 2、详细操作 3、经验分享、注意事项&#xf…

手机网站建设的图片网站运营需要

简单介绍一下JsoupJsoup是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于Xpath,jQuery的操作方法来取出和操作元素和数据。使用Jsoup,需要导入Jsoup所需Jar包&a…

网站建设专家工作总结地推扫码平台

好久不看大陆的恐怖电影了。18号是《门》的首映,我是冲着原作者周德东去的,也是冲着导演李少红去的。况且又是在北京音响效果最好的影院华星。电影没让我失望,甚至还超乎了我的期待。首先,场景设在重庆是个不错的选择,…

贵州建设职业技术学院招商网站js不能打开插件wordpress

前言 数据采集的步骤是固定: 发送请求, 模拟浏览器对于url地址发送请求获取数据, 获取网页数据内容 --> 请求那个链接地址, 返回服务器响应数据解析数据, 提取我们需要的数据内容保存数据, 保存本地文件 所需模块 win R 输入cmd 输入安装命令 pip install 模块名 (如果你…

有什么比较好的做海报网站wordpress仿fe素材

阅读文献代码时发现新版scipy中的imread,imsave,imresize被弃用报错 搜索了一下发现可以用imageio中的imread和imsave代替原有的,用numpy的reshape来代替imresize 试了一下,不太行,文献中imread有mode‘L’,即读取灰度图&#xff…

济南seo整站优化招商电话网站建设 计划书

一、背景知识:点乘、叉乘复数的点乘:(aibjck)•(xiyjzk)-(axbycz)复数的叉乘:(aibjck)(xiyjzk)(ax)ii(ay)ij(az)ik(bx)ji(by)jj(bz)jk(cx)ki(cy)kj(cz)kkijk三轴定义如上图所示。满足右手螺旋定则:(这个不是太明白,但是…

站长工具下载app自己搭建ddns动态域名解析

winclone 8 Mac版是一款专业的boot Camp迁移助手,能够将你的PC移动到你的Mac中,让你实现win系统的迁移。winclone Mac版可以将Bootcamp分区安装的windows进行克隆也可将克隆文件传回Bootcamp分区。并且操作简单。你只需要通过几次点击,就能快…

长沙推广网站南京百度seo代理

概述 jstack可用于导出java运用程序的线程堆栈。其基本使用语法为: jstack [-l] pid -l 选项用于打印锁的额外信息。使用演示样例 以下这段代码执行之后会出现死锁现象(由于线程1持有lock1。在等待lock2。线程2持有lock2在等待lock1,造成了循环等待。形成…

如何设计和建立一个公司的网站专业做网络推广

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/justin051/article/details/84289189Python使用sorted函数来排序:l [2,1,3,5,7,3]print …

有哪些做网站的专门做离异相亲的网站

今天要分享的是基于BEV的多模态、多任务、端到端自动驾驶模型FusionAD,其专注于自动驾驶预测和规划任务。这项工作首次发表于2023年8月2日,性能超越了2023 CVPR最佳论文UniAD模型。论文题目是FusionAD: Multi-modality Fusion for Prediction and Planni…

漫画网站开发源码社交模板wordpress

MySQL 御用的 ODBC 驱动程序发布了 5.2.4 版本,下载地址: http://dev.mysql.com/downloads/connector/odbc/5.2.html 没有改进说明! 转载于:https://www.cnblogs.com/shihao/archive/2013/02/06/2901851.html

北京朝阳网站制作仿网站建设教程视频教程

光端机,就是光信号传输的终端设备。光端机现在能传输的业务很多,如:视频,音频,数据,开关量,电话,以太网等。那么,你对光端机的几种物理接口了解吗,是否懂得光…

惠州市 网站开发公司重庆建站免费模板

文章目录一、专题页1. 效果图2. 专题api2.Topic.vue 组件3. 专题源码二、分类页2.1. 效果图2.2. 分类api2.3. Category.vue 组件三、购物车页3.1. 效果图3.2. 购物车api3.3. 购物车页面四、我的页4.1. 效果图4.2. 定义api4.3. User.vue五、路由守卫和异常处理5.1. 编写路由守卫…

成都网站外包公司北京南站地铁线路图

越狱 第一季 Prison Break Season 1 (2005) 本季看点:迈克尔斯科菲尔德是一头陷于绝境欲拼死一搏的怒狮——他的哥哥林肯巴罗斯被认定犯有谋杀罪被投入了福克斯河监狱的死囚牢。虽然所有的证据都指出林肯就是凶手,迈克尔坚信兄长是无辜的。林肯的死刑执行…