IT评测·应用市场-qidao123.com

标题: C++面试八股文:什么是左值,什么是右值? [打印本页]

作者: 北冰洋以北    时间: 2023-6-17 00:10
标题: C++面试八股文:什么是左值,什么是右值?
某日二师兄参加XXX科技公司的C++工程师开发岗位第16面:
面试官:什么是左值,什么是右值?
二师兄:简单来说,左值就是可以使用&符号取地址的值,而右值一般不可以使用&符号取地址。
  1. int a = 42;        //a是左值,可以&a
  2. int* p = &a;
  3. int* p = &42;        //42是右值,无法取地址
复制代码
二师兄:一般左值存在内存中,而右值存在寄存器中。
  1. int a = 42, b = 1024;
  2. decltype(a+b);        //类型为右值,a+b返回的值存在寄存器中
  3. decltype(a+=b);        //类型为左值,a+=b返回的值存储在内存中
复制代码
二师兄:严格意义上分,右值分为纯右值(pvalue)和将亡值(xvalue)。C++中,除了右值剩余的就是左值。
  1. 42;                                //纯右值
  2. int a = 1024;
  3. std::move(a);        //将亡值
复制代码
面试官:C++98/03中已经有了左值,为什么还要增加右值的概念?
二师兄:主要是为了效率。特别是STL中的容器,当需要把容器当作参数传入函数时:
  1. void function(std::vector<int> vi2)
  2. {
  3.     vi2.push_back(6);
  4.     for(auto& i: vi2) { std:: cout < i << " " ;}
  5.     std::cout << std::endl;
  6. }
  7. int main(int argc, char* argv[])
  8. {
  9.     std::vector<int> vi1{1,2,3,4,5};
  10.     function(vi1);
  11.     return 0;
  12. }
复制代码
完美转发知道吗?
当我们需要在function中传递t参数时,如何保证它的左值或右值语义呢?这时候完美转发就登场了:
  1. void function(std::vector<int>&& vi2)
  2. {
  3.     vi2.push_back(6);
  4.     for(auto& i: vi2) { std:: cout < i << " " ;}
  5.     std::cout << std::endl;
  6. }
  7. int main(int argc, char* argv[])
  8. {
  9.     std::vector<int> vi1{1,2,3,4,5};
  10.     function(std::move(vi1));
  11.     return 0;
  12. }
复制代码
当传入的参数t的类型时右值时,由于引用折叠还是右值,此时的t虽然时一个右值引用,但t本身却是一个左值!这里非常的不好理解。如果我们把t直接传入到function2,那么function2中的t2会被推导成左值,达不到我们的目标。如果在调用function2时传入std::move(t),当t是右值时没有问题,但当t是左值时,把t移动到t2,t在外部不在能用。这也不符合我们的预期。此时std::forward闪亮登场!
  1. struct Foo
  2. {
  3.     int* data_;
  4.    
  5.     //copy construct
  6.     Foo(const Foo& oth)
  7.     {
  8.         data_ = new int(*oth.data_);
  9.     }
  10.     //move construct
  11.     Foo(Foo&& oth) noexcept
  12.     {
  13.         data_ = oth.data_;                //steal
  14.         oth.data_ = nullptr;        //set to null
  15.     }
  16. }
复制代码
std::forward使用了编译时多态(SFINAE)技术,使得当参数t是左值是和右值是匹配不同的实现,完成返回不同类型引用的目的。以下是标准库的实现:
  1. template<typename T>
  2. void function(T&& t) { ...}
复制代码
好了,今日份面试到这里就结束了。二师兄的表现如何呢?预知后事如何,且听下回分解。
关注我,带你21天“精通”C++!(狗头)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4