C++进阶 —— 右值引用(C++11新特性)

【C++】右值引用(极详细版) 右值引用的两个价值;万能引用和完美转发 阅读详情

目录

一,左值与右值

左值 loactor value

右值 read value

二,右值引用

以值的形式返回对象的缺陷

三,移动语义

move函数

四,完美转发

forward函数


一,左值与右值

        左值与右值是C语言中的概念,但并没有严格的区分方式;在C++中每个表达式都有两个独立属性:类型和值分类;值类别决定表达式如何被使用,最主要的值类别为左值和右值;

        左右值根本的区别在于是否可通过取地址以获取对应内存地址;通俗来说,可以放在=左边的、或能取地址的称为左值,只能放在=右边的、或不能取地址的称为右值,但不完全正确;可看出,左值一定可以作为右值使用,右值一定不能为左值使用;

         expression
          /      \
     glvalue    rvalue
      泛左值      右值
       /  \      /  \
   lvalue  xvalue   prvalue
    左值    将亡值    纯右值

左值 loactor value

有标识符(变量名),占据特定内存位置且可取地址,可出现在赋值运算符左边;

  • 普通类型的变量可取地址,都认为是左值;
  • 如单个变量是引用或表达式运行结果是引用,则认为是左值;
  • const修饰的常变量是不可修改的只读类型,但可取地址,C++11认为是左值(常量左值);
  • 字符串字面量为左值,有固定内存位置可取地址,类型为const char[N](常量左值);
  • 右值引用本身是左值,所有有名字的引用变量本身都是左值;
int a = 1; //普通类型变量a为左值,可取地址&a
int arr[10]; arr[0]=1;
string s="hello"; s[0]='H'; //operator[]返回左值引用,所以vec[0]是左值

int& c = a; //引用变量c为左值
int& fun(int& a) { return a; }
fun(a) = 10; //表达式fun(a)运行结果是引用为左值

const int b = 1; //常变量b认为是常量左值
const char* good_ptr = "Hello"; //"Hello"是常量左值,可取地址(&"Hello")

//std::move(str)返回参数右值引用,这个返回的表达式本身是将亡值
void process(string&& str) {
    // 在函数内部,str是有名字的变量,所以是左值!
    string local = std::move(str); // 需要std::move将左值转为右值
}

右值 read value

临时的,没有名字,即将销毁的值;

  • 纯右值 Pure Right Value,无标识,通常用于初始化对象或计算表达式,生命周期仅限于当前表达式,绑定到右值引用会延长纯右值的生命周期,如:
    • 字面量(除了字符串字面量),100;
    • 算数表达式的结果,a+b;
    • 函数返回非引用类型,int add(int x, int y) { return x + y; };
    • lambda表达式,[](){ return 42; };
    • this指针;
100; 
int a,b;
int c = a + b; //隐式转换为右值
int add(int x, int y) { return x + y; } //函数返回的是值
string getName() { return "Alice"; } //函数返回临时对象
[](){ return 42; } 
this; //在成员函数中,this是纯右值
  • 将亡值 Expiring Value,是有身份(有明确内存地址)但即将结束生命周期(资源可被窃取);
    • 函数返回的局部对象;
    • 通常由 std::move 或 static_cast<T&&> 产生;
      • 返回类型为右值引用的函数调用表达式是 xvalue(将亡值),如std::move;
      • 转换为右值引用的类型转换表达式是 xvalue(将亡值),如static_cast<T&&>;
//函数返回的局部对象
string createString() {
    string local = "Hello";
    return local;  // 返回时,local变成将亡值
}

string str = "Hello";
string new_str = std::move(str);
string&& rref = static_cast<string&&>(str);

注:三个隐式自动转换

  • 左值转换为右值,如i+3;
  • 数组名为常量左值,在表达式中会转换为首元素地址;
  • 函数名为常量左值,在表达式中转换为函数地址;

二,右值引用

        C++98提出了引用的概念,引用即别名,引用变量与其引用的实体公共同一块空间,且引用的底层是通过指针来实现的,使用引用可提高程序的可读性;通常说的引用指的是左值引用(T&);

void swap(int& left, int& right)
{
	int tmp = left;
	left = right;
	right = tmp;
}

        为了提高程序的运行效率,C++11引入了右值引用(T&&),右值引用也是别名,但其只能对右值引用;

  • 右值引用也必须立即进行初始化操作;
  • 且只能使用右值进行初始化;
  • 可延长生命周期并修改;
    • 直接绑定到临时值;
    • 直接绑定到函数值返回;
    • 不能绑定到函数int&&返回;
