【C++11】C++11新纪元:深入探索右值引用与移动语义

📝个人主页🌹:Eternity._
⏩收录专栏⏪:C++ “ 登神长阶 ”
🤡往期回顾🤡:位图与布隆过滤器
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀C++11

  • 📒1. C++11简介
  • 📜2. 统一的列表初始化
    • 🌸{ }初始化
    • 🌺initializer_list
  • 📚3. decltype与新容器 array
    • 🎩decltype
    • 🎈新容器 array
  • 📝4. 右值引用和移动语义
    • ⛰️左值引用和右值引用
    • 🌄左值引用与右值引用比较
    • 🌞右值引用使用场景和意义
    • ⭐完美转发
  • 📙5. 新的类功能
  • 📖6. 总结


前言:在C++的悠久历史中,每一次标准的更新都如同为这门强大的编程语言注入了新的活力。C++11,作为这一进程中的一个重要里程碑,不仅带来了众多新特性,还深刻改变了C++编程的范式,其中右值引用(Rvalue References)无疑是最为引人注目的特性之一

在传统的C++编程中,我们习惯于通过左值(Lvalues)来引用和操作对象,这些左值通常指向具有持久身份的对象。然而,随着C++应用的日益复杂和对性能要求的不断提高,如何高效地处理临时对象(即右值,Rvalues)成为了亟待解决的问题。C++11引入的右值引用,正是为了填补这一空白,它允许我们直接引用即将被销毁的临时对象,从而开启了C++编程的新纪元

本篇将带您深入探索C++11中的右值引用及其相关特性,包括移动语义(MoveSemantics)、完美转发(Perfect Forwarding)等。我们将从基础概念讲起,逐步深入到实际应用和最佳实践,旨在帮助您全面理解并掌握这一强大的编程工具

让我们一起踏上学习的旅程,探索它带来的无尽可能!


📒1. C++11简介

C++11是C++编程语言的一个重大更新版本,也被称为C++标准第三版,正式名称为ISO/IEC 14882:2011 - Information technology – Programming languages – C++

相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个重点去学习

C++11标准的发布对C++编程产生了深远的影响,推动了C++语言的现代化和性能提升。随着各大主流编译器(如GCC、Clang、MSVC等)对C++11语法的支持逐渐完善,越来越多的项目开始采用C++11标准进行开发。同时,相关的技术书籍和教程也相继更新,以支持C++11的新特性

总之,C++11是C++编程语言发展历程中的一个重要里程碑,它带来了众多新特性和改进,为C++程序员提供了更加强大和灵活的工具来编写高效、可维护的代码

C++11介绍


📜2. 统一的列表初始化

在C++11及以后的版本中,引入了统一的列表初始化(Uniform Initialization)或称为初始化列表(Initialization List),这是一种新的初始化语法,使用大括号{}来初始化变量。统一的列表初始化不仅提高了代码的一致性和可读性,还解决了之前初始化语法中的一些歧义和限制


🌸{ }初始化

在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定

代码示例 (C++):

// C++98
struct Pxt
{int _x;int _y;
};
int main()
{Pxt p = { 1, 2 };return 0;
}

C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加

代码示例 (C++):

// C++11
struct Pxt
{int _x;int _y;
};
int main()
{int a = 1;int b{ 2 };Pxt p{ 1, 2 };// C++11中列表初始化也可以适用于new表达式中int* pa = new int[4]{ 0 };return 0;
}

我们的自定义创建的对象也可以使用列表初始化方式调用构造函数初始化

代码示例 (C++):

class Date
{
public:Date(int year, int month, int day):_year(year), _month(month), _day(day){cout << "Date(int year, int month, int day)" << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 7, 28); // old style// C++11支持的列表初始化,这里会调用构造函数初始化Date d2{ 2024, 7, 29 };Date d3 = { 2024, 7, 30 };// 这里的 vector 和上面的 Date 不太一样vector<int> v = { 1,2,3,4,5 };return 0;
}

列表初始化时,必须要跟对应的构造函数参数个数匹配,Data中只能有三个参数,但是vector的参数可以有很多个,列表初始化也支持隐式类型转换

vector<Data> vd = { {2024, 7, 28},{2024, 7, 29},{2024, 7, 30} };

🌺initializer_list

initializer_list 是 C++11 引入的一个特性,它提供了一种方式来初始化容器类对象或函数参数列表,使得可以使用花括号 { } 来直接初始化对象或传递参数。initializer_list 是一个轻量级的模板类,它用于表示一个给定类型的值的数组,但大小是固定的,且生命周期与包含它的对象相同

