从一道错误的阿里面试题浅谈函数

2016年阿里有一道关于c++的面试题(错题):

#include<iostream> 
void func(const int &v1,const int &v2) {
	std::cout<<v1<<” ”;
	std::cout<<v2 <<” ”;
}
int  main(int argc ,char * argv[])
{
    int i=0;
   func(++i,i++);
   return 0;
}


首先看到这个题的时候,对于很多人来说第一感觉就是茫然的感觉,答案全凭猜测,但其实搞清楚i++和i++的实质之后,你也就可以对这题发表看法了,确实存在着问题。

首先我们要弄懂++i和i++的区别,我们看下源码:

 
 
// ++i前缀形式:
int& int::operator++() //这里返回一个引用形式,说明函数返回值可以作为一个左值使     用
{
  *this += 1;  // 增加
  return *this;  // 返回值(数据和地址)
}


很明显我们看到对于++i的操作,在源码中是先自增加,再返回这个变量的,当然包括了变量的值和对应的地址,也就是左值。

//后缀形式i++:
const int int::operator++(int) //函数返回值是一个常量int型,与前缀形式的差别所在。
{//函数带参,说明有另外的空间开辟
  int oldValue = *this;  
  ++(*this);  // 增加
  return oldValue;  // 返回被取回的值(只是数据)

}

函数返回的是变量还未增加的值,注意这里返回的是一个新声明的变量,即只有数据值,但地址是不同的。也就是i++是一个右值

再看看func函数原型:

void func(const int &v1,const int &v2),形参是常量引用型,也就是说,传进去的是地址,并且是不可被修改的。这点很重要。

熟悉c++都知道:

1.c++不规定求职的顺序

2.同一函数调用的参数间没有序列点,不规定副作用(变量值变化)发生时机

3.ABI规定的入栈顺序,但并没规定谁先计算

所以,由于未定义行为,这道题其实是有问题的,核心问题就是求职顺序的不确定性。而不同的编译器可以有不同的编译顺序!

如果是右→左的顺序:

1. v2作为i的副本值的引用,v2=0;

2. i=i+1;//(i++)=1

3. i=i+1;//(++i)=2

4. V1为i的引用 //v1=i=2

而如果是左→右的顺序,不难知道v1=2;v2=1;

猜你喜欢

转载自blog.csdn.net/qq_38506897/article/details/79432967