C++面试八股文:什么是左值,什么是右值? 天天新消息
时间:2023-06-17 08:02:35来源:博客园

某日二师兄参加XXX科技公司的C++工程师开发岗位第16面:

面试官:什么是左值,什么是右值?

二师兄:简单来说,左值就是可以使用&符号取地址的值,而右值一般不可以使用&符号取地址。


(资料图)

int a = 42;//a是左值,可以&aint* p = &a;int* p = &42;//42是右值,无法取地址

二师兄:一般左值存在内存中,而右值存在寄存器中。

int a = 42, b = 1024;decltype(a+b);//类型为右值,a+b返回的值存在寄存器中decltype(a+=b);//类型为左值,a+=b返回的值存储在内存中

二师兄:严格意义上分,右值分为纯右值(pvalue)和将亡值(xvalue)。C++中,除了右值剩余的就是左值。

42;//纯右值int a = 1024;std::move(a);//将亡值

面试官:C++98/03中已经有了左值,为什么还要增加右值的概念?

二师兄:主要是为了效率。特别是STL中的容器,当需要把容器当作参数传入函数时:

void function(std::vector vi2){    vi2.push_back(6);    for(auto& i: vi2) { std:: cout < i << " " ;}    std::cout << std::endl;}int main(int argc, char* argv[]){    std::vector vi1{1,2,3,4,5};    function(vi1);    return 0;}

二师兄:当我们要把vi1传入函数时,在C++98/03时只能通过拷贝构造函数,把vi1中所有的元素全部拷贝一份给vi2,拷贝完成之后,当function函数返回时,vi2被析构,然后vi1被析构。

二师兄:在C++11及之后,我们可以通过std::move()vi1强制转为右值,此时在初始化vi2时执行的不是拷贝构造而是移动构造:

void function(std::vector&& vi2){    vi2.push_back(6);    for(auto& i: vi2) { std:: cout < i << " " ;}    std::cout << std::endl;}int main(int argc, char* argv[]){    std::vector vi1{1,2,3,4,5};    function(std::move(vi1));    return 0;}

二师兄:这里只进行了一次构造。一次移动(当元素特别多时,移动的成本相对于拷贝基本可以忽略不记),一次析构。效率得到很大的提升。

二师兄:当然,移动过后的变量已经不能再使用(身体被掏空),在std::move(vi1)之后使用vi1是未定义行为。

面试官:好的。那你知道移动构造是如何实现的吗?

二师兄:移动构造是通过移动构造函数实现的,当类有资源需要管理时,拷贝构造会把资源复制一份,而移动构造偷走了原对象的资源。

struct Foo{    int* data_;        //copy construct    Foo(const Foo& oth)    {        data_ = new int(*oth.data_);    }    //move construct    Foo(Foo&& oth) noexcept    {        data_ = oth.data_;//steal        oth.data_ = nullptr;//set to null    }}

面试官:好的。你觉得移动构造函数的noexcept关键字能省略吗?为什么?

二师兄:应该不能吧,具体不清楚。

面试官:那你知道std::move是如何实现的吗?

二师兄:好像是static_cast实现的吧。

面试官:那你知道什么叫万能引用吗?

二师兄:万能引用主要用在模板中,模板参数是T,形参是T&&,此时可以传入任何类型的参数,所以称之为万能引用。

templatevoid function(T&& t) { ...}

面试官:那你知道万能引用是如何实现的吗?

二师兄:不太清楚。。

面试官:完美转发知道吗?

二师兄:std::forward吗,了解过一些,不太熟悉。

面试官:好的,回去等消息吧。

让我们来回顾以下二师兄今天的表现:

移动构造函数的noexcept关键字能省略吗?为什么?

这里尽量不要省略。如果省略,编译器会推断是否会抛出异常。如果移动构造函数可能会抛出异常,则编译器不会将其标记为noexcept。当编译器不标记为noexcept时,为了保证程序的正确性,编译器可能会采用拷贝构造的方式实现移动构造,从而导致效率降低。

需要注意的是,如果标记了noexcept但在移动时抛出了异常,则程序会调用std::terminate()函数来终止运行。

知道std::move是如何实现的吗?

这里的确是通过static_cast实现的,讲左值强行转换成右值,用来匹配移动语义而非拷贝。

templatetypename std::remove_reference::type&& move(T&& t) { return static_cast::type&&>(t);}

万能引用是如何实现的?

万能引用主要使用了引用折叠技术,

templatevoid function(T&& t) { ...}

当T类型为左值时,&& &被折叠为&, 当T类型为右值时,&& &&被折叠称为&&。以下是折叠规则:

& &    -> && &&   -> &&& &   -> &&& &&  -> &&

完美转发知道吗?

当我们需要在function中传递t参数时,如何保证它的左值或右值语义呢?这时候完美转发就登场了:

templatevoid function2(T&& t2) {}templatevoid function(T&& t) {    function2(t);}

当传入的参数t的类型时右值时,由于引用折叠还是右值,此时的t虽然时一个右值引用,但t本身却是一个左值!这里非常的不好理解。如果我们把t直接传入到function2,那么function2中的t2会被推导成左值,达不到我们的目标。如果在调用function2时传入std::move(t),当t是右值时没有问题,但当t是左值时,把t移动到t2t在外部不在能用。这也不符合我们的预期。此时std::forward闪亮登场!

templatevoid function2(T&& t2) {}templatevoid function(T&& t) {    function2(std::forward(t));}

std::forward使用了编译时多态(SFINAE)技术,使得当参数t是左值是和右值是匹配不同的实现,完成返回不同类型引用的目的。以下是标准库的实现:

template constexpr _Tp && forward(typename std::remove_reference<_Tp>::type &&__t) noexcept{    return static_cast<_Tp &&>(__t);}template constexpr typename std::remove_reference<_Tp>::type && move(_Tp &&__t) noexcept{    return static_cast::type &&>(__t);}

好了,今日份面试到这里就结束了。二师兄的表现如何呢?预知后事如何,且听下回分解。

关注我,带你21天“精通”C++!(狗头)

标签:

最新
  • C++面试八股文:什么是左值,什么是右值? 天天新消息