initializer_list介绍文档

代码示例 (C++):

int main()
{auto it = { 1 ,2 };// initializer_listcout << typeid(it).name() << endl;return 0;
}

在这里插入图片描述


在这里插入图片描述
在这里插入图片描述

注意:initializer_list的迭代器就是原生指针


std::initializer_list一般是作为构造函数的参数,C++11对STL中的不少容器就增加 std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator=的参数,这样就可以用大括号赋值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我们当初在模拟实现这些STL容器时,并没有实现initializer_list,今天我们以vector为例子,实现一下initializer_list的构造

代码示例 (C++):

vector(initializer_list<T> lt)
{reverse(lt.size());for(auto& e : lt){push_back(e);}
}

📚3. decltype与新容器 array

🎩decltype

decltype 是 C++11 引入的一个关键字,它作为操作符用于查询表达式的数据类型。这个操作符主要用于泛型编程中,特别是在模板编程中,当需要推导表达式的类型但又不想实际执行该表达式时,decltype 显得尤为有用

代码示例 (C++):

int main()
{const int x = 1;double y = 2.2;decltype(x * y) ret; // ret的类型是doubledecltype(&x) p; // p的类型是int*cout << typeid(ret).name() << endl;cout << typeid(p).name() << endl;return 0;
}

关键字decltype将变量的类型声明为表达式指定的类型


🎈新容器 array

在C++中,std::array 是一个固定大小的容器,它提供了类似于数组的接口,但它是标准库的一部分,因此提供了更多的安全性和灵活性。std::array 定义在头文件 <array> 中,是一个模板类,可以存储任何类型的固定数量元素

在这里插入图片描述

array<int, 10> a; // a[10]vector<int> v(10, 0) 
// 因为有vector的存在,让array的出现有点“小丑”,而且vector 似乎比array好用

因为有vector的存在,让array的出现有点“小丑”,而且vector 似乎比array好用,这里我就不细说了,想了解的朋友可以了解一下

array介绍文档


📝4. 右值引用和移动语义

右值引用

  • 在C++中,表达式根据它们是否可以被修改分为左值(lvalue)和右值(rvalue)。左值是可以被取地址的表达式,通常对应于具有持久状态的实体(如变量)。而右值则是不可以被取地址的临时对象或字面值,它们通常表示计算的结果或函数返回的临时对象。
  • 右值引用是C++11引入的一种新类型的引用,它通过类型后加&&来表示。右值引用可以绑定到右值上,但也可以绑定到左值上(需要std::move来显式转换)。右值引用的主要目的是允许函数或操作以“移动”而不是“复制”的方式处理资源,这通常意味着资源的所有权从源对象转移到目标对象,源对象则变为一个安全可销毁的状态。

移动语义

移动语义允许对象通过转移其资源(如动态分配的内存)而不是复制它们来初始化或赋值另一个对象。这通常是通过一个特殊的成员函数——移动构造函数和移动赋值操作符来实现的。这两个函数都接受右值引用作为参数,表示它们可以从一个即将被销毁的对象中“窃取”资源。

  • 移动构造函数: 接受一个右值引用参数,用于初始化新对象,通过转移源对象的资源而不是复制它们,从而避免不必要的资源分配和复制。
  • 移动赋值操作符: 同样接受一个右值引用参数,用于将一个对象的资源转移到另一个已经存在的对象上,并将源对象置于一个可析构的状态。

⛰️左值引用和右值引用

左值引用

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋
值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边
。定义时const修饰符后的左
值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名

代码示例 (C++):

int main()
{// p、b、c、*p都是左值int* p = new int(0);int b = 1;const int c = 2;// 对上面左值的左值引用int*& rp = p;int& rb = b;const int& rc = c;int& pvalue = *p;return 0;
}

右值引用

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回) 等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。右值引用就是对右值的引用,给右值取别名

代码示例 (C++):

int main()
{double x = 1.1, y = 2.2;// 常见的右值10;x + y;fmin(x, y);// 对右值的右值引用int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);return 0;
}

左操作数必须为左值,否则就会报错

int main()
{// 这里编译会报错:error C2106: “=”: 左操作数必须为左值10 = 1;x + y = 1;fmin(x, y) = 1;
}

注意:

  • 不能用一个值能不能修改来区分左右值,右值是不能取地址的
  • 给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址

🌄左值引用与右值引用比较

左值引用:

  • 左值引用只能引用左值,不能引用右值
  • 但是const左值引用既可引用左值,也可引用右值

