我们都知道new是用来在程序运行过程中为变量临时分配内存的C++关键字,那它跟C语言中的malloc有什么区别呢,相比之下又为什么推荐使用new呢

c++
throwing() void* operator new (std::size_t size);
nothrow() void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) noexcept;
placement() void* operator new (std::size_t size, void* ptr) noexcept;
<stdlib.h>
void *malloc(size_t size);

1. 申请的内存所在位置

operator new 从自由存储区上为对象动态分配内存空间,而 malloc 从堆上动态分配内存。

自由存储区是C++基于 operator new 的抽象概念,凡是通过 operator new 申请的内存,即为自由存储区。而堆是计算机操作系统的术语,是操作系统所维护的一块特殊内存,用于程序内存动态分配,C语言使用 malloc 从堆上分配内存,

使用 free 释放已分配的相应内存。

那么 new 是否能在堆上动态分配内存呢?这取决于 operator new 的实现细节,自由存储区不仅可以是堆,还可以是静态存储区,这都看  operator new 在哪里为对象分配内存。 new 甚至可以不为对象分配内存!

new (place_address) type

place_address 是一个指针,代表一块内存地址。当仅以一个地址调用 new 操作符时, new 操作符会调用特殊的 operator new ,也就是上面的 palcement()

void* operator new (std::size_t size, void *ptr); // 此版本的operator new不允许重载

这个 operator new 不分配任何内存,只是简单地返回指针实参,然后由 new 表达式负责在  place_address  指定的地址进行对象的初始化工作。

2. 返回类型安全性

operator new 内存分配成功时,返回对象类型的指针,无须进行类型转换,因此是符合类型安全性的操作符。而 malloc 内存分配成功返回  (void *)  ,需要通过强制类型转换转换成我们需要的类型。

3. 内存分配失败时的返回值

new 内存分配失败时,会抛出  bac_alloc exception ,它不会返回 NULL ; malloc 分配内存失败时返回 NULL 

使用C语言时,我们习惯在 malloc 分配内存后判断分配是否成功

int *a = (int *)malloc(sizeof(int));
if (a == NULL) {
// ...
} else {
// ...
}