    某日二师兄参加XXX科技公司的C++工程师开发岗位第16面:>面试官:什么

  • 身边雷锋 衡阳好人丨坚持13年捐款助残的退休教师刘显文

    衡阳新闻网讯 记者程聪报道 刘爹爹您又来了,十分感谢您对耒阳残疾儿

  • 明确了!2024年年底中山将实现村(居)民议事厅全覆盖-世界滚动

    6月16日,中山市城乡社区协商工作推进会在横栏镇五沙村举行。会议总结

  • 疯狂爆梗王一切会好通关攻略 全球快讯

    许多疯狂爆梗王同学还不了解疯狂爆梗王一切会好通关攻略,现在将由第一

  • 当前热讯:经济持续好转,就业保持总体稳定,一周工作一小时及以上就算就业

    经济持续好转,就业保持总体稳定,一周工作一小时及以上就算就业,就业

  • 父亲节送什么手机合适?拍照强悍系统流畅,OPPO Find X6不会让你失望

    父亲节的到来,加上618年中大促活动收尾,相信不少人会准备给父亲挑选一

  • 文科医生有哪些属于理还是可以报考吗 全球观热点

    1、文科医生有哪些阔以,文科生身上带着文人的气质,和病人交流的时候

  • 下班快回家!厦门发布暴雨蓝色预警信号

    厦门网讯综合“厦门天气在线”微博消息,今日:暖切北抬,辐合明显,天

  • 十代i7什么时候上市 十代i7发布时间

    十代i7什么时候上市,以英特尔酷睿为例,十代i7上市时间是2019年10月8

  • 世界观焦点:高盛:维持水滴公司“买入”评级 目标价格3.2美元

    水滴公司(WDH US)2023年Q1财报发布后,高盛最新研究报告维持水滴公司“

  • 吴优个人资料简介

    吴优个人资料简介吴优因个人喜爱度较低被淘汰了,娜姐瞬间哭成泪人,好

  • 每日龙虎榜 | 期市资金日内净流入 豆粕大幅增仓位居榜首

    【每日龙虎榜】期市资金日内净流入,豆粕大幅增仓位居榜首!一文带你深

  • 全球报道:解剖屎山,寻觅黄金之第二弹

    大家好,我3y啊。由于去重逻辑重构了几次,好多股东直呼看不懂,于是我

  • 证券开户佣金什么意思?股票一股和一手的区别介绍

    股市清明节休市几天3天清明节股市休市3天,如果遇到法定调班为周末,

  • 世界快报:清华大学陈国强获国际代谢工程奖,表彰其对下一代工业生物技术的贡献

    每经AI快讯,近日,由代谢工程领域国际权威学术组织国际代谢工程学会主

  • 环球热议:基金定投投多长时间最好?什么是主动管理型基金?

    基金定投投多长时间最好?基金定投多久比较合适需要看投资者想要的止

  • 旅游
    • Win10系统如何更改磁贴大小?win10如何开启跨设备共享功能?

    • 股票涨停还能买吗?股票涨停了卖好还是不卖好?

    • 猫咪托运的基本流程是怎样的? 猫咪托运需要办理什么呢?

    • 科力远创建于哪一年?科力远主要产品有哪些?|世界信息