c++23中的新功能之六更简单的隐性Move

news/2024/12/15 18:50:56/

一、介绍

在学习c++的过程中,一些老的技法,其实在不断的被自动优化。比如一些循环的优化、字符串的处理等等。随着标准的发展,编译器的跟进,有些优化其实编译器可以做的更好,比如一些字符串处理过程中的临时变量。但是c++毕竟是一门中高级语言,不可能做到面面俱到。这里面仍然有大量的优化需要开发者自己承担,不过,随着更新的c++标准不断提出,又有一些优化的可能被编译器实现了。那就是今天本文提到的“Simpler Implicit Move”。
这里先引入一些基础,需要大家回忆一下在什么情况下会出现复制对象的可能,哪种更频繁。换句话说,哪里有可能出现内存的重复应用,那就有优化的空间,不管他是不是必须的。因为这种必须可能是现在必须,未来未必。

二、返回值的优化

在早期的c++的函数返回值的处理中,可能有印象的早期的学习c++的朋友都知道,返回值是要复制三次的,这对于一个普通的基础类型如int,char之类的还可以忽视,但对于一个拥有数据较多的类对象本身就是一种内存的浪费,所以才有了NRVO,返回值优化。其实这是Copy Elision,复制省略的一种方式。这和前面提到过的COW和零拷贝目的都是一样的,内存毕竟宝贵,省一下是一下,省一回是一回。看下面的一个例子:

struct A
{A() {};A(const A&) {};A(A&&) noexcept {};
};
A Create()
{return A{};
};
A Inst()
{A a = Create();return a;
}
void Get()
{A a1 = Inst();
}

这里面有拷贝构造函数和移动构造函数,对于这种non-trivial的行为,c++的中会产生多次拷贝和移动。但是这时,编译器就出手了。先分析一下,如果从代码上分析,A构造会产生一次,然后再移动构造一次,Create后返回被拷贝一次,最后a1再来一次移动构造。然后在c++11标准后的编译器,发现有的处理其实是在Get()函数的栈帧上,所以它直接掠过当中的拷贝把a返回到a1中,省略一次拷贝。其实编译器不但会省略这一步,还会进一步把Create函数的结果直接拷贝到a1,这在c++11以前的编译器中,就称为前面说的NRVO。但是它有着一些比较严格的媱,比如返回值不能有修饰,比如move之类的,这就没办法NRVO了。另外,要求返回值必须有明确的拷贝构造函数且必须是同一类(父子类都不行)
而在c++11中,则提出implicit move,其实就是对移动处理这些,即先把返回值定做右值进行重载,成功就NRVO,不成功则回到原来的NRVO规则。


std::unique_ptr<T> Get()
{std::unique_ptr<T> uPtr =  Inst();return uPtr;
}

三、c++14以后的变化

技术标准只要开了口子,在不会有威胁时,只会越开越大,c++14以后进一步进行了放松,即对返回同类型也不要求必须完全一致了,即下面也是可以的:

struct P { };
struct S : public P { };
std::unique_ptr<P> Get()
{std::unique_ptr<S> uPtr = Inst();return uPtr;
}

原来的标准中,复制省略在不同的类型中是完全不起作用的,但是在c++14后,将其看做右值,利用移动构造函数来返回。
在c++20后,继续放松,但它更倾向于复制省略而非implicit move,看一个例子:

struct S {};
struct S1 { S1(S ss){}; };//S1接受S的值来构造
S1 Get() { S s; return s; }

在c++17中,在Get函数中,s会被先拷贝,然后调用S1的构造函数,因为S1没有&&移动构造函数(这是c++11中implicit move严格接受右值,必须有S1(S&&)这种签名才可),但是在c++20 中则进一步放松,此处即可调用S的移动构造函数,然后再调用S1的构造函数。
但是有没有发现,下面的例子却编译不过:

struct S {};
struct S1 { S1(S &&ss){}; };
S&& Get() { S s; return s; }

不行的原因是,c++中怎么可以允许你返回一个悬垂引用(野指针)。

等到了c++23,则又出现了新的问题,这个问题还是上面的这个问题引出的,看下面的例子:

struct S {};
struct S1 { S1(S&&){}; };
S1 Get1(S&& s) { return s; }
//下面的错误
S&& Get2(S&& s) { return s; }

刚刚在前面说过的话,只要能省略的,都有优化的可能。这里的代码不再有NRVO,只是直接把s返回,如果可以,这就有点香了。但一个左值变成右值需要std::move,这从一个右值变成左右再变成右值,明显是在玩儿闹啊。标准制定者后终决定,只要可以move的return值,直接把返回值做为右值。但是这个有点小瑕疵,看下面的代码:

