C++学习笔记 11 new 关键字
一、new 关键字综述
new 关键字很有趣,因为它很深奥。很多人会使用new,但他们并没有真正去思考它。实际上当你编写C++程序的时候,你需要关心内存,性能和优化等问题。因为,如果你不考虑这些问题的话,那为什么还要用C++呢?有很多其他编程语言可以用,现在都2025年了,为什么还要用C++呢?除非你特别需要高性能,你特别关心发生的一切。那么弄明白new关键字就非常重要了。特别是如果你来自Java或C#这样为你自动清理内存的语言,但是这样在内存方面,你也就不会像在C++中有那么多的选择。对那些会使用C#和Java的人来说,他们总是使用new关键字。当他们使用C++时,可能回想,yeah,C++也没那么难嘛!这个new关键字也就是用来创建一个新的类对象的。NO,不是这样的。
new的主要目的是分配内存,具体来说就是在堆上分配内存。先写new,然后写上数据类型,可以是一个类,也可以是一个基本类型,又或者是一个数组,根据你写的类型,以字节为单位决定了要分配的内存的大小。比如你写new int,它会请求分配4个字节的内存。一旦有了那个数字,它会请求操作系统(应该说是C标准库),我需要4个字节的内存,请把它给我。这就是乐趣开始的地方。现在我们需要找到一个包含4个字节的连续内存块。当然,因为4个字节的内存很容易找到,所以分配起来也会很快。找到之后,它就返回一个指向那个内存地址的指针。这样你就可以开始使用你的数据了:存储或访问,或读、写都可以。你看,我刚列出了大概5步之类的东西,这就是主要内容。当你调用new的时候,这需要花费时间。
我说过,我们需要找到一个连续的4个字节,这并不是说我们在连续的搜索内存,就像激光扫过那样 :这里有没有四个字节的空闲空间,没有,OK,,再去搜索下个位置 。其实有一个叫空闲列表的东西,它会维护那些有空闲字节的地址。 这个过程没有你想的那么慢,但显然更加聪明,但仍然还是很 慢。这就是主要内容,new主要就是找到一个满足我们需求的足够大的内存块,然后给我们一个指向那个内存地址的指针。
new不紧分配内存空间,还调用了构造函数。

二、new关键字本质原理
new 实际上是一个操作符。首先你会发现它是一个操作符,new只是一个操作符,就像加、减、乘、除、等于一样,是个操作符。这意味着你可以重装这个操作符,并改变它的行为。很快我们就会讲到操作符重载。它就是一个函数,有一个size参数,返回值是一个void指针。
void指针就是一个没有类型的指针,指针就是一个内存地址。指针确实需要一个类型,他需要类型是为了你能够以想要的方式来操纵它。但核心概念就是:指针就是一个内存地址,它只是一个数字。所以它为什么需要一个特定类型呢,像int,double或者Entity等。
但是这里,new实际上做到事情,这实际上依赖于C++库。所以,如果你写自己的C++编译器和库,理论上你可以让它做任何事情。
但是,通常,调用new关键字,会调用底层C函数:malloc,它是用来分配内存的。
//以下2行内容理论上是一个性质
//这里不仅仅是分配了内存,还调用了构造函数
Entity* e = new Entity();
//C++ 需要强转,C不需要
Entity* e = (Entity*)malloc(sizeof(Entity));
三、new的对象必须手动delete
- delete只是一个常规函数
- delete实际上是调用了C函数的free函数,free可以释放malloc申请的内存
- delete也会调用析构函数:destructor
当我们使用new关键字的时候,内存没有被释放,它没有被标记为空闲,它就不会被放回空闲列表,因此当我们调用new再次申请内存空间时,这些内存就不能再被分配。直到我们调用delete,我们必须手动释放它。
有很多C++策略可以让这个过程自动化。一些简单的策略,比如基于作用域的指针;也有一些高级的策略,比如引用计数。

四、placement new
实际上没有分配内存,只是调用了构造函数,并在一个特定的内存地址上初始化了你的类对象。你可以写new(),然后指定内存地址:
placement new(定位new)是C++中一种特殊的内存管理机制,它允许在已经预先分配好的内存区域上构造对象,而不需要额外分配内存。
基本概念与语法
核心作用:placement new不负责分配内存,而是直接在指定的内存地址上调用对象的构造函数来初始化对象。这与普通new操作符(先分配内存再构造对象)不同。
语法格式:new (address) Type(initializer_list),其中address是已分配内存的指针,Type是对象类型,initializer_list是构造函数参数。
例如:char* buffer = new char[sizeof(int)]; int* p = new (buffer) int(42); 这会在buffer指向的内存上构造一个值为42的int对象。
使用场景
内存池管理: 在对象频繁创建和销毁的场景(如游戏引擎、高频交易系统)中,内存池预先分配大块内存,使用placement new在池中构造对象,避免频繁调用系统内存分配器,减少内存碎片。
性能优化: 当需要避免动态内存分配的开销时,例如容器(如vector)预留内存后,用placement new构造对象,实现内存分配与构造的解耦。
** 自定义内存管理:** 在嵌入式系统或对内存布局有严格要求的场景,placement new可用于在栈、静态内存或特定对齐的缓冲区上构造对象。

浙公网安备 33010602011771号