int&& a = 1; //对右值进行引用
a = 10; //还可对右值引用进行修改
const int&& b = 1; //常量右值引用,无实际用处
//把返回值x存储在临时空间,int tmp = x;
int fun1(int x) { return x; } 
//把指向返回值x的地址存储在临时空间,会释放悬空,int& tmp = x;
int& fun2(int x) { return x; } 
//把指向返回值x+1的地址存储在临时空间,会释放悬空,int&& tmp = x+1;
int&& fun3(int x) { return x + 1; } 

int main() {
	int a1 = fun1(10); //将临时空间值存入a1
    //int&& a1 = fun1(10); //ok,可延长生命周期
	int a2 = fun2(10); //读取临时空间指向的值存入a2
	int a3 = fun3(10); //读取临时空间指向的值存入a3
    //int&& a3 = fun3(10); //不ok,不可延长生命周期	
}

引用与右值引用比较

  • T& 只能绑定左值,给对象起别名,作为函数参数可修改传入对象;
  • const T& 即可绑定左值也可绑定右值,只读访问;
  • T&& 只能绑定右值,实现移动语义和完美转发;

//普通类型只能引用左值,不能引用右值
int a = 10;
int& ra = a;
//int& rb = 10; 编译失败,10是右值

//常量左值引用,即可引用左值也可引用右值
const int& rc = a;
const int& rb = 10;
//右值引用只能引用右值,一般不能引用左值
int&& rd = 10;
//int&& re = a; 编译失败,a是左值
//int&& re = rd; 编译失败,rd是左值
//以下函数均可传入右值,int&& value会更优先因为更精确
void process(const int& value)
void process(int&& value) 

以值的形式返回对象的缺陷

        如一个类中涉及到资源管理,需显式提供拷贝构造、赋值运算符重载以及析构函数,否则拷贝对象或对象之间赋值就会出错(浅拷贝);

class String
{
public:
	String(const char* str = "")
	{
		if (nullptr == str)
			str = "";
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	String(const String& s)
		:_str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}

	String& operator=(const String& s)
	{
		if (this != &s)
		{
			char* tmp = new char[strlen(s._str) + 1];
			strcpy(tmp, s._str);
			delete[] _str;
			_str = tmp;
		}
		return *this;
	}

	String operator+(const String& s)
	{
		char* tmp = new char[strlen(_str) + strlen(s._str) + 1];
		strcpy(tmp, _str);
		strcpy(tmp + strlen(_str), s._str);
		String strRet(tmp);
		return strRet;
	}

	~String() { delete[] _str; }
private:
	char* _str;
};

int main()
{
	String s1("hello");
	String s2("world");
	String s3(s1 + s2);
	return 0;
}

上述代码s1+s2调用operator+中,返回的是strRet值(将完值),s3创建过程为:

  • 创建一个临时对象接收然后strRet值,调用拷贝构造,String Tmp = strRet;
    • strRet出作用域将销毁;
  • 然后使用临时对象来构造s3,调用拷贝构造,String s3(Tmp);
    • 最后在销毁此临时对象Tmp;

        在这个过程中,strRet、Tmp,s3,都有自己独立的空间,相当于创建了三个内容完全相同的对象,浪费空间,程序效率低下,且临时对象作用不大;

右值引用和右值的区别

右值引用是类型,右值是值类别;

// a是一个左值,其类型是“对int的右值引用”
// 可理解为将一个字面量纯右值1生命周期延长,并给延长的对象起名为a
int&& a = 1;        

// 告知编译器将a作为右值处理,表达式结果为将完值
// 实际即为std::move函数的实现,等价于std::move(a)
// 核心意义是:启用移动语义
static_cast<int&&>(a); // 将一个左值a强制转换为右值

三,移动语义

         C++11新增的特性,以提高对象传递和拷贝时的效率;即通过将资源所有权从一个对象转移到另一个对象,来避免不必要的内存分配和数据复制;具体表现为,通过“右值引用”将移动构造或移动赋值运算符设置为优先于常规的拷贝构造或拷贝赋值运算符;

  • 即将一个对象中资源移动到另一个对象中的方式;
  • C++11中如需实现移动语义,必须使用右值引用;