代码示例 (C++):

int main()
{// 左值引用只能引用左值,不能引用右值。int a = 10;int& ra1 = a; // ra为a的别名//int& ra2 = 10; // 编译失败,因为10是右值// const左值引用既可引用左值,也可引用右值。const int& ra3 = 10;const int& ra4 = a;return 0;
}

右值引用:

  • 右值引用只能右值,不能引用左值
  • 但是右值引用可以move以后的左值

代码示例 (C++):

int main()
{// 右值引用只能右值,不能引用左值。int&& r1 = 10;// error C2440: “初始化”: 无法从“int”转换为“int &&”// message : 无法将左值绑定到右值引用int a = 10;int&& r2 = a;// 右值引用可以引用move以后的左值int&& r3 = std::move(a);return 0;
}

move

当你对一个对象使用move时,你实际上是在告诉编译器:“这个对象我之后可能不再需要了,或者我可以接受它处于某种未定义状态,所以你可以安全地‘窃取’它的资源。”,从而变成将亡值,然后,编译器会寻找接收该对象的函数是否支持移动语义(即是否有一个接受右值引用的构造函数或赋值运算符)

在这里插入图片描述

代码示例 (C++):

int main()
{string s1("hello world");string s2 = s1;string s3 = move(s1);return 0;
}

在这里插入图片描述
直接将s1中的资源“移动”到了s3中


🌞右值引用使用场景和意义

右值引用让我们能够在一些函数中直接使用右值,而不用开空间而节省资源,而在STL的很多容器中也够重载了右值引用

在这里插入图片描述
在这里插入图片描述

右值引用的使用可以让很多场景得到更高的效率来实现功能

移动构造,移动赋值代码示例 (string为例):

// 移动构造
string(string&& s):_str(nullptr),_size(0),_capacity(0)
{cout << "string(string&& s) -- 移动语义" << endl;swap(s);
}// 移动赋值
string& operator=(string&& s)
{cout << "string& operator=(string&& s) -- 移动语义" << endl;swap(s);return *this;
}

左值引用做参数可以减少拷贝,提高效率的使用场景和价值,但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回

代码示例 :

string to_string(int x)
{string ret;while (x){int val = x % 10;x /= 10;ret += ('0' + val);}reverse(ret.begin(), ret.end());return ret;
}int main()
{string ret = to_string(1234);return 0;
}

在这里插入图片描述

  • to_string的返回值是一个右值,用这个右值构造ret2,如果没有移动构造,调用就会匹配调用拷贝构造,因为const左值引用是可以引用右值的,这里就是一个深拷贝
  • 移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己,而移动构造中没有新开空间,拷贝数据,所以效率就提高了
  • 如果既有拷贝构造又有移动构造调用就会匹配调用移动构造,因为编译器会选择最匹配的参数调用。那么这里就是一个移动语义

在这里插入图片描述


有些场景下,可能真的需要用右值去引用左值实现移动语义。当需要用右值引用引用一个左值时,可以通过move函数将左值转化为右值。该函数名字具有迷惑性,它并不搬移任何东西,唯一的功能就是将一个左值强制转化为右值引用,然后实现移动语义

代码示例 :

void push_back (value_type&& val);int main()
{list<pxt::string> lt;pxt::string s1("1111");// 这里调用的是拷贝构造lt.push_back(s1);// 下面调用都是移动构造lt.push_back("2222");lt.push_back(std::move(s1));return 0;
}

在这里插入图片描述


⭐完美转发

“完美转发”(Perfect Forwarding)是C++11及以后版本中引入的一个特性,它允许函数模板以完全相同的类型(包括const限定符和引用类型)转发其参数到另一个函数或模板。这通常通过模板和std::forward函数实现


模板中的&& 万能引用

我们写代码测试一下,如果是右值引用就调用函数打印右值引用,如果是左值引用就调用函数打印左值引用

代码示例 :

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }template<typename T>
void PerfectForward(T&& t)
{Fun(t);
}
int main()
{PerfectForward(10); // 右值int a;PerfectForward(a); // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b); // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}

神奇的一幕发生了,我们运行发现结果全是左值引用
在这里插入图片描述

我们有以下结论:

  • 模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值
  • 模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力
  • 但是引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值

那我们如何能够在传递过程中保持它的左值或者右值的属性, 就需要用我们用到完美转发


完美转发

forward 它允许函数模板将参数转发到另一个函数时,保持其值类别(左值或右值)不变。这是通过模板的隐式类型转换和引用折叠规则实现的,完美转发在传参的过程中保留对象原生类型属性

template<typename T>
void PerfectForward(T&& t)
{Fun(forward<T>(t));
}

在这里插入图片描述


📙5. 新的类功能

C++11在原来的基础上新增了两个默认成员函数:移动构造函数和移动赋值运算符重载

关于这两个函数需要注意:

  • 如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任
    意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类
    型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,
    如果实现了就调用移动构造,没有实现就调用拷贝构造。
  • 如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中
    的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内
    置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋
    值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造
    完全类似)
  • 如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值

