3.1左值与右值 左值是⼀个表⽰数据的表达式(如变量名或解引⽤的指针),⼀般是有持久状态,存储在内存中,我 们可以获取它的地址,左值可以出现赋值符号的左边,也可以出现在赋值符号右边。...需要注意的是变量表达式都是左值属性,也就意味着⼀个右值被右值引⽤绑定后,右值引⽤变量变 量表达式的属性是左值 语法层⾯看,左值引⽤和右值引⽤都是取别名,不开空间。...右值引⽤变量在⽤于表达式时属性是左值 # include using namespace std; void f ( int & x) {...但是结合我们在3.2章节的讲解,变量表达式都是左值属性,也就意味着⼀个右值被右值引⽤绑定 后,右值引⽤变量表达式的属性是左值,也就是说Function函数中t的属性是左值,那么我们把t传 递给下...,否则编译时包扩展后右值引⽤变量表达式就变成了左 值。
这个初始化列表对象会隐式地进行类型转换,构造出一个std::vector对象,然后通过拷贝构造函数将这个std::vector对象赋值给变量v。...左值引用就是给左值的引用,给左值取别名 右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,...std::forward 接受一个参数和参数的类型,并根据参数的值类别(左值或右值)进行转发。...当传递左值时,std::forward 将返回左值引用;当传递右值时,std::forward 将返回右值引用。...()和insert emplace_back() 是 C++ 容器类(如 std::vector, std::deque, std::list 等)提供的一个成员函数,用于在容器的末尾直接构造一个新元素
3.1 左值和右值 左值是⼀个表⽰数据的表达式(如变量名或解引⽤的指针),⼀般是有持久状态,存储在内存中,我 们可以获取它的地址,左值可以出现赋值符号的左边,也可以出现在赋值符号右边。...需要注意的是变量表达式都是左值属性,也就意味着⼀个右值被右值引⽤绑定后,右值引⽤变量变 量表达式的属性是左值 语法层⾯看,左值引⽤和右值引⽤都是取别名,不开空间。...右值引⽤变量在⽤于表达式时属性是左值,这个设计这⾥会感觉跟怪,下⼀⼩节我们讲右值引⽤的 使⽤场景时,就能体会这样设计的价值了 #include using namespace std...但是结合我们在5.2章节的讲解,变量表达式都是左值属性,也就意味着⼀个右值被右值引⽤绑定 后,右值引⽤变量表达式的属性是左值,也就是说Function函数中t的属性是左值,那么我们把t传 递给下⼀层函数...传递参数包过程中,如果是 Args&&... args 的参数包,要⽤完美转发参数包,⽅式如下 std::forward(args)... ,否则编译时包扩展后右值引⽤变量表达式就变成了左值。
为了解决上述性能问题,自C++11起,std::vector中引入了一个新的成员函数emplace_back(),只需要将构造对象所需要的参数传入emplace_back(),该函数会自动创建对象并将其添加到...示例如下: template void fun(std::vector&& t); // t是左值引用 显然,在调用f时会执行类型推导,但是参数t的类型声明的形式并非T &...我们之前强调过,万能引用必须是T &&才行,因此,t是一个右值引用,如果尝试将左值传入,编译器将会报错: std::vector v; fun(v); // 错误,不能将左值绑定到右值 形如const...相比之下,std::vector中的emplace_back成员函数则确实触发了类型推导: template> // still...结合前面引用折叠(reference collapsing),当接收一个左值作为参数时,std::forward()返回左值引用,相应的,当接收一个右值作为参数时,std::forward()返回右值引用
因此可以指向右值,这也是为什么要使用 const & 作为函数参数的原因之一,如 std::vector 的 push_back 。...所以,单纯的std::move(xxx)不会有性能提升。同样的,右值引用能指向右值,本质上也是把右值提升为一个左值,并定义一个右值引用通过std::move指向该左值。...从表达式 int &&ref = std::move(a) 来看,右值引用 ref 指向的必须是右值,所以move返回的 int && 是个右值。所以右值引用既可能是左值,又可能是右值吗?...将左值转为右值std::vector vec; vec.push_back(MyString("World")); // Move Constructor is called!...c++11可以用emplace_back代替push_back,emplace_back可以直接在vector中构建一个对象,而非创建一个临时对象,再放进vector,再销毁。
一.可变参数模板的首次登场 #include #includevector> using namespace std; //Args是一个模板参数包,args是一个函数形参参数包...Args> void ShowList(Args... args) { //逗号表达式:结果为后面的值,通过可变参数列表展开并推演个数,进行实例化调用上面的函数。...PrintArg带有返回值的方式,因为数组里面初始化必须有值,除了逗号表达式就是这种方式,相比前者,这种更直观。...三.容器的emplace方法 对于各种容器的emplace、emplace_back方法,由于是c++11新出的方法,参数无论是右值还是左值,都存在一个可变参数列表为函数的重载函数,其功能与push、push_back...当然,emplace_back也可以直接传对象。 ---- 这就可以看出,为什么通过emplace_back()更快,如果没有实现移动构造,那么这两个的差别就会非常的大。
右值引用 分类 在古老的标准里,C++中的变量分为左值(lvalue)与右值(rvalue)这两种,左值就是能够用&获得地址的值,可以对他进行修改,右值就是不能用&获得地址的值,通常只是临时变量,不能进行修改...这样我们就可以像使用左值一样的使用这个右值了。 那么现在就应该清楚了,右值引用就是通过对右值进行引用使得我们能够保存这个右值的生命周期,并像使用左值一样的使用右值的方法。...为了使左值的移动能够使用移动构造,我们就有了std::move这个东西,他的作用很简单,就是把左值变成右值引用。...答案是当然有,这就是std::emplace_back方法。...move destroy destroy emplace_back int main(){ std::vectorv; v.emplace_back(); } 输出: construct
一个 lvalue 是通常可以放在等号左边的表达式,左值 一个 rvalue 是通常只能放在等号右边的表达式,右值 一个 glvalue 是 generalized lvalue,广义左值 一个 xvalue...对比下 std::vector 的emplace_back,它看起来是这样的: template > class vector...函数的模板参数 Args 和类的模板参数T无关,所以即使我知道这个类具体是什么,比如说,std::vector,但我们还是不知道emplace_back的参数类型是什么。...我们看下在类std::vector外面声明的 emplace_back会更清楚的表明这一点 (我会继续忽略 Allocator 参数): template void std::vector::emplace_back(Args&&... args); 6.表达式的左右值性与类型无关 “值类别”(value category)和
一句话概述 std::move本身只做类型转换,对性能无影响。 我们可以在自己的类中实现移动语义,避免深拷贝,充分利用右值引用和std::move的语言特性。...可以发现左值引用真是用的很不爽,右值引用的出现解决了这个问题,在STL的很多容器中,都实现了以右值引用为参数的移动构造函数和移动赋值重载函数,或者其他函数,最常见的如std::vector的push_back...参数为左值引用意味着拷贝,为右值引用意味着移动。...::push_back使用std::move提高性能 // 例2:std::vector和std::string的实际例子 int main() { std::string str1 = "aacasxs...emplace_back效果相同,str1会失去原有值 vec.emplace_back("axcsddcas"); // 当然可以直接接右值 } // std::vector方法定义 void
左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。...右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。...但是右值引用可以move以后的左值。 #include using namespace std; int main() { // 左值引用只能引用左值,不能引用右值。...这里用vector举例:如果传进去的是右值,就会走这个接口,会提升效率。 **注意:**右值引用被引用一次之后,引用的这个别名就变成了左值。 如果不变成左值怎么传给swap。...STL容器中的empalce相关接口函数 http://www.cplusplus.com/reference/vector/vector/emplace_back/ emplace_back
实际上C++11更新后,容器中增加的新方法最后用的插入接口函数的右值引用版本: https://cplusplus.com/reference/vector/vector/emplace_back/...左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。...什么是右值引用? 右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。...int&& r2 = a; // 右值引用可以引用move以后的左值 int&& r3 = std::move(a); return 0; } 7.3 右值引用使用场景和意义 前面我们可以看到左值引用既可以引用左值和又可以引用右值.../reference/string/string/string/ http://www.cplusplus.com/reference/vector/vector/vector/ 7.4 右值引用引用左值及其一些更深入的使用场景分析
> class vector : protected _Vector_base { } C++11后,vector的push_back方法通过调用emplace_back...方法实现,实现源码为: void push_back(value_type&& __x) { emplace_back(std::move(__x)); } #if __cplusplus...__args); 在C++11后,推荐大家使用emplace_back或者empalce插入数据,从实现方式来说,比push_back更加高效,因为empalce使用了move减少了内存的拷贝操作。..._M_finish); _GLIBCXX_ASAN_ANNOTATE_SHRINK(1); } empalce,C++11新增方法,提升了插入元素的性能,参数传入使用右值表达式,使用完美转发保证参数类型不变...__args) { return _M_emplace_aux(__position, std::forward(__args)...); } insert,插入元素,使用右值表达式,通过
介绍两个关键词 (1) constexpr 是 C++11 中新增的关键字,其语义是 "常量表达式",也就是在编译期可求值的表达式。...最基础的常量表达式就是字面值或全局变量/函数的地址或 sizeof 等关键字返回的结果,而其它常量表达式都是由基础表达式通过各种确定的运算得到的。...如果的 vector 值为空,则返回的迭代器将等于 end()。 ...of a 'vector' is 9223372036854775807s reserve() 将 vector 的容量增加到大于或等于的值 new_cap。 ...如果当前大小小于 count,需要附加额外的拷贝值 value。
左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。...什么是右值引用? 右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。...// 右值引用可以引用move以后的左值 int&& r3 = std::move(a); return 0; } 5.3 右值引用的使用场景和意义 前面我们可以看到左值引用既可以引用左值和又可以引用右值...这种就地展开参数包的方式实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。...int main() { std::liststd::pair > mylist; // emplace_back支持可变参数,拿到构建pair对象的参数后自己去创建对象
ret).name() << endl; cout << typeid(p).name() << endl; // vector存储的类型跟x*y表达式返回值类型一致 // decltype推导表达式类型...,用这个类型实例化模板参数或者定义对象 vector v; return 0; } decltype和表达式的返回结果密切相关,即返回表达式结果对应的类型。...实际上C++11更新后,容器中增加的新方法最后用的插入接口函数的右值引用版本: https://cplusplus.com/reference/vector/vector/emplace_back/ https...(2)右值:也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等 右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址..._y << endl; } 总的来说就是emplace_back和push_back 在处理已经构建好的对象时,是没有差异的,因为无论是左值还是右值,push_back都有对应的版本。
左值是⼀个表⽰数据的表达式(如变量名或解引⽤的指针),⼀般是有持久状态,存储在内存中,我们可以获取它的地址,左值可以出现赋值符号的左边,也可以出现在赋值符号右边 定义时const修饰符后的左值,不能给他赋值...需要注意的是变量表达式都是左值属性,也就意味着⼀个右值被右值引⽤绑定后,右值引⽤变量变量表达式的属性是左值 左值引用的属性是左值,右值引用的属性也是左值 // b、r1、rr1都是变量表达式,都是左值...右值引⽤变量在⽤于表达式时属性是左值 之所以这样设计是因为右值本身不能被修改,但是右值被右值引⽤之后本身的属性变成了左值之后就可以修改了,因为只有左值才能修改 // 右值引⽤变量在⽤于表达式时是左值...结合5.2章节来看,变量表达式都是左值属性,也就意味着⼀个右值被右值引⽤绑定后,右值引⽤变量表达式的属性是左值,也就是说Function函数中t的属性是左值,那么我们把t传递给下⼀层函数Fun,那么匹配的都是左值引...,否则编译时包扩展后右值引⽤变量表达式就变成了左值 push_back和emplace_back的区别:如果只是当前对象的左值和右值的插入,那他们就是一样的 如果要将一个临时变量push
当可变参数包被展开到只剩一个参数时,调用这个函数来处理最后一个参数,并打印出它的值。...ShowList(std::string("sort")) 调用终止函数,输出:sort 输出:A sort 输出:1 A sort 1 1 A 1 A sort 逗号表达式展开参数包 这种展开参数包的方式...这种就地展开参数包的方式实现的关键是逗号表达式。...Args> void emplace_back (Args&&... args); emplace_back 是 C++ 标准库容器(例如 std::vector, std::deque 等)的一个成员函数...std::vector numbers; numbers.emplace_back(3.14); // 会将 3.14 隐式转换为 int,并存储为 3 需要构造函数支持:emplace_back
::move(s1); Person s4; s4 = std::move(s2); return 0; } 类成员变量初始化 C++11允许在类定义时给成员变量初始缺省值,默认生成构造函数会使用这些缺省值初始化...这种就地展开参数包的方式 实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。...::string("sort")); return 0; } STL容器中的emplace相关接口函数: std::vector::emplace_back std::list::emplace_back...int main() { std::liststd::pair > mylist; // emplace_back支持可变参数,拿到构建pair对象的参数后自己去创建对象...fyd::string,再试试呢 // 我们会发现其实差别也不到,emplace_back是直接构造了,push_back std::liststd::pair<int, fyd::string
std的智能指针(std::unique_ptr,std::shared_ptr),使用智能指针目的之一是减少对象的拷贝:对超出作用域的对象进行释放。...多个不同的shared_ptr不仅共享同一个对象,也需要共享计数。 2.2 左值和右值 左值:有标识符、可以取地址的。反之为右值。...常见的左值有:变量、函数、成员;返回左值的表达式(++x,x=1,cout<<''),字符串常量 常见的右值有:返回右值得表达式(x++,x+1,make_shared(42)),非字符串的字面量...左值和右值首先是个值,所有对于指针,因为用值传递,不关心它是左值还是右值。 std::move(ptr)是个右值引用。等价于static_cast&&>(ptr)。...emplace_back比push_back 少额外生成临时对象,少一次拷贝构造和一次析构。 现代处理器架构对连续内存访问速度比不连续内存访问速度快很多,所以vector的连续内存是他的优点。
C++11认为其是左值 如果表达式的运行结果是一个临时变量或者对象,认为是右值 如果表达式运行结果或单个变量是一个引用则认为是左值 注意: 不能简单地通过能否放在=左侧右侧或者取地址来判断左值或者右值...,要根据表达式结果或变量的性质判断 能得到引用的表达式一定能够作为引用,即为左值,否则就用常引用,即为右值 C++11对右值进行了严格的区分: C语言中的纯右值,比如:a+b, 100 将亡值,也就是生命周期即将结束的变量...,其生命周期并没有随着左值的转化而改变,即std::move转化的左值变量lvalue不会被销毁 STL中也有另一个move函数,就是将一个范围中的元素搬移到另一个位置 示例: int main() {...,对于引用左值,本身就是左值;对于右值引用,引用后的引用变量会将引用内容储存到空间中,也就是会退化成左值,这里就存在属性的混淆 对于这种情况,C++11通过forward函数来实现完美转发 std::forward...,在底层直接调用普通构造函数生成对象 示例: int main() { //带有拷贝构造和移动构造的String std::liststd::pair >
领取专属 10元无门槛券
手把手带您无忧上云