引用和指针
引用和指针
引用和指针的区别什么?
什么是引用, 声明和使用引用要注意哪些问题
- 引用简单的理解就是某个目标变量的别名(alias), 对应用的操作与对变量直接操作效果完全相同;
- 声明一个引用的时候一定要对其进行初始化, 引用声明完成后, 相当于目标值有两个完全不同的名称;
- 引用本身不是一种数据类型, 因此引用本身不占用存储单元, 系统也不给引用分配存储单元;
- C++中引用的底层实现;
- 引用在内存中也会分配空间,空间中存放的事被引用变量的地址,因此可以将引用看作为一个常量指针ptr;
- 对引用取地址操作,其实是对被引用变量取地址,编译器将对引用取地址解释为&(*ptr)取地址;
- 更深入的理解是: 引用看作是一个常量指针ptr; 从底层来看, 引用确实占用了内存;
- 本质上,引用和指针没有区别, 只不过在语言层面上,C++设计者将通过指针来操作引用的实现细节隐藏了。不过,我们依然可以肯定:
- 定义一个引用就是定义一个指针,这个指针保存引用对象的地址,且指针类型为const,不可以再指向其他对象;
- 每次对引用变量的使用,实际都伴随着解引用,只是我们看不到符号*, 解完引用就对应着类型的大小;
- 所以内置类型直接传值就ok, 只有copy时需要大量的时间采用引用或指针;
- 理解C++中引用的底层实现
- 本质上,引用和指针没有区别, 只不过在语言层面上,C++设计者将通过指针来操作引用的实现细节隐藏了。不过,我们依然可以肯定:
什么是指针
- 指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;
引用和指针的区别 --- 本质区别是引用是一个别名, 不占内存
- 引用不可以为空,当被创建的时候,必须初始化,而指针可以是空值,可以在任何时候被初始化;
- 可以有const指针, 但是没有const引用, const不能修饰引用;
- 指针可以有多级,但是引用只能是一级;
- 指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;
- 指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了;
- sizeof引用得到的是所指向的变量(对象)的大小,而sizeof指针得到的是指针本身的大小;
- 指针和引用的自增(++)运算意义不一样(指针自加和对象自加);
- 返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄漏, 为什么会发生内存泄漏?
- 如果分配的空间比返回类型的空间大, delete对象后还会剩余一部分空间没有被释放掉, 造成内存泄漏;
引用作为函数参数有哪些特点
- 传递引用给函数与传递指针的效果是一样的;
- 使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;
- 而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;
- 如果传递的是对象,还将调用拷贝构造函数, 因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好;
- 使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;
- 另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰;
常引用
- 如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用
引用作为函数返回值类型的格式、好处和需要遵守的规则
- 格式:类型标识符 &函数名(形参列表及类型说明)
- 好处:在内存中不产生被返回值的副本;
- 注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!
- 注意事项:
- 不能返回局部变量的引用, 主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态;
- 不能返回函数内部new分配的内存的引用, 虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面;
- 例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak;
- 可以返回类成员的引用,但最好是const, 主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中;
- 如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性;
- 流操作符重载返回值申明为“引用”的作用;
- 让流可以连续使用;
- 等号的连续复制;
- 在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符;
- 主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值;