class A
{
public:
	A(int a) :_a(a) { cout << "A(int a)._a=" << _a << endl; } //构造,注意A(int&& a)
	A(A& a) :_a(a._a) { cout << "A(A& a)._a=" << _a << endl; } //拷贝构造
	A& operator=(const A& a) { _a = a._a; return *this; } //赋值重载

	A(A&& a)noexcept :_a(a._a) { cout << "A(A&& a)._a=" << _a << endl; } //移动构造
	A& operator=(A&& a)noexcept { _a = a._a; return *this; } //移动赋值重载
private:
	int _a;
};

int main()
{
	A a1(1), a2(2); //调用 A(int a)
	A a3(a1); //调用 A(A& a)
	a3 = a2; //调用 A& operator=(const A& a)

	A a4(move(a1)); //调用 A(A&& a)
	a4 = move(a2); //调用 A& operator=(A&& a)
	return 0;
}

上述代码s1+s2调用operator+中,引入移动构造,将strRet中资源转移到临时对象中;

String(String&& s)
	:_str(s._str)
{
	s._str = nullptr;
}

引入移动构造后,s3创建过程为:

  • 创建一个临时对象接收然后strRet值,调用移动构造,String Tmp = strRet;
    • 将strRet中资源转移到临时对象中,strRet出作用域将销毁;
  • 然后使用临时对象来构造s3,调用移动构造,String s3(Tmp);
    • 将临时对象中资源转移到s3中,最后在销毁此临时对象Tmp;

