复习C++:深入new

来源:计算机等级考试    发布时间:2012-08-29    计算机等级考试视频    评论

  但是,上述错误的代码似乎也能编译执行,并不会带来什么错误。事实上,new与new[]、delete与delete[]是有区别的,特别是当用来操作复杂类型时。假如针对一个我们自定义的类MyClass使用new[]:

  MyClass* p = new MyClass[10];

  上述代码的结果是在堆上分配了10个连续的MyClass实例,并且已经对它们依次调 用了构造函数,于是我们得到了10个可用的对象,这一点与Java、C#有区别的,Java、C#中这样的结果只是得到了10个null。换句话说,使用 这种写法时MyClass必须拥有不带参数的构造函数,否则会发现编译期错误,因为编译器无法调用有参数的构造函数。

  当这样构造成功后,我们可以再将其释放,释放时使用delete[]:

  delete[] p;

  当我们对动态分配的数组调用delete[]时,其行为根据所申请的变量类型会有所不同。如果p指向简单类型,如int、char等,其结果只不过是这块内存被回收,此时使用delete[]与delete没有区别,但如果p指向的是复杂类型,delete[]会针对动态分配得到的每个对象调用析构函数,然后再释放内存。因此,如果我们对上述分配得到的p指针直接使用delete来回收,虽然编译期不报什么错误(因为编译器根本看不出来这个指针p是如何分配的),但在运行时(DEBUG情况下)会给出一个Debug assertion failed提示。

  到这里,我们很容易提出一个问题--delete[]是如何知道要为多少个对象调用析构函数的?要回答这个问题,我们可以首先看一看new[]的重载。

  class MyClass

  {

  int a;

  public:

  MyClass() { printf("ctorn"); }

  ~MyClass() { printf("dtorn"); }

  };

  void* operator new[](size_t size)

  {

  void* p = operator new(size);

  printf("calling new[] with size=%d address=%pn", size, p);

  return p;

  }

  // 主函数

  MyClass* mc = new MyClass[3];

  printf("address of mc=%pn", mc);

  delete[] mc;

  运行此段代码,得到的结果为:(VC2005)

  calling new[] with size=16 address=003A5A58

  ctor

  ctor

  ctor

  address of mc=003A5A5C

  dtor

  dtor

  dtor

  虽然对构造函数和析构函数的调用结果都在预料之中,但所申请的内存空间大小以及地址的数值却出现了问题。我们的类MyClass的大小显然是4个字节,并且申请的数组中有3个元素,那么应该一共申请12个字节才对,但事实上系统却为我们申请了16字节,并且在operator new[]返后我们得到的内存地址是实际申请得到的内存地址值加4的结果。也就是说,当为复杂类型动态分配数组时,系统自动在最终得到的内存地址前空出了 4个字节,我们有理由相信这4个字节的内容与动态分配数组的长度有关。通过单步跟踪,很容易发现这4个字节对应的int值为0x00000003,也就是说记录的是我们分配的对象的个数。改变一下分配的个数然后再次观察的结果证实了我的想法。于是,我们也有理由认为new[] operator的行为相当于下面的伪代码:

  template <class T>

  T* New[](int count)

  {

  int size = sizeof(T) * count + 4;

  void* p = T::operator new[](size);

  *(int*)p = count;

  T* pt = (T*)((int)p + 4);

  for(int i = 0; i < count; i++)

  new(&pt[i]) T();

  return pt;

  }

视频学习

我考网版权与免责声明

① 凡本网注明稿件来源为"原创"的所有文字、图片和音视频稿件,版权均属本网所有。任何媒体、网站或个人转载、链接转贴或以其他方式复制发表时必须注明"稿件来源:我考网",违者本网将依法追究责任;

② 本网部分稿件来源于网络,任何单位或个人认为我考网发布的内容可能涉嫌侵犯其合法权益,应该及时向我考网书面反馈,并提供身份证明、权属证明及详细侵权情况证明,我考网在收到上述法律文件后,将会尽快移除被控侵权内容。

最近更新

社区交流

考试问答