禁止生成默认函数的关键字delete

如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补丁
已,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即
可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数

class Person
{
public:Person(const char* name = "", int age = 0):_name(name), _age(age){}Person(const Person& p) = delete;private:string _name;int _age;
};

📖6. 总结

在探索C++11的广阔特性时,右值引用无疑是一个令人兴奋且意义深远的新特性。它不仅为C++带来了移动语义和完美转发的能力,还极大地增强了C++代码的性能和灵活性。通过深入学习和实践右值引用,我们学会了如何更有效地管理资源,减少了不必要的拷贝操作,从而提高了程序的运行效率

在学习过程中,我们见证了右值引用如何与移动构造函数、移动赋值操作符以及std::move函数等配合使用,共同构建起了一套完整的移动语义体系。这套体系不仅优化了STL容器的性能,还为我们编写高性能的C++代码提供了强有力的支持

随着C++标准的不断演进,我们期待看到更多基于右值引用的新特性和优化,C++11的内容我们还没有完全了解,愿我们都能保持好奇心和求知欲,不断探索C++的无限可能,我们下期见!

在这里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

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

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

相关文章

【Qt】修改窗口的标题和图标

以下操作仅对顶层 widget(独⽴窗口),有效。 修改窗口的标题 一.windowTitle属性 1.概念 是一种在用户界面中显示窗口的标题的属性。它可以用来设置窗口的标题栏文本。 2.API API说明windowTitle()获取到控件的窗⼝标题.setWindowTitle(const QString& title)设置控件的…

10 BERT

目录 1 综述 1.1 BERT的核心思想 1.2 BERT的关键技术&#xff1a;预训练阶段 1.3 微调阶段 2 BERT的架构 2.1 输入处理 3. 特征选择/学习模块 BERT 的自注意力过程 4. 预训练任务&#xff1a;同时进行 4.1 Next Sentence Prediction (NSP) 4.2 Masked Language Model…

基于微信小程序+SpringBoot+Vue的网络安全科普系统(带1w+文档)

基于微信小程序SpringBootVue的网络安全科普系统(带1w文档) 基于微信小程序SpringBootVue的网络安全科普系统(带1w文档) 优质的网络安全科普系统不仅可以单纯的满足工作人员管理的日常工作需求&#xff0c;还可以满足用户的需求。可以降低工作人员的工作压力&#xff0c;提高效…

2024.7.29 作业

1> 写一个日志文件&#xff0c;将程序启动后&#xff0c;每一秒的时间写入到文件中 #include <myhead.h> int main(int argc,const char *argv[]) {FILE *fp NULL;if((fpfopen("./log.txt","r"))NULL) {perror("open error1");return…

Python数值计算(1)

准备总结一下通过Python进行数值计算的环境&#xff0c;先说一下数值计算的基本语法和库。 1.基本运算 Python中提供基本运算符&#xff0c;常见的加减乘除&#xff0c;唯一需要注意的是除法&#xff0c;整数除法和浮点数除法不一样。 一般除法/&#xff0c;无论参与运算的数…

通信系统的均衡技术

1、摘要 在通信系统中&#xff0c;信号从发送端发出&#xff0c;经过信道&#xff0c;到达接收端&#xff0c;而在传输的过程中&#xff0c;信号会发生失真&#xff0c;产生失真的原因有很多&#xff0c;包括阻抗不匹配&#xff0c;干扰等。为了优化信号质量&#xff0c;需要进…

基于tkinter的学生信息管理系统之登录界面和主界面菜单设计

目录 一、tkinter的介绍 二、登陆界面的设计 1、登陆界面完整代码 2、部分代码讲解 3、登录的数据模型设计 4、效果展示 三、学生主界面菜单设计 1、学生主界面菜单设计完整代码 2、 部分代码讲解 3、效果展示 四、数据库的模型设计 欢迎大家进来学习和支持&#xff01…

灯具外贸公司用什么企业邮箱好