整个过程只需创建一块堆内存即可,节省空间也提供运行效率;

    注:

    • 移动构造函数的参数,不要设置成const类型的右值引用,因为资源无法转移而导致移动语义失效;
    • 在C++11中如都没有显式创建拷贝构造、拷贝赋值、移动构造、移动赋值、析构函数,编译器会为类默认生成,但为浅拷贝,因此当类中涉及到资源管理时需显式定义移动构造;

    move函数

            按照语法右值引用只能引用右值,但有些场景可能需要用右值去引用左值实现移动语义;当需要用右值引用引用左值时,可通过move函数将左值转化为右值;移动语义接管资源后,被移动的对象(源对象)必须处于一个有效但未指定的状态;

    • 内置类型没有资源需要转移,移动=拷贝;
    • 自定义类型有资源要转移,需显式实现移动语义,标准库类型已实现;

    • 辅助函数,其唯一的功能就是将一个左值强制转化为右值引用,以实现移动语义;
    • 标准库的许多组件实现了移动语义,允许在参数为右值时直接转移对象的资产和属性的所有权,而无需复制,如string,vector等;
    • 注意,在标准库中,被移出的对象处于有效但未指定的状态;在操作后,被移出的对象应被销毁或分配一个新值;否则访问会产生一个未指定的值;
    • 被转化的左值,其生命周期并没有随左值的转化而改变,即std::move转化的左值变量不会被销毁;
    • STL中也有另一个move函数,将一个范围的元素搬移到另一个位置;
    //返回值
    static_cast<remove_reference<decltype(arg)>::type&&>(arg)
    template<class _Ty>
    inline typename remove_reference<_ty>::type&& move(_Ty&& _Arg) _NOEXCEPT
    {
        return ((typename remove_reference<_Ty>::type&&)_Arg);
    }
    int main()
    {
    	int a = 1;
    	int aa = move(a); 
    
    	string s = "abcd";
    	string ss = move(s); //实现移动语义,资源已转移,s已为空;
    
    	vector<int> v = { 1,2,3,4 };
    	vector<int> vv = move(v); //实现移动语义,资源已转移,v已为空;
        
        //std::move(str)是将亡值,但变量b是左值
        string&& b = std::move(str);  
    	return 0;
    }

    move函数的经典误用:

    String s1("hello world");
    String s2(move(s1));
    String s3(s2);
    

            move将s1转化为右值后,在实现s2的拷贝时会使用移动构造,此时s1的资源就被转移到s2中了,s1就会成为无效字符串;

    四,完美转发

            以下PerfectForword为转发的模板函数,Func为实际目标函数,但转发不算完美;完美转发是将参数按传递给PerfectForword函数的实际类型转发给目标函数,而不产生额外开销,就像不存在转发者一样;

    void Func(int x){cout << x << endl;}
    
    template<typename T>
    void PerfectForward(T t)
    {
        //目标函数
        Func(t);
    }

    完美转发是指在函数模板中,完全依照模板的参数类型,将参数传递给函数模板中调用的另一个函数,同时保持其值类别(lvalue或rvalue)和类型不变;

    所谓完美,即模板函数在向其他函数传递自身形参时:

    • 如相应实参是左值,就应被转发为左值;如相应实参是右值,就应该被转发为右值;
    • 为保留对转发而来的参数的左右值属性进行不同处理;
      • 如参数为左值时拷贝语义,参数为右值移动语义;

    通用引用,即可绑定左值也可绑定右值;

    • 如果传入左值结果为左值引用,T 推导为 T&,T&& 折叠为 T&;

    • 如果传入右值结果为右值引用,T 推导为 T,T&& 保持 T&&;

    // 右值引用 - 只能绑定到右值
    void process(string&& str) {}  // 明确的右值引用
    
    // 通用引用 - 可以绑定到左值和右值
    template<typename T>
    void PerfectForward(T&& t) {}  // 可能是左值引用或右值引用

    引用折叠规则

    • T& & 折叠为 T&
    • T& && 折叠为 T&
    • T&& & 折叠为 T&
    • T&& && 折叠为 T&&
    template<typename T>
    void func(T&& param) //这里会发生引用折叠
    {
        // 检查 T 的具体类型
        if constexpr (std::is_same_v<T, int>)
            { std::cout << "T 被推导为: int" << std::endl; }
        else if constexpr (std::is_same_v<T, int&>)
            { std::cout << "T 被推导为: int&" << std::endl; }
        else if constexpr (std::is_same_v<T, const int&>)
            { std::cout << "T 被推导为: const int&" << std::endl; }
    
        // 检查最终参数类型
        if constexpr (std::is_same_v<decltype(param), int&>) 
            { std::cout << "param 类型: int&" << std::endl; }
        else if constexpr (std::is_same_v<decltype(param), const int&>)
            { std::cout << "param 类型: const int&" << std::endl; }
        else if constexpr (std::is_same_v<decltype(param), int&&>) 
            { std::cout << "param 类型: int&&" << std::endl; }
        std::cout << std::endl;
    }
    
    int main() {
        int x = 10;
        const int cx = 20;
    
        func(x);
        func(cx);
        func(30);
    }
    调用实参类型实参值类别T推导结果T&&类型引用折叠过程最终param类型原因
    func(x)int左值int&int& &&& + && → &int&必须保持左值性
    func(cx)const int左值const int&const int& &&& + && → &const int&必须保持左值性和常量性
    func(30)int右值intint&&无折叠int&&普通类型就足够匹配右值

    forward函数

    • 如arg不是左值引用,则返回arg的右值引用;
    • 如arg是左值引用,则返回arg(不修改其类型);
    • 辅助函数,将右值引用完美转发到其他函数;
      • 因为所有有名字的引用变量本身都是左值,即使是右值引用;
      • 右值引用类型不等于是右值;
    • 任何实例化都必须显式指定T的类型(任何隐式推断的T都不匹配);
    //均返回
    static_cast<decltype(arg)&&>(arg)
    //C++11通过forward函数来实现完美转发!
    void Fun(int& x) { cout << "int& -> lvalue ref" << endl; }
    void Fun(int&& x) { cout << "int&& -> rvalue ref" << endl; }
    void Fun(const int& x) { cout << "const int& -> lvalue ref" << endl; }
    void Fun(const int&& x) { cout << "const int&& -> rvalue ref" << endl; }
    
    template<typename T>
    void PerfectForward(T&& t) { //万能引用,即可传递左值也可传递右值
    	Fun(std::forward<T>(t));
    }
    
    int main() {
    	PerfectForward(10); //10是右值,int&& -> rvalue ref
    
    	int a;
    	PerfectForward(a); //a是左值,int& -> lvalue ref
    	PerfectForward(std::move(a)); //将a转化为右值 int&& -> rvalue ref
    
    	const int b = 8;
    	PerfectForward(b); //b是const左值 const int& -> lvalue ref
    	PerfectForward(std::move(b)); //将b转化为const右值 const int&& -> rvalue ref
    	return 0;
    }
    // PerfectForward(10); 此语句推导过程:
    1,依据传递的实参10为字面量右值,根据引用折叠规则
        推导模板函数void PerfectForward(T&& t)的 T 类型为 int
        // 模板实例化为:
        void PerfectForward(int&& t) {
            Fun(std::forward<int>(t));
        }
    
    2,int&& t变量t为右值引用类型,值类别为左值
        std::forward<int>(t)已显式指定类型为int
        static_cast<decltype(arg)&&>(arg)
      -> static_cast<int&&>(t)
      -> 表明将左值t转化为右值

    右值引用作用

    C++98中引用作用,因为引用是别名,需要用指针操作的地方,可以使用引用来替代,可提高代码的可读性及安全性;

    C++11中右值引用主要有以下作用:

    • 给中间临时变量取别名;
    • 实现移动语义(移动构造或移动赋值);
    • 实现完美转发,通过万能引用和引用折叠机制实现的;

    【C++】右值引用详解(移动构造、移动赋值、万能引用和完美转发、关键字default和delete) 右值引用总结 阅读详情

    相关推荐

    C++ 左值、右值、左值引用、右值引用

    本文介绍C++11的各种引用的概念,理解清楚各种引用的概念,非常有助于理解基于c11引用的各种操作。

    baiiu 1205

    详解—C++右值引用

    而临时对象也是右值,因此在用临时对象构造s3时,也采用移动构造,将临时对象中资源转移到s3中,整个过程,只需要创建一块堆内存即可,既省了空间,又大大提高程序运行的效率。2. const修饰的常量,不可修改,只读类型的,理论应该按照右值对待,但因为其可以取地址(如果只是const类型常量的定义,编译器不给其开辟空间,如果对该常量取地址时,编译器才为其开辟空间),C++11认为其是左值。C++98中引用作用:因为引用是一个别名,需要用指针操作的地方,可以使用指针来代替,可以提高代码的可读性以及安全性。

    weixin_55582891的博客 5263

    C++11 新特性 ② | 左值、左值引用、右值与右值引用

    详细讲述左值、左值引用、右值与右值引用相关概念。

    dvlinker的技术专栏 1万+

    C++11特性——右值引用

    首先介绍下左右值(我发现自己学了好长时间都没有对两者进行区分~)对于左值、右值可以简单的以放在等号左右为区分,等号左边的是左值,等号右边的是右值。再来详细的介绍下各自的特点:左值:1)左值可以取地址2)左值可以修改3)左值可以放在等号左右两边右值:1)右值不可以取地址2)右值不可以直接修改3)右值只能放在等号右边4)右值往往是没有名称的再来举几个实例:左值举例:int a;int a = 3;上面的a都是左值纯右值、将亡值。...

    gls_nuaa的博客 7040

    风力发电机并网模型建立及仿真验证

    传统能源日益匮乏,环境污染日趋严重,全球向安全、可靠和环保的可持续能源体系转型迫在眉睫,风电迎来了重要的发展契机。近年来,全球风电迅猛发展,我国已成为世界风电新增装机容量第一的国家。然而,随着风电规模的不断增大,风电场接入对系统影响不容忽视。随着变速恒频风力发电系统优越的性能突出和大容量电力电子技术的成熟,风速随机性引起的功率波动及故障情况下的动态响应,对电能质量,系统电压、频率的稳定性产生的影响需要深入研究。因而,本文结合实际项目,针对变速恒频风力发电系统建模,端口动态特性及对电网电能质量、运行稳定性的影

    毕业设计区博客 1638

    将AD域服务从windows server 2008 R2 迁移到windows server 2019

    添加一台windows 2019 的服务器并加入现有林的域中,并将角色升级为域控制器。然后迁移FSMO角色,使其成为PDC,然后降级旧DC,并提升域和林的功能级别。最后还要说下,Server 2008 R2我们还可以删除角色并退出当前域,这里就不做操作了。2)右键 mingling.com(我的域为mingling.com)--提升域级别功能。勾选 将域控制器添加到现有域,使用域管理员将DC2加入到现有的AD域。1)打开服务器管理器---工具---AD域和信任关系。2)运行域安装服务向导,选择下一步。

    lionxam的博客 3659

    右值引用及其作用

    什么是左值、右值? 可以出现在=号左边的则为左值,否则为右值。可以出现在=左边,意味着一定能保存数据,存放在内存中,有实际的内存地址,而右值则是一个临时中间存放的数据,是存放在寄存器中的。 inta = 9, b = 8; a = 8, b = 0; // a,b为左值 // a + 4 = 5; // 错误 a + 4为右值,a + 4为一个临时对象 // -a = 4; // 错误 -a为右值,为一个临时对象 (a) = 5; ...

    caojianfa969的博客 1万+

    物联网技术-第2章-物联网技术架构

    • 物联网具有很强的异构性• 为实现异构设备之间的互联、互通与互操作,物联网需要以一个开放的分层的可扩展的为框架。

    m0_73804764的博客 2976

    【C++进阶】C++11的新特性—右值引用和移动语义

    本文介绍了C++中左值和右值的概念及区别,重点讲解了左值引用和右值引用的语法特性与应用场景。文章首先通过示例代码区分了左值(可寻址)和右值(不可寻址),然后详细分析了引用类型对参数匹配的影响。特别强调了右值引用的设计意义:通过move语义延长临时对象生命周期并支持修改,同时解释了右值引用变量在表达式中具有左值属性的特殊设计。最后指出引用折叠等更深入的内容将在后续探讨。全文通过代码示例和图示帮助理解这些关键概念及其底层实现原理。

    Linux、C++、图形软件开发等。不一定每次都能写出完美的代码,但会认真搞懂每一个问题。 1283

    脑机接口(BCI)从原理到开发实战 09|SSVEP应用:通过视觉刺激控制设备

    本文介绍了稳态视觉诱发电位(SSVEP)脑机接口技术。SSVEP是一种高效的非侵入式BCI范式,当用户注视特定频率闪烁的视觉刺激时,大脑枕叶会产生对应的节律性响应。文章详细阐述了SSVEP的神经机制、刺激范式设计、数据预处理方法,重点讲解了典型相关分析(CCA)这一核心识别算法。相比运动想象和P300范式,SSVEP具有信息传输率高(60-100 bits/min)、信号稳定、无需训练等优势,在高速拼写、设备控制等领域应用广泛。文章还提供了完整的电极选择、滤波、分段等预处理流程,以及CCA和滤波器组CCA的

    小明的博客 1350

    Mixly 数码管时钟

      本文是米思齐数码管图形化编程实验总结分享,走过路过的来看看吧,其中的不足望指出。 一、实验目的及要求 【实验一】实现滚动显示自定义字符串。 【实验二】实现显示自定义时间。 【实验三】实现显示秒表。 二、实验原理与内容 实现米思齐的数码管图形化编程。 三、实验软硬件环境 硬件:Arduino、TM1637数码管 软件:Mixly IDE 四、核心代码及实验效果如下所示 1.实现滚动显示...

    weixin_44614199的博客 1647

    C++进阶—C++11新特性(移动语义&&右值引用&&可变参数模板&&lambda表达式&&function包装器&&bind函数)

    在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了 C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞 进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。

    IfYouHave的博客 1254

    智能座舱架构与芯片- (10) 音频篇 下

    若将有限个 量化样值的绝对值从小到大依次排列,并对应地依次赋予一个十进制数字代码(例如,赋予样值0的十进制数字代码为0),在码前以“+”、“-”号为前缀,来 区分样值的正、负,则量化后的抽样信号就转化为按抽样时序排列的一串十进制数字码流,即十进制数字信号。如果声学密封不牢,来自内部结构的噪声可能到达传感器,两个传感器之间的泄漏可能降低BF算法的性能。未来,随着汽车电动化的普及,传统的ANC降噪所针对的发动机噪音已经不复存在,而路噪问题将越发明显,因此,全新的RNC主动路噪消减技术将会有一个更为宽广的市场。

    joanna_xiao的博客 3838

    c++ 右值引用和完美转发(转)

    C++11的右值引用 如下主要讲了引用折叠,但是注意,文章中有不少错误 https://blog.youkuaiyun.com/u014351125/article/details/84502427

    silver9886的专栏 204

    【C语言趣味教程】(0) 专栏介绍

    这是一套C 语言趣味教学专栏,目前正在火热连载中,欢迎猛戳订阅!本专栏保证篇篇精品,继续保持本人一贯的幽默式写作风格,当然,在有趣的同时也同样会保证文章的质量,旨在能够产出"有趣的干货" !本系列教程不管是零基础还是有基础的读者都可以阅读,可以先看看目录!标题前带星号 (*) 的部分不建议初学者阅读,因为内容难免会超出当前章节的知识点,面向的是对 C 语言有一定基础或已经学过

    有道无术, 术尚可求。有术无道, 止于术。 2万+

    斗鱼直播间弹幕爬虫实战:WebSocket连接与实时数据采集

    在数据驱动的时代,直播平台的弹幕数据蕴含着巨大的价值——用户行为分析、舆情监控、弹幕情感分析、直播热度评估等应用场景层出不穷。斗鱼作为国内领先的直播平台,其弹幕系统基于WebSocket协议实现实时双向通信。本文将带您从零开始,使用Python构建一个完整的斗鱼直播间弹幕爬虫系统。

    2201_76125261的博客 135

    详解 C++ 左值、右值、左值引用以及右值引用

    主要讲解了 C++11 的右值引用(及其支持的移动语义和完美转发)。

    Butayarou的博客 2万+

    计算机控制技术及应用

    《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

    C++11 左值、右值、右值引用详解

    左值、右值在C++11中所有的值必属于左值、右值两者之一,右值又可以细分为纯右值、将亡值。在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值(将亡值或纯右值)。

    Hyman's Blog 4万+

    C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

    基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

    数学建模模型总结

    这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

    【C++11】右值引用

    C++11右值引用

    A.的博客 2013

    Devexpress16.2.6破解工具

    Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

    【C++】C++11新特性—右值引用,来看看怎么个事儿

    传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以从现在开始我们之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名。

    小羊的博客 4262

    【C++】C++11右值引用

    今天我们正式进入C++11的学习,C++11引入的一个非常重要的语法就是右值引用,在C++11之前的C++版本我们所提的引用都是左值引用,那么右值引用与左值引用又有什么区别呢?什么是左值?什么是右值?右值引用的价值体现在哪里?那么接下来我们就来学习有关右值引用的相关知识。

    ℉f的博客 2247

    《C++进阶之C++11》【列表初始化 + 右值引用】

    本文摘要: 文章介绍了C++11引入的列表初始化和右值引用两大特性。文中通过代码示例展示了列表初始化在数组、结构体和容器中的实际应用,并对比了C++98与C++11的初始化差异。这些特性显著提升了C++代码的简洁性和性能,是现代化C++编程的重要基础。

    序属秋秋秋的博客 1728

    C++11——右值引用

    前言 在C++98中也有一个引用,为左值引用,但是左值引用有一些不足。而C++11的右值引用的提出弥补了左值引用的不足。 左值引用和右值引用都是别名。 说明:下面说引用都代表C++98的左值引用。 一.右值引用的概念 右值引用也是一块空间的别名。只能对右值进行引用。使用是在类型后面加两个&&。 #include<iostream> using namespace std; int Add(int x,...

    weixin_57023347的博客 9488

    【C++】C++11语法之右值引用

    关于C++11新语法的一些理解以及对其中右值引用的使用的讲解。

    jhao的博客 5609

    左值引用和右值引用

    1.左值和右值 在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值(将亡值或纯右值)。 举个例子,int a = b+c, a 就是左值,其有变量名为a,通过&a可以获取该变量的地址;表达式b+c、函数int func()的返回值是右值,在其被赋值给某一变量前,我们不能通过变量名找到它,&(b+c)这样的操作则不会通过编译。 左值是可以放在赋值号左边可以被赋值的值;左值必须要在内存中有实体; 右值当在赋值号右边取出值赋给其他变量的值;右值可以在内存也可以在CPU寄存

    qq_41181857的博客 8896

    【C++学习】C++11——新特性 | 右值引用 | 完美转发

    介绍了C++11的一些新特性,如列表初始化,以及一些语法糖,最重要的是介绍了右值引用的原理及意义,以及应用场景,从而引出的移动构造和移动赋值函数,还介绍了完美转发,万能引用等内容,以及几个新的关键字。

    weixin_63726869的博客 2058
    上一篇: C++进阶 —— lambda表达式(C++11新特性)
    下一篇: C++进阶 —— 其他(C++11新特性)
    挨代码
    博客等级 码龄5年 1696粉丝 384原创
    评论
    成就一亿技术人!
    拼手气红包6.0元
    还能输入1000个字符
     
     条评论被折叠 查看
    添加红包

    请填写红包祝福语或标题

    个

    红包个数最小为10个

    元

    红包金额最低5元

    当前余额3.43元 前往充值 >
    需支付:10.00元
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付元
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值