有时候在写C++程序时我们可能按照C语言的习惯来写,int *a = new int(); if (a == NULL) { // ... } else { // ... } , 实际上这样做没有一点意义,因为 new 根本不会返回 NULL ,程序能够执行到if说明内存已经分配成功,否则早就抛异常了。正确的做法是使用异常机制

try {
int *a = new int();
} catch (bac_alloc) {
// ...
}

4. 是否需要指定内存大小

使用 new 操作符申请内存时无须指定内存块大小,编译器会根据类型信息自行计算,而 malloc 则需要显式地指出所需内存大小。

malloc 仅仅分配内存, free 仅仅回收内存,而且是以字节为单位进行内存操作,并不执行构造和析构函数; new 可以调用对象的构造函数, delete 可以调用相应的析构函数,以具体类型为单位进行内存分配与释放。

class A {
public:
A() {}
~A() {}
}
A *ptr_new = new A;
A *ptr_malloc = (A *)malloc(sizeof(A)); // 当然这里使用malloc来为我们自定义类型分配内存其实并不怎么合适。

5. 是否调用构造/析构函数

使用  operator new  操作符来分配对象内存时会经历三个步骤:

  1. 调用  operator new  函数(对于数组是  operator new[]  )分配一块足够大的、原始的、未命名的内存空间。
  2. 编译器运行相应的构造函数以构造指定类型的对象并初始化。
  3. 对象构造完成后,返回一个指向该对象的指针。

使用  operator delete 操作符来释放对象内存时会经历两个步骤:

  1. 调用对象的析构函数。
  2. 编译器调用  operator delete  (或  operator delete[]  )函数释放内存空间。

总之来说 new/delete 会调用对象的构造函数/析构函数以完成对象的构造/析构,而 malloc/free 不会。

malloc 不具备内存初始化的特性,而 new 在申请单个类型变量时可进行初始化 。

6. 对数组的处理

C++ 提供了 new[] / delete[] 专门处理数组类型

A *ptr_single new A;
A *ptr_arr = new A[];
delete ptr_single;
delete[] ptr_arr;

new 对数组的支持体现在它会对每一个数组元素分别调用构造函数进行初始化,释放对象时为每个对象调用析构函数。注意 delete[] 要与 new[] 配套使用,不然会出现数组对象部分释放的现象,造成内存泄漏。

而 malloc 并不知道你在这块内存上要放的数组还是单个数据,反正它就给你一块原始内存,返回一个内存的地址。所以如果要动态分配一个数组的内存,需要我们手动指定数组大小

int * ptr = (int *)malloc(sizeof(int) * );

7. new与malloc是否可以相互调用

operator new/operator delete 的实现可以基于 malloc  ,但  malloc  的实现不可以调用  new 。

malloc/free  是C语言提供的标准库函数,使用时要包含头文件,在 C/C++ 中通用,可以覆盖;

// for C
#include <stdlib.h> // for C++
#include <cstdlib>

new/delete 是运算符,也是关键字,是C++的一部分,只能在C++中使用,并且可以重载。

void * operator new (sieze_t size)
{
if(void * mem = malloc(size)
return mem;
else
throw bad_alloc();
}
void operator delete(void *mem) noexcept
{
free(mem);
}

8.是否可以被重载

opeartor new / operator delete 可以被重载。标准库是定义了 operator new / operator delete 的12个重载版本

// new
throwing () void* operator new (std::size_t size);
nothrow () void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) noexcept;
placement () void* operator new (std::size_t size, void* ptr) noexcept; throwing () void* operator new[] (std::size_t size);
nothrow () void* operator new[] (std::size_t size, const std::nothrow_t& nothrow_value) noexcept;
placement () void* operator new[] (std::size_t size, void* ptr) noexcept; // delete
ordinary () void operator delete (void* ptr) noexcept;
nothrow () void operator delete (void* ptr, const std::nothrow_t& nothrow_constant) noexcept;
placement () void operator delete (void* ptr, void* voidptr2) noexcept; ordinary () void operator delete[] (void* ptr) noexcept;
nothrow () void operator delete[] (void* ptr, const std::nothrow_t& nothrow_constant) noexcept;
placement () void operator delete[] (void* ptr, void* voidptr2) noexcept;

我们可以自定义上面函数中的任意一个,前提是自定义版本必须位于全局作用域或者类作用域中。而 malloc/free 并不允许重载。

9. 是否能够直观地重新分配内存

使用 malloc 分配的内存后,如果在使用过程中发现内存不足,可以使用 realloc 函数进行内存重新分配实现内存的扩充。

realloc 先判断当前的指针所指内存是否有足够的连续空间,如果有,原地扩大可分配的内存地址,并且返回原来的地址指针;否则先按照新指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,然后释放原来的内存区域。

new 没有这样直观的配套设施来扩充内存。

10. 是否能够自定义如何处理内存分配不足

在  operator new  抛出异常之前会先调用一个用户指定的错误处理函数,即  new-handler ,这是一个指针类型,指向一个没有参数没有返回值的函数——错误处理函数。

namespace std{
typedef void (*new_handler)();
}

为了指定错误处理函数,用户需要调用  set_new_handler  这是一个声明于std命名空间的标准库函数 namespace std{ new_handler set_new_handler(new_handler p) throw(); }

namespace std{
new_handler set_new_handler(new_handler p) throw();
}

set_new_handler  的参数为  new_handler  指针,指向  operator new  无法分配足够内存时该调用的函数。其返回值也是个指针,指向  set_new_handler  被调用前正在执行(但马上就要发生替换)的那个  new_handler  函数。

对于 malloc ,用户并不能够去编程决定内存不足以分配时如何操作,只能看着 malloc 返回 NULL 。

C++之new关键字的更多相关文章

  1. 作为一个新手的Oracle(DBA)学习笔记【转】

    一.Oracle的使用 1).启动 *DQL:数据查询语言 *DML:数据操作语言 *DDL:数据定义语言 DCL:数据控制语言 TPL:事务处理语言 CCL:指针控制语言 1.登录 Win+R—cm ...

  2. JavaScript var关键字、变量的状态、异常处理、命名规范等介绍

    本篇主要介绍var关键字.变量的undefined和null状态.异常处理.命名规范. 目录 1. var 关键字:介绍var关键字的使用. 2. 变量的状态:介绍变量的未定义.已定义未赋值.已定义已 ...

  3. java面向对象中的关键字

    1,super关键字 super:父类的意思 1. super.属性名 (调用父类的属性) 2. super.方法名 (调用父类的方法) 3. super([参数列表])(调用父类的构造方法) 注意: ...

  4. 关于javascript中的this关键字

    this是非常强大的一个关键字,但是如果你不了解它,可能很难正确的使用它. 下面我解释一下如果在事件处理中使用this. 首先我们讨论一下下面这个函数中的this关联到什么. function doS ...

  5. transient关键字的用法

    本篇博客转自 一直在路上 Java transient关键字使用小记 1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,Java ...

  6. Java关键字:static

    通常,当创建类时,就是在描述那个类的外观和行为.只有用new创建类的对象时,才分配数据存储空间,方法才能被调用.但往往我们会有下面两种需求: 1.我想要这样一个存储空间:不管创建多少对象,无论是不创建 ...

  7. Core Java 总结(关键字,特性问题)

    2016-10-19 说说&和&&的区别 初级问题,但是还是加入了笔记,因为得满分不容易. &和&&都可以用作逻辑与的运算(两边是boolean类型), ...

  8. Net中的常见的关键字

    Net中的关键字有很多,我们最常见的就有new.base.this.using.class.struct.abstract.interface.is.as等等.有很多的,在这里就介绍大家常见的,并且有 ...

  9. php多关键字查询

      php单一关键字查询 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 tdansitional//EN" "http: ...

  10. Keil> 编译器特有的功能 > 关键字和运算符 > __weak

    __weak 此关键字指示编译器弱导出符号. 可以将 __weak 关键字应用于函数和变量声明以及函数定义. 用法 函数和变量声明 对于声明,此存储类指定一个 extern 对象声明,即使不存在,也不 ...

