C++ Gotchas && FAQ(2)

本文探讨了C++中new、malloc、delete和free的区别与注意事项,包括new的构造函数调用、类型安全、可覆盖性,以及new与delete的内存管理规则。此外,还讲解了new过程中的内存分配和构造,delete过程中的析构与内存释放。最后,讨论了继承和组合的概念及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

G14.new && malloc()
  new是一个关键字,malloc是一个函数
  构造函数/析构函数:与 malloc(sizeof(Fred))不一样,new Fred() 调用 Fred 的构造函数。同样,delete p 调用 *p 的析构函数。
  类型安全:malloc() 返回一个没有类型安全的 void* 。new Fred() 返回一个正确类型(一个 Fred*)的指针。
  可覆盖性:new 是一个可被类重写/覆盖的算符(operator),而 malloc() 在类上没有可覆盖性。

G15.new,free(),delete,malloc()
  在一个程序中同时使用 malloc() 和 delete 或者同时使用 new 和 free() 是合情合理合法的。但是,对由 new 分配的指针调用 free(),或对由 malloc() 分配的指针调用 delete,是无理的、非法的。
  不要在同一个指针上混合malloc() 和 delete,或在同一个指针上混合new 和 free()。如果通过p = new char[n]分配,则必须使用delete[] p;不可以使用free(p)。如果通过分配p = malloc(n),则必须使用free(p);不可以使用delete[] p 或 delete p!

G16.new的NULL检查?
  不!在 C++中,如果运行时系统无法为p = new Fred()分配 sizeof(Fred) 字节的内存,会抛出一个std::bad_alloc异常(set_new_handler()总结)。与 malloc()不同,new 永远不会返回 NULL!
  因此你只要简单地写:
  Fred* p = new Fred(); // 不需要检查 p 是否为 NULL
  
G17.delete的NULL检查?
  不需要!
  C++担保,如果p等于NULL,则delete p不作任何事情,因此你不应该加上多余的 if 测试。
错误的:
  if (p != NULL)
  delete p;
正确的:
 delete p;

G18.new过程
  new Fred()是一个两步的过程:分配内存,然后调用构造函数
  使用void* operator new(size_t nbytes)函数分配sizeof(Fred) 字节的内存。该函数类似于malloc(size_t nbytes)。
  它通过调用Fred构造函数在内存中建立对象。第一步返回的指针被作为 this 参数传递给构造函数。这一步被包裹在一个块中以处理这步中抛出异常的情况。
  因此实际产生的代码可能是这样的:
  //原始代码:Fred* p = new Fred();
  Just like:
   Fred* p = (Fred*) operator new(sizeof(Fred));
   try {
    new(p) Fred(); // Placement new
   } catch (…) {
     operator delete(p); // 释放内存
     throw; // 重新抛出异常
   }
  可以看到,如果异常发生在p = new Fred()的 Fred 构造函数中, C++语言将进行相关处理,确保已分配的 sizeof(Fred)字节的内存会自动从堆中回收。

G19.delete过程
  delete p 是一个两步的过程:调用析构函数,然后释放内存。  delete p产生的代码看上去是这样的(假设是Fred*类型的):
  // 原始代码:delete p;
  Just like:
  if (p != NULL) {
     p->~Fred();
    operator delete(p);
  }
  p->~Fred() 语句调用 p 指向的Fred 对象的析构函数。
  operator delete(p) 语句调用内存释放函数void operator delete(void* p)。该函数类似free(void* p)。

G20.继承和组合
  组合:简单地创建一个包含已存在的类对象的新类,这称为组合,因为这个新类是由已存在类的对象组合的。对于新类的public接口函数,包含对嵌入对象的使用,但不必模仿这个嵌入对象的接口。
  继承:创建一个新类作为一个已存在类的类型,采取这个已存在类的形式,对它增加代码,但不修改它。
  组合通常在希望新类内部有已存在类性能时使用,而不希望已存在类作为它的接口。这就是说,嵌入一个计划用于实现新类性能的对象,而新类的用户看到的是新定义的接口而不是来自老类的接口。
  因为正在由一个已存在的类做一个新类,并且希望这个新类与已存在的类有严格相同的接口(希望增加任何我们想要加入的其他成员函数),所以能在已经用过这个已存在类的任何地方使用这个新类,这就是必须使用继承的地方。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

One2zeror

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值