灯具外贸公司面对海外市场的推广、产品销售、客户沟通、市场信息收集等多重需求&#xff0c;选择一个合适的企业邮箱显得尤为重要。本文将介绍灯具外贸公司为什么应选择Zoho Mail企业邮箱&#xff0c;并详细探讨其优势和功能。 一、公司背景 广东省深圳市光明新区&#xff0c…

Redis 安装和数据类型

Redis 安装和数据类型 一、Redis 1、Redis概念 redis 缓存中间件&#xff1a;缓存数据库 nginx web服务 php 转发动态请求 tomcat web页面&#xff0c;也可以转发动态请求 springboot 自带tomcat 数据库不支持高并发&#xff0c;一旦访问量激增&#xff0c;数据库很快就…

vTESTstudio中如何添加DLL文件?

文章目录 一、CANoe添加DLL二、vTESTstudio中添加DLL1.手动添加2.代码添加 一、CANoe添加DLL 在CANoe中添加DLL的路径如下图&#xff0c;在Simulation Setup中选择需要添加的节点&#xff0c;右键选择Configuration进行添加DLL。 二、vTESTstudio中添加DLL 1.手动添加 在打…

java中 VO DTO BO PO DAO

VO、DTO、BO、PO、DO、POJO 数据模型的理解和实际使用_vo dto bo-CSDN博客 深入理解Java Web开发中的PO、VO、DTO、DAO和BO概念_java dto dao-CSDN博客

【计算机网络】WireShark和简单http抓包实验

一&#xff1a;实验目的 1&#xff1a;熟悉WireShark的安装流程和界面操作流程。 2&#xff1a;学会简单http的抓取和过滤&#xff0c;并分析导出结果。 二&#xff1a;实验仪器设备及软件 硬件&#xff1a; Windows 2019操作系统的计算机等。 软件&#xff1a;WireShark、…

【算法/训练】:动态规划(线性DP)

一、路径类 1. 字母收集 思路&#xff1a; 1、预处理 对输入的字符矩阵我们按照要求将其转换为数字分数&#xff0c;由于只能往下和往右走&#xff0c;因此走到&#xff08;i&#xff0c;j&#xff09;的位置要就是从&#xff08;i - 1&#xff0c; j&#xff09;往下走&#…

前端面试基础题(微信公众号:前端面试成长之路)

BFC、IFC、GFC、FFC CSS2.1中只有BFC和IFC, CSS3中才有GFC和FFC。 到底什么是BFC、IFC、GFC和FFC Whats FC&#xff1f; 一定不是KFC&#xff0c;FC的全称是&#xff1a;Formatting Contexts&#xff0c;是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域&#xff0c;并…

免费【2024】springboot 宠物领养救助平台的开发与设计

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

普元EOS学习笔记-EOS项目HTTP访问安全和权限控制

前言 对于企业应用系统&#xff0c;出于安全和权限控制的目的&#xff0c;需要对http请求做若干控制。 比如文件上传的时候要控制不允许上传的文件后缀。 又比如控制应用程序中的哪些资源不允许被访问。 EOS项目通过 xml配置文件来实现这一需求。 Http访问管理模块 在EOS项…

【C++版本】protobuf与gRPC

文章目录 一、Protobuf二、安装以及使用protoc参考 一、Protobuf Google Protocol Buffers&#xff08;protobuf&#xff09;是一种语言中立、平台中立的序列化协议&#xff0c;旨在高效地将结构化数据进行序列化和反序列化。它主要用于通信协议、数据存储和其他需要高效编码和…

封装和桥接Unity 协程体系

简介 协程&#xff08;Coroutine&#xff09;在C#中是一种特殊的函数&#xff0c;它允许开发者编写可以暂停执行并在未来某个时刻恢复执行的代码块。协程通常用于实现异步操作&#xff0c;如延时执行、等待某个事件发生、或者分段执行复杂的任务。在Unity游戏引擎中&#xff0c…

(Arxiv-2023)MobileDiffusion:移动设备上即时文本到图像生成

MobileDiffusion&#xff1a;移动设备上即时文本到图像生成 Paper Title&#xff1a;MobileDiffusion: Instant Text-to-Image Generation on Mobile Devices Paper是谷歌出品 Paper地址 图 1&#xff1a;MobileDiffusion 用于 (a) 文本到图像的生成。(b) Canny 边缘到图像、风…

docker容器cuda不可用,怎么解决?

通过Docker 构建的镜像中,启动之后,发现容器内部读取不到显卡驱动nvidia-smi 1、设置 NVIDIA Docker 存储库 distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add