随机推荐

  1. 基于 Vue3.0 Composition Api 快速构建实战项目

    Quick Start 项目源码:https://github.com/Wscats/vue-cli 本项目综合运用了 Vue3.0 的新特性,适合新手学习

  2. java this,super简单理解

    *****this****** 表示对当前对象的引用. 作用:1.区分实例变量和局部变量(this.name----->实例变量name) 2.将当前对象当做参数传递给其它对象和方法.利用thi ...

  3. SpringBoot写一个登陆注册功能,和期间走的坑

    文章目录 前言 1. 首先介绍项目的相关技术和工具: 2. 首先创建项目 3. 项目的结构 3.1实体类: 3.2 Mapper.xml 3.3 mapper.inteface 3.4 Service ...

  4. Java数组与C/C++数组的区别

    C数组一维数组: 定义方式:datatype arrayname[length]数组是一个整体,在内存中是连续的: 初始化:1:可以只给部分赋值int a[5] = {1,2}; 剩下的自动赋值为02 ...

  5. PAT(甲级)2017年秋季考试

    PAT(甲级)2017年秋季考试 D题红黑树待补21/30 大佬的代码,看着想哭,这才是艺术啊 A Cut Integer 模拟题 #include<bits/stdc++.h> usin ...

  6. 新一代数据安全的制胜法宝-UBA

    [摘要]在入侵防御领域,运用数据分析的方法保护数据的技术其实没有什么新的东西,比如防火墙-分析数据包的内容以及其他的元数据,如IP地址,从增长的数据条目中检测和阻断攻击者:防病毒软件不断的扫描文件系统 ...

  7. 洛谷 题解 CF1151D 【Stas and the Queue at the Buffet】

    本蒟蒻又双叒叕被爆踩辣!!! 题目链接 这道题我个人觉得没有紫题的水平. 步入正题 先看题: 共有n个人,每个人2个属性,a,b; 窝们要求的是总的不满意度最小,最满意度的公式是什么? \(ai * ...

  8. 显示cifar图片

    # coding:utf-8 import numpy as np import matplotlib.pyplot as plt import pickle FILE_PATH = r"D ...

  9. Selenium之勾选框操作

    勾选框操作:       所谓勾选框,意思是可以勾选一个及以上或全部勾选.勾选框的图标一般都是方形的. 复选框勾选一般分为三种情况: ①勾选单个框,我们直接用元素定位的方式定位到点击即可. ②勾选多个 ...

  10. 使用iCamera 测试MT9M001 130w高分辨率摄像头说明

    该摄像头默认分辨率为1280*1024,即不设置任何寄存器参数,只要给该模块提供时钟,就可以输出. 在这里 我们可以通过右侧寄存器栏动态调整各寄存器 观察效果. 0x09寄存器可以调整曝光值,可以根据 ...