哪个网站教做饭做的好,域名买好了怎么建网站,上海网站设计公司排行榜,网站建设十年经验个人主页点击直达#xff1a;小白不是程序媛
C系列专栏#xff1a;C干货铺
代码仓库#xff1a;Gitee 目录
左值与左值引用
右值与右值引用
左值引用和右值引用的比较 左值引用总结#xff1a;
右值引用总结#xff1a;
左值引用的作用和意义
右值引用的使用场景和…
个人主页点击直达小白不是程序媛
C系列专栏C干货铺
代码仓库Gitee 目录
左值与左值引用
右值与右值引用
左值引用和右值引用的比较 左值引用总结
右值引用总结
左值引用的作用和意义
右值引用的使用场景和意义
移动赋值和移动构造 完美转发
std::forward 完美转发在传参的过程中保留对象原生类型属性
编辑新的类功能
默认成员函数
强制生成默认函数的关键字default
禁止生成默认函数的关键字delete
继承和多态中的final与override关键字 左值与左值引用
传统的C语法中就有引用的语法而C11中新增了的右值引用语法特性所以从现在开始我们 之前学习的引用就叫做左值引用。无论左值引用还是右值引用都是给对象取别名。
什么是左值什么是左值引用 左值是一个表示数据的表达式(如变量名或解引用的指针)我们可以获取它的地址可以对它赋值左值可以出现赋值符号的左边右值不能出现在赋值符号左边。定义时const修饰符后的左值不能给他赋值但是可以取它的地址。左值引用就是给左值的引用给左值取别名。 //左值与左值引用
int main()
{//左值//可以取到地址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;
}右值与右值引用 右值也是一个表示数据的表达式如字面常量、表达式返回值函数返回值(这个不能是左值引用返回)等等右值可以出现在赋值符号的右边但是不能出现出现在赋值符号的左边右值不能取地址。右值引用就是对右值的引用给右值取别名。 //右值与右值引用
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;
} 左值引用和右值引用的比较 左值引用总结 1. 左值引用只能引用左值不能引用右值。2. 但是const左值引用既可引用左值也可引用右值。 右值引用总结 1. 右值引用只能右值不能引用左值。2. 但是右值引用可以move以后的左值。 //左值引用和右值引用的比较
int main()
{//左值引用int a 10;int ra a;//const 左值引用既可以引用左值又可以引用右值const int ra1 a;const int ra2 10;//右值引用//不可以引用左值/*int r1 a;*///使用mova后可以int r1 move(a);int r1 10;return 0;} 左值引用的作用和意义 左值引用可以做函数的参数和函数的返回值这样可以避免在函数传参和函数返回的时候去进行各种拷贝构造对于一些大对象和需要进行深拷贝的对象来说这样做可以提高效率。 左值引用的缺陷当函数返回的对象是一个局部变量时出了函数的作用域该对象就被销毁了就不能使用左值引用返回只能通过传值返回。而传值返回会导致至少调用一次拷贝构造如果是旧一点的编译器可能是调用两次构造函数。。 //MyStringstring to_string(int x){string ret;while (x){int val x % 10;x x / 10;ret (0 val);}reverse(ret.begin(), ret.end());return ret;}int main()
{bit::string s; s to_string(1234);return 0;
} 右值引用的使用场景和意义
其实右值含有两种形式 纯右值编写程序时所出现的的字面值常属于纯右值将亡值自定义类型的临时对象 右值引用的出现完全是为了解决左值引用的缺陷的 移动赋值和移动构造
还是对上面的代码进行分析 注上面的代码我们先生成一个临时对象ret函数调用结束会销毁栈帧因此ret拷贝构造在生成一个临时对象在由这个临时对象深拷贝生成String类的s。为了实例化这个对象我们进行了两次临时对象的创建在由这两个临时对象进行两次深拷贝对于很大的类时进行这样的操作是非常浪费时间和空间的由于中间产生了临时值这个临时值就是我们上面所说的将亡值而恰好临时值取不到地址是一个右值我们可以对其引用使用移动赋值。 string operator(string s)
{cout string operator(string s) -- 移动语义 endl;swap(s);return *this;
}
只需要重载一个右值引用参数类型的重载函数即可。 函数调用结束需要销毁栈帧编译器识别ret为一个临时值并且这个临时值需要拷贝在产生一个临时值return返回调用移动拷贝交换数据即可释放ret函数返回的临时值需要赋值给另外一个同类型的值编译器识别进行移动赋值交换数据释放临时值这个过程就是移动赋值及减少了临时对象的产生将亡值又减少了深拷贝。对于一些大的类来说进行连续的赋值节省了空间和时间。 移动构造和移动赋值的原理差不多这里不进行过度赘述。
注目前比较新的编译器会对连续的拷贝构造进行优化。 完美转发
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; }templatetypename 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;
}这是什么情况 模板中的不代表右值引用而是万能引用其既能接收左值又能接收右值。模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力但是引用类型的唯一作用就是限制了接收的类型后续使用中都退化成了左值我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发。 注你也可以这样理解上面的PerfectForward函数其实是左值引用和右值引用是重载的当传入左值时候重载直接调用Fun函数当传入右值时刚好符合参数进行右值引用但是右值的右值引用的属性是左值因此调用Fun函数也是左值引用。 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; }templatetypename T
void PerfectForward(T t)
{//完美转发Fun(forwardT(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;
}新的类功能
默认成员函数
原来C类中有6个默认成员函数 1. 构造函数2. 析构函数3. 拷贝构造函数4. 拷贝赋值重载5. 取地址重载6. const 取地址重载 最后重要的是前4个后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。 C11 新增了两个移动构造函数和移动赋值运算符重载。
针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下 如果你没有自己实现移动构造函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数对于内置类型成员会执行逐成员按字节拷贝自定义类型成员则需要看这个成员是否实现移动构造如果实现了就调用移动构造没有实现就调用拷贝构造。如果你没有自己实现移动赋值重载函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数对于内置类型成员会执行逐成员按字节拷贝自定义类型成员则需要看这个成员是否实现移动赋值如果实现了就调用移动赋值没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)如果你提供了移动构造或者移动赋值编译器不会自动提供拷贝构造和拷贝赋值。 强制生成默认函数的关键字default C11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数但是因为一些原因这个函数没有默认生成。比如我们提供了拷贝构造就不会生成移动构造了那么我们可以使用default关键字显示指定移动构造生成。 禁止生成默认函数的关键字delete 如果能想要限制某些默认函数的生成在C98中是该函数设置成private并且只声明补丁已这样只要其他人想要调用就会报错。在C11中更简单只需在该函数声明加上delete即可该语法指示编译器不生成对应函数的默认版本称delete修饰的函数为删除函数。 继承和多态中的final与override关键字
这个我们在继承和多态章节已经进行了详细讲解这里就不再细讲需要的话去复习继承和多态那篇文章吧。 今天给大家分享介绍了C11中的右值引用和移动构造。如果觉得文章还不错的话可以三连支持一下个人主页还有很多有趣的文章欢迎小伙伴们前去点评您的三连支持就是我前进的动力