int& Example() {int a = 0; return a;}   (1)
int&& Example() {int a = 0; return a;}  (2)

如果认真学习过c++的基础语法的都明白,(1)式是明显的返回一个临时变量的引用(悬垂引用,这个和野指针是一个道理),这玩意儿闹大了啊,但在c++23中这个玩意儿合法了。惊不惊喜,意不意外。但(2)式仍然是个坏孩子,返回一个悬垂引用。

四、总结

通过对上面的隐性移动的不断扩展的路程可以看到,标准的演化,仍然是前面分析过的,不断的朝着简单,填坑的方向发展。在尽量易用的前提下,把特殊情况不断的排除。这也是c++原来固有的一个毛病,大多数可以,有几种情况不可以,有些开发者可能一辈子都遇不到这些情况,但面试时还得被虐。话又说回来,标准发展着就发现,有些东西还是得补洞,不然会有新的窟窿出来。完美的事情,毕竟是不存在的。


http://www.ppmy.cn/news/184903.html

相关文章

Pytorch中x.cuda(non_blocking=True)参数解释

Pytorch中x.cuda(non_blockingTrue)参数解释 文章目录 Pytorch中x.cuda(non_blockingTrue)参数解释 在 PyTorch 中&#xff0c; non_blocking 是一个布尔类型的参数&#xff0c;用于指定是否启用异步数据传输。当你将 Tensor 数据从 CPU 移动到 GPU 时&#xff0c;可以通过设置…

华为OD机试真题 Java 实现【火车进站】【牛客练习题】

一、题目描述 给定一个正整数N代表火车数量&#xff0c;0<N<10&#xff0c;接下来输入火车入站的序列&#xff0c;一共N辆火车&#xff0c;每辆火车以数字1-9编号&#xff0c;火车站只有一个方向进出&#xff0c;同时停靠在火车站的列车中&#xff0c;只有后进站的出站了…

计算机组装模拟课堂,《电脑装机模拟》获教师青睐 又一款游戏将进入课堂

《电脑装机模拟》上架Steam后让不少玩家过了一把攒机瘾&#xff0c;首月销量也突破了10万份。近日游戏发行商的制作人还表示&#xff0c;已经有不少教师联系了他们&#xff0c;声称想要用这款游戏当做课堂教材。 《电脑装机模拟》发行商The Irregular Corporation的制作人Stuar…

电脑电源问题,导致攒机电脑无法开机

大概有十年了&#xff0c;没有自己攒机。倒是修了不少电脑&#xff0c;大多是内存条没插好&#xff0c;硬盘损坏数据恢复&#xff0c;重装系统之类的问题。前段时间公司要买台配置 比较高的电脑做流体模拟运算&#xff0c;买台高配置的电脑感觉不划算&#xff0c;不如自己攒一…

对微型计算机硬件的认识,如何认识计算机硬件系统

如何认识计算机硬件系统 现在个人电脑已经成为学习&#xff0c;办公&#xff0c;娱乐不可或缺的工具了&#xff0c;或许对于电脑大家最熟悉的莫过于系统或者一些常用的办公&#xff0c;学习软件&#xff0c;那么计算机硬件系统又是什么呢? 认识计算机硬件系统——1、主机 1.1 …

今天看了一下攒机配置 5000元以下 参考以下

今天看了一下攒机配置 5000元以下 参考以下 AMD 羿龙 II X6 1035T(盒)&#xffe5;1180 华擎 890GX Extreme3&#xffe5;899 Samsung/三星 单条4G 台式机内存 dd3 1333 PC3-10600 &#xffe5;710 淘宝网 AOC 2430V&#xffe5;1350 posted on 2010-06-16 12:47 冯瑞涛 阅读( …

ssm基于Android的组装机配置商城APP(ssm+uinapp+Mysql)

网络的广泛应用给生活带来了十分的便利。所以把组装机配置商城管理与现在网络相结合&#xff0c;利用java技术建设组装机配置商城app&#xff0c;实现组装机配置的信息化。则对于进一步提高组装机配置商城管理发展&#xff0c;丰富组装机配置商城管理经验能起到不少的促进作用。…

玩转四旋翼无人机(攒机基础1)

机架 轴距&#xff08;飞机大小&#xff09; 机架定义的飞机的基本外观以及飞机的大小。主要参数为轴距。 F450&#xff08;轴距450mm&#xff09;是比较合适的&#xff0c;推荐&#xff0c;机架比较小&#xff0c;安装的时候比较简单&#xff0c;没有那么多螺丝&#xff0c;…