程序员面试宝典_笔记

第4章 程序设计基础

C++中的左值与右值

左值指的是可以出现在表达式左边的值(等号左边),可以被改变,它是存储数据值的内存地址,右值是存储在内存地址中的数据。左值可以作为右值,但很明显右值无法当成左值。
对于代码(a++) += a,a++不能当左值使用,++a可以,因为++a表示取a的地址中数据,加1后值放寄存器里面,返回a的内存地址值。而a++返回的是一个临时值。具体的解释如下:
i++ 与 ++i 的主要区别有两个:1、 i++ 返回原来的值,++i 返回加1后的值。2、 i++ 不能作为左值,而++i 可以。毫无疑问大家都知道第一点(不清楚的看下下面的实现代码就了然了),我们重点说下第二点。首先解释下什么是左值(以下两段引用自中文维基百科『右值引用』词条)。左值是对应内存中有确定存储地址的对象的表达式的值,而右值是所有不是左值的表达式的值。一般来说,左值是可以放到赋值符号左边的变量。但能否被赋值不是区分左值与右值的依据。比如,C++的const左值是不可赋值的;而作为临时对象的右值可能允许被赋值。左值与右值的根本区别在于是否允许取地址&运算符获得对应的内存地址。比如,

int i = 0; 
int *p1 = &(++i); //正确 
int *p2 = &(i++); //错误

++i = 1; //正确 
i++ = 5; //错误

那么为什么『i++ 不能作为左值,而++i 可以』?

// 前缀形式:
int& int::operator++() //这里返回的是一个引用形式,就是说函数返回值也可以作为一个左值使用
{//函数本身无参,意味着是在自身空间内增加1的
  *this += 1;  // 增加
  return *this;  // 取回值
}

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

如上所示,i++ 最后返回的是一个临时变量,而临时变量是右值。

C/C++关于new/delete与malloc/free的区别

在C++中,申请动态内存与释放动态内存,用new/delete与malloc/free都可以,而且它们的存储方式相同,new与malloc动态申请的内存都位于堆中,无法被操作系统自动回收,需要对应的delete与free来释放空间,同时对于一般的数据类型,如Int、char型,它们的效果一样。​

malloc/free是C/C++语言的标准库函数,在C语言中需要头文件的支持,new/delete是C++的运算发。对于类的对象而言,malloc/free无法满足动态对象的要求,对象在创建的同时要自动执行构造函数,对象消亡之前要自动执行析构函数,而malloc/free不在编译器控制权限之内,无法执行构造函数和析构函数。​

具体而言,new/delete与malloc/free的区别主要表现在以下几个方面:​

(1)new能够自动计算需要分配的内存空间,而malloc需要手工计算字节数。例如,int*p1=new int[2],int*p2=malloc(2*sizeof(int))。​

(2)new 与delete直接带具体类型的指针,malloc与free返回void类型的指针。​

(3)new是类型安全的,而malloc不是,例如,int*p=new float[2],编译时就会报错;而int*p=malloc(2*sizeof(int)),编译时编译器就无法指出错误来。​

(4)new一般有两步构成,分别是new操作和构造。new操作对应于malloc,但new操作可以重载,可以自定义内存分配策略,不做内存分配,甚至分配到非内存设备上,而malloc不行。​

(5)new将调用构造函数,而malloc不能;delete将调用析构函数,而free不能。​

(6)malloc/free需要库文件stdlib.h支持,new/delete则不需要库文件支持。
我们看一看malloc/free和new/delete如何实现对象的动态内存管理,见示例。

class Obj
{
public:
    Obj() { cout << "Initialization" << endl; }
    ~Obj() { cout << "Destroy" << endl; }
    void Initialize() { cout << "Initialization" << endl; }
    void Destroy() { cout << "Destroy" << endl; }
};

void UseMallocFree()
{
    Obj *a = (Obj*)malloc(sizeof(obj));
    a->Intialize();
    // ...
    a->Destroy();
    free(a);
}

void UseNewDelete()
{
    Obj *a = new Obj;
    //...
    delete a;
}

类Obj的函数Initialize模拟了构造函数的功能,函数Destroy模拟了析构函数的功能。函数UseMallocFree中,由于malloc/free不能执行构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。函数UseNewDelete则简单得多。

这只是个例子,不会有人用malloc/free来创建类对象。另外,new和delete配套使用,new[]和delete[]配套使用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值