C++笔记 -- move_if_noexcept

move_if_noexcept

std::move()总是返回一个xvalue,即无名的T&&

std::move_if_noexcept()根据条件,可能返回T&&或者const T&

std::move_if_noexcept()是模板函数,总能根据实参推演做实例化为不同的静态多态函数。否则普通函数怎么既能返回X类型,又返回Y类型呢?

简单的说,如果类型T的移动构造函数(简称move-ctor)是noexcept修饰符保证过的,则返回T&&, 否则返回const T&.

#include <iostream>
#include <vector>
 
using namespace std;
 
class String{
public:
 
    String(){
        id_ = ++cnt_;
        std::cout<<"default ctor["<< id_ <<"]"<<endl;
    }
 
    ~String(){
        std::cout<<"dtor["<<id_<<"]"<<endl;
    }
 
    String(const String& rhs){
        id_ = ++cnt_;
        std::cout<<"copy ctor ["<<id_<<"] from ["<< rhs.id_ <<"]"<<endl;
        //if (id_==17) throw 1;
    }
 
    String(String&& rhs){
        id_ = ++cnt_;
        std::cout<<"move ctor ["<<id_<<"] from ["<< rhs.id_ <<"]"<<endl;
    }
 
    static int cnt_;
    int id_;
};
 
int String::cnt_=0;
 
int main() {
 
    std::vector<String> vec;
    vec.resize(3);
 
    std::cout<<"-------------------------\n";
    try{
        vec.push_back(String());
    }
    catch(...){}
    std::cout<<"-------------------------\n";
    return 0;
}

程序输出: 解释:

default ctor[1]
default ctor[2]
default ctor[3]
// resize(3)会产生3个String对象的连续存储数组,对象分别标号[1][2][3]

default ctor[4] // vec.push_back(String());语句中Test()临时对象 id==[4]
move ctor [5] from [4] // 新插入的数据用move-ctor
copy ctor [6] from [1] // 旧数据的搬移,用copy-ctor
copy ctor [7] from [2]
copy ctor [8] from [3]
dtor[1] // 数据迁移成功后,原有老数据都废弃
dtor[2]
dtor[3]
dtor[4]

dtor[6] main函数返回,vec中数据都析构
dtor[7]
dtor[8]
dtor[5]

问题1) 为什么对象[1],[2], [3] 的迁移,都采用copy-ctor,明明String类有move-ctor而舍弃不用?

反证法:假设用move-ctor,再假设当处理到对象[3]迁移到对象[8]时,move-ctor抛异常了,对象[3]怎么恢复成最初的样子?

异常安全的代码,要求即使push_back()失败了,vec要保证还是原先的样子,即有完好的三个对象[1][2][3]的样子。

把数据反向move?

<pre name="code" class="cpp">
catch(...){
[6]==>[1],[7]==>[2],[8]==>[3]   //在异常处理块中恢复被破坏的数据[1],[2],[3](他们都被偷窃空了)
}

要知道现在正在处理的问题正是[3]>[8]造成的,谁保证[6]>[1],[7]>[2]不出问题(move-ctor抛异常),而且[3]>[8]时抛异常时[8]是个未能完成初始化的不可靠的对象,怎么保证能从[8]中拿出可靠数据去初始化[3]?

因此,vector库的作者不敢使用move-ctor。
 
问题2)为什么对象[5]的初始化却敢用move-ctor?

很简单,[4]==>[5],[4]是临时对象,不是vec数组中的老数据,所以即使这个过程抛例外,也不会影响“异常安全性”。

vec仍然在[4]==>[5]抛例外后,保持完整的老数据。

问题3)如何完全利用move-ctor,而不用copy-ctor

很简单,向党组织保证不抛例外:String(const String& rhs) noexcept {。。。},加上noexcept异常修饰符。vector库将知道String作者已经用人格保票不抛例外了,就会全部选用高效的move-ctor。

问题4)如果加上noexcept异常修饰符后,还是不自觉的抛异常了怎么办?

很简单,欺骗党组织,会死的很惨,C++规范上说,直接给你std::terminate(),一般就是abort(),程序挂了。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值