C++——右值引用
1.绑定到一个将要销毁的右值的引用——移动
2.左值表达式——对象的身份;右值表达式——对象的值
int i=;
int& r=i; int&& rr=i;//×,左值不能绑定到右值引用
int& r2=i*;//×,右值不能绑定到左值引用 const int& r3=i*;//√,右值可以绑定const引用
int&& rr2 = i*;//右值绑定到右值引用 int&& rr1=;//√
int&& rr2=rr1;//× int&& rr3=std::move(rr1);//√,使用std可以避免潜在的命名冲突
3.左值持久,右值短暂(一般是字面常量,或表达式创建的临时对象(如上))//变量寿命很长的,出}才会被销毁
4.右值引用的对象即将被销毁且该对象没有其他用户
5.移动构造函数和移动赋值运算符
5.1 移动构造函数不分配任何新内存,直接接管给定的内存,接管后将原对象置为null
StrVec(StrVec&& s) noexcept :elements(s.elements), first_free(s.first_free), cap(s.cap)//接管s的资源
{
s.elements = s.first_free = s.cap = nullptr;//让s进入null,否则销毁s时,构造也会被销毁
}
5.2 移动赋值运算符
StrVec& operator=(StrVec&& rhs) noexcept//为何其他地方不需要?
{
if (this != &rhs)//检测自赋值
{
free();
elements = rhs.elements;
first_free = rhs.first_free;
cap = rhs.cap;
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
return *this;
}
5.3 合成移动操作:
类定义了自己的拷贝构造函数、拷贝赋值运算符或析构函数,便不会合成移动构造函数和移动赋值运算符。只有当一个类未定义任何自己版本的拷贝控制成员,且类的每个非static数据成员都可以移动时,编译器才会为其合成移动构造函数或移动赋值运算符。
struct X{
int i; //内置类型,可以移动
string s;//string有定义的移动操作
};
struct hasX{
X men;//X有合成的移动操作
};
X x,x2=std::move(x);//使用合成移动构造函数
hasX hx,hx2=std::move(hx); //使用合成移动构造函数
5.4 定义了一个移动构造函数或移动赋值运算符的类,必须定义自己的拷贝操作。否则,这些成员将是delete的
6.移动右值,拷贝左值。但若没有移动构造函数,右值也被拷贝。
7.一个类有一个可用的拷贝构造函数,没有移动构造函数,则对象是通过拷贝构造函数来“移动”的。同理,适用于拷贝赋值运算符和移动赋值运算符。
class StrVec {
public:
StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}//默认初始化
StrVec(const StrVec&);//拷贝构造
StrVec& operator=(const StrVec&);//拷贝赋值运算符
~StrVec();
StrVec(StrVec&& s) noexcept :elements(s.elements), first_free(s.first_free), cap(s.cap)//接管s的资源
{
s.elements = s.first_free = s.cap = nullptr;//让s进入null
}
StrVec& operator=(StrVec&& rhs) noexcept
{
if (this != &rhs)//检测自赋值
{
free();
elements = rhs.elements;
first_free = rhs.first_free;
cap = rhs.cap;
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
return *this;
}
void push_back(const string&);//拷贝元素
void push_back(string&&);//移动元素,右值引用
string* begin() const { return elements; }
string* end() const { return first_free; }
size_t size() const { return first_free - elements; }
size_t capacity() const { return cap - elements; }
private:
static std::allocator<std::string> alloc;//分配器
void chk_n_alloc() { if (size() == capacity()) reallocate(); }//每一次添加元素都要check
pair<string*, string*> alloc_n_copy(const string*, const string*);//工具,给拷贝构造、赋值运算符和析构用
void reallocate(); //获得更多内存并拷贝元素
void free(); //销毁释放内存
std::string *elements; //指向数组元素的指针
std::string *first_free; //指向第一个空闲元素的指针
std::string *cap; //指向数组尾后位置的指针
};
void StrVec::push_back(const string& s)
{
chk_n_alloc();//确保空间够容纳新的元素
alloc.construct(first_free++, s);
}
void StrVec::push_back(string&& s)
{
chk_n_alloc();//确保空间够容纳新的元素
alloc.construct(first_free++, std::move(s));
}
StrVec vec;
string s = "some thing";
vec.push_back(s);//调用push_back(const string& s)
vec.push_back("done");//调用push_back(string&& s)
8.左值和右值的引用成员函数
8.1 右值引用如何修饰成员函数,什么含义,怎么调用
class Foo
{
Foo& operator=(const Foo& rhs) &
{
//rhs赋值给本对象
return *this;//指向左值
}
Foo sorted() && ;
Foo sorted() const &;
private:
list<int> data;
};
Foo Foo::sorted() &&//本对象是右值,没有其他用户,可以对源对象排序
{
sort(data.begin(), data.end());
return *this;
}
Foo Foo::sorted() const &//本对象是左值,只能先复制一份,再排序,不能改变原来的
{
Foo ret(*this);
sort(ret.data.begin(), ret.data.end());
return ret;
}
8.2 定义两个或以上同名同参数列表的成员函数,要么都加上引用限定符,要么都不加
Foo sorted() && ;//
Foo sorted() const &;//2都加(如果没有&就×)
using Comp = bool(const int&, const int&);//com是函数类型的类型别名
Foo sorted(Comp*);//
Foo sorted(Comp*) const;//4都不加(如果有&就×)
9.问题
virtual Quote* clone() && {return new Quote(std::move(*this));}
virtual shared_ptr<Quote> clone() const & { return make_shared<Quote>(*this); }
有了&&限定符,*this本身就是右值?为何还要std::move(*this)呢?不能return new Quote(*this)?这种函数什么时候用?
C++——右值引用的更多相关文章
- C++右值引用浅析
一直想试着把自己理解和学习到的右值引用相关的技术细节整理并分享出来,希望能够对感兴趣的朋友提供帮助. 右值引用是C++11标准中新增的一个特性.右值引用允许程序员可以忽略逻辑上不需要的拷贝:而且还可以 ...
- C++ 11 中的右值引用
C++ 11 中的右值引用 右值引用的功能 首先,我并不介绍什么是右值引用,而是以一个例子里来介绍一下右值引用的功能: #include <iostream> #include &l ...
- 图说函数模板右值引用参数(T&&)类型推导规则(C++11)
见下图: 规律总结: 只要我们传递一个基本类型是A④的左值,那么,传递后,T的类型就是A&,形参在函数体中的类型就是A&. 只要我们传递一个基本类型是A的右值,那么,传递后,T的类型就 ...
- c++11的右值引用、移动语义
对于c++11来说移动语义是一个重要的概念,一直以来我对这个概念都似懂非懂.最近翻翻资料感觉突然开窍,因此记下.其实搞懂之后就会发现这个概念很简单,并无什么高深的地方. 先说说右值引用.右值一般指的是 ...
- VS2012 error C2664: “std::make_pair”:无法将左值绑定到右值引用
在vs2012(c++)make_pair()改动: C++: template <class T1, class T2> pair<V1, V2> make_pair(T1& ...
- 右值引用、move与move constructor
http://blog.chinaunix.net/uid-20726254-id-3486721.htm 这个绝对是新增的top特性,篇幅非常多.看着就有点费劲,总结更费劲. 原来的标准当中,参数与 ...
- 【转】C++11 标准新特性: 右值引用与转移语义
VS2013出来了,对于C++来说,最大的改变莫过于对于C++11新特性的支持,在网上搜了一下C++11的介绍,发现这篇文章非常不错,分享给大家同时自己作为存档. 原文地址:http://www.ib ...
- move语义和右值引用
C++11支持move语义,用以避免非必要拷贝和临时对象. 具体内容见收藏中的“C++右值引用” .
- [转载] C++11中的右值引用
C++11中的右值引用 May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移动语义std::move() 右值引用和右值的关系 完美转发 引用折叠推导 ...
- C++ 11 右值引用
C++11中引入的一个非常重要的概念就是右值引用.理解右值引用是学习“移动语义”(move semantics)的基础.而要理解右值引用,就必须先区分左值与右值. 注意:左值右值翻译可能有些问题 *L ...
随机推荐
- Linux启动详细过程(开机启动顺序)
启动第一步--加载BIOS当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它.这是因为BIOS中包含了CPU的相关信息.设备启动顺序信息.硬盘 ...
- 网络安全随笔 - Linux的netstat查看端口 0.0.0.0与127.0.0.1的区别
linux运维都需要对端口开放查看 netstat 就是对端口信息的查看 # netstat -nltp p 查看端口挂的程序 [root@iz2ze5is23zeo1ipvn65aiz ~]# n ...
- Python 进阶_生成器 & 生成器表达式
目录 目录 相关知识点 生成器 生成器 fab 的执行过程 生成器和迭代器的区别 生成器的优势 加强的生成器特性 生成器表达式 生成器表达式样例 小结 相关知识点 Python 进阶_迭代器 & ...
- iview+vue 表格中添加图片
开门见山,话不多说,要在表格中添加图片,可以使用td: <table " width="100%"> <tr class="tr-style ...
- CSL 的密码(后缀数组)
CSL 的密码 题目传送门 解题思路 后缀数组.对于每一个后缀\(k\)都有\(n - k + 1\)个前缀,把所有不和前一个(排序后的)公共且长度大于\(m\)的前缀个数加起来. 代码如下 #inc ...
- Digital Root 的推导
背景 在LeetCode上遇到这道题:Add Digits 大意是给一个数,把它各位数字相加得到一个数,如果这个数小于10就返回,不然继续 addDigits(这个相加得到的数). 题目很简单,但是如 ...
- 深入理解javascript原型和闭包(3)——prototype原型 (转载)
深入理解javascript原型和闭包(3)——prototype原型 既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的 ...
- Workbox使用策略
1.什么是Workbox Strategies? 当service workers 首次被引入时,可以设定一组常见的缓存策略. 缓存策略是一种模式,用于确定service workers 在收到fet ...
- 关于ovf导入到Esxi上出显的“文件条目(行1)无效,sha256……”处理办法
通常删除同名文件*.mf文件即可导入!
- css 多行省略号兼容移动端
浏览器兼容css样式 -webkit-line-clamp: ; display: -webkit-box; overflow: hidden; text-overflow: ellipsis; te ...