右值,右值引用,移动语义相关
C++ 居然可以给右值赋值?
1 |
|
这段代码没有报错,这里的 f() 应该是一个纯右值表达式,因为它是一个返回类型是非引用的函数调用。
类实际上会隐式声明一个复制赋值运算符,如果把它 delete 掉,还能成功运行吗?
1 | A& operator=(cosnt A&) = delete; |
就不能了,因为 右值不能用作内建赋值运算符及内建复合赋值运算符的左操作数。 例子中的 f() = a的 = 不是内建的函数
移动语义相关
1 |
|
局部声明的右值引用是某些情况下可以视为左值;这里需要 test(std::move(a));
.
移动语义与所有权:
1 |
|
至此,你就可以理解移动语义了
那么被移动的对象还能不能继续使用?
除非另有规定,此类移动对象应置于有效但未指定的状态。
比如移动了一个vector
1 | void foo(vector<int>& a, vector<int>& b){ |
b 被移动后,其数据为空吗?还是会和 a 交换?这些都有可能,是不确定的,所以不应直接访问b,应主动清空其数据再访问。
1 | void foo(vector<int>& a, vector<int>& b){ |
这样才是安全的。
被移动的对象既可以读取自己的数据成员的值,也可以调用自己的成员函数(如果是类类型)(如果是无前提的话)。
特别说明:一个成员函数在对象任何状态下进行调用都返回合法的值,这个函数就是无前提的。
我们拿vector的begin()和front()成员函数进行说明。
- front()的调用合法依赖容器不为空(不然就是ub)
- begin()并不依赖
那么你是否认为,被 std::move
后的 vector
调用 front()
成员函数就一定是 ub 呢?
显然不是,因为移动以后状态不一定是空的。
我们再用std::thread 举例:
1 |
|
以上代码没有问题,即使t已经被移动过,但依然可以t = std::move(t2) 这是理所应当的。
包括对joinable()的调用,也毫无问题。顺带一提,智能指针和std::thread 在C++有特殊指定,被移动后的状态为空。
如果是平凡类型的话(包括平凡类类型),一切的移动构造,移动赋值之类的操作,等价于复制。 int b = std::move(a) 等价于 int b = a
,
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 luseYang的妙妙屋!