跳转到内容

C++ new 运算符

来自代码酷


C++ new运算符是C++中用于动态内存分配的核心操作符,它允许程序在运行时从堆(heap)中请求内存空间。与C语言的malloc()不同,new不仅分配内存,还会调用对象的构造函数,是面向对象内存管理的关键工具。

基本语法与功能[编辑 | 编辑源代码]

new运算符的基本语法如下:

pointer_variable = new data_type;
pointer_variable = new data_type[size]; // 数组分配
pointer_variable = new data_type(initial_value); // 带初始化

工作原理[编辑 | 编辑源代码]

当使用new时,会发生以下步骤:

  1. 计算所需内存大小
  2. 在堆上寻找连续可用空间
  3. 调用构造函数(对于类对象)
  4. 返回指向该内存的首地址指针

graph TD A[调用new] --> B[计算内存大小] B --> C[堆空间分配] C --> D[调用构造函数] D --> E[返回指针]

基础示例[编辑 | 编辑源代码]

单对象分配[编辑 | 编辑源代码]

#include <iostream>

int main() {
    int* ptr = new int;    // 分配一个int空间
    *ptr = 42;             // 存储值
    std::cout << *ptr;     // 输出: 42
    delete ptr;            // 必须手动释放
    return 0;
}

数组分配[编辑 | 编辑源代码]

double* arr = new double[10]; // 分配10个double的数组
arr[0] = 3.14;               // 访问第一个元素
delete[] arr;                // 必须使用delete[]

高级特性[编辑 | 编辑源代码]

定位new(Placement new)[编辑 | 编辑源代码]

允许在已分配的内存上构造对象:

#include <new>

char buffer[sizeof(int)];
int* p = new (buffer) int(42); // 在buffer位置构造int
// 不需要delete,因为是栈内存

异常处理[编辑 | 编辑源代码]

默认情况下,new失败会抛出std::bad_alloc异常:

try {
    int* p = new int[10000000000];
} catch (const std::bad_alloc& e) {
    std::cerr << "内存不足: " << e.what();
}

可以使用nothrow版本:

int* p = new(std::nothrow) int[100];
if (!p) { /* 处理分配失败 */ }

数学原理[编辑 | 编辑源代码]

new操作的时间复杂度通常为O(1),但实际性能取决于内存分配器的实现。连续分配n个对象的空间需求为:

i=1nsizeof(Ti)+开销

其中开销包括内存对齐填充和管理信息。

实际应用案例[编辑 | 编辑源代码]

动态数据结构[编辑 | 编辑源代码]

实现链表节点分配:

struct Node {
    int data;
    Node* next;
};

Node* createNode(int value) {
    Node* newNode = new Node;
    newNode->data = value;
    newNode->next = nullptr;
    return newNode;
}

工厂模式[编辑 | 编辑源代码]

class Shape {
public:
    virtual void draw() = 0;
    static Shape* create(int type);
};

Shape* Shape::create(int type) {
    switch(type) {
        case 1: return new Circle();
        case 2: return new Square();
        default: return nullptr;
    }
}

最佳实践[编辑 | 编辑源代码]

  • 总是检查分配是否成功(特别是大型分配)
  • 每个new必须对应一个delete
  • 数组使用delete[]释放
  • 优先使用智能指针(如std::unique_ptr)管理动态内存
  • 避免在频繁调用的代码路径中使用new/delete

常见问题[编辑 | 编辑源代码]

内存泄漏[编辑 | 编辑源代码]

忘记释放内存是最常见错误:

void leak() {
    int* p = new int(10);
    // 忘记delete p
} // 内存永久丢失

悬垂指针[编辑 | 编辑源代码]

int* p = new int(5);
delete p;
*p = 10; // 未定义行为!

性能考虑[编辑 | 编辑源代码]

new操作涉及系统调用,比栈分配慢得多。典型对比:

barChart title 分配速度比较 x-axis 分配方式 y-axis 时间(ns) bar 栈分配: 1 bar new操作: 100

与malloc()的区别[编辑 | 编辑源代码]

特性 new malloc()
调用构造函数
返回类型 类型安全指针 void*
失败处理 异常或nothrow 返回NULL
大小计算 自动 需手动计算

扩展阅读[编辑 | 编辑源代码]

  • C++17引入的带对齐分配的new:align_val_t
  • 重载类特定的new/delete运算符
  • 内存池技术优化频繁分配

模板:C++内存管理导航