深入理解 C++ 动态内存管理:new vs malloc

概述
  1. new/delete 是 C++ 的关键字,需要编译器支持。malloc/free 是库函数,需要头文件支持。
  2. 使用 new 申请内存分配时无需指定内存块大小,编译器会自动计算。而 malloc 需要明确指定所需内存的大小。
  3. new 会返回对象类型的指针,类型安全。而 malloc 返回 void*,需要进行强制类型转换。
  4. new 分配内存失败时会抛出 std::bad_alloc 异常。malloc 分配内存失败时返回 NULL
  5. new 会调用构造函数,delete 会调用析构函数。malloc/free 只负责内存的分配和释放,不会调用构造或析构函数。
详细解释
  1. new/delete 是 C++ 的关键字,而 malloc/free 是标准库函数。

示例:

#include <iostream>
#include <cstdlib>  // for malloc and free

int main() {
    // 使用new关键字
    int* p1 = new int(5);   // 分配并初始化int
    delete p1;              // 删除并释放内存

    // 使用malloc/free函数
    int* p2 = (int*)malloc(sizeof(int));  // 分配内存,返回 void*
    *p2 = 5;                              // 初始化int
    free(p2);                             // 释放内存

    return 0;
}
  1. new 不需要指定内存块大小,而 malloc 需要明确指出大小。

示例:

#include <iostream>
#include <cstdlib>

int main() {
    // 使用new操作符分配内存,编译器自动计算所需内存大小
    int* p1 = new int[10];   // 分配10个int的数组
    delete[] p1;             // 使用delete[]释放数组内存

    // 使用malloc函数分配内存,需明确指定大小
    int* p2 = (int*)malloc(10 * sizeof(int));  // 分配10个int的数组
    free(p2);                                  // 使用free释放内存

    return 0;
}
  1. new 返回对象类型的指针,而 malloc 返回 void* 需要强制类型转换。

示例:

// 无需转换类型的情况
double* p1 = new double(3.14);  // 分配并初始化double
delete p1;                      // 删除内存

// 需要强制转换类型的情况
double* p2 = (double*)malloc(sizeof(double));  // 分配内存
*p2 = 3.14;                                    // 初始化
free(p2);                                      // 释放内存
  1. new 分配内存失败时抛异常,malloc 分配内存失败返回 NULL

示例:

#include <iostream>
#include <new>
#include <cstdlib>

int main() {
    try {
        int* p1 = new int[1000000000000];  // 可能抛出异常
        delete[] p1;
    } catch (std::bad_alloc& e) {
        std::cerr << "Memory allocation failed: " << e.what() << std::endl;
    }

    int* p2 = (int*)malloc(1000000000000 * sizeof(int));  // 可能返回NULL
    if (p2 == NULL) {
        std::cerr << "Memory allocation failed" << std::endl;
    } else {
        free(p2);
    }

    return 0;
}
  1. new 调用构造函数,delete 调用析构函数。

示例:

#include <iostream>
#include <cstdlib>

class MyClass {
public:
    MyClass() { std::cout << "Constructor called." << std::endl; }
    ~MyClass() { std::cout << "Destructor called." << std::endl; }
};

int main() {
    // 使用new,自动调用构造函数
    MyClass* obj1 = new MyClass();
    delete obj1;  // 自动调用析构函数

    // 使用malloc,必须手动调用构造和析构函数
    void* mem = malloc(sizeof(MyClass));
    MyClass* obj2 = new (mem) MyClass();  // 使用placement new 调用构造函数
    obj2->~MyClass();  // 手动调用析构函数
    free(mem);  // 释放内存

    return 0;
}

delete p; 与 delete[] p; 以及 allocator

  1. 动态数组管理中,new[] 要求数组大小为整数但不一定是常量,普通数组必须是常量。
  2. new 动态数组返回元素类型的指针,而不是数组类型。
  3. delete[] 会按逆序销毁数组中的元素。
  4. allocator 分开内存分配和对象构造,提供更灵活的对象管理。

示例:

#include <iostream>
#include <memory>  // for std::allocator

class MyClass {
public:
    MyClass() { std::cout << "Constructor called." << std::endl; }
    ~MyClass() { std::cout << "Destructor called." << std::endl; }
};

int main() {
    // 使用new和delete[]管理动态数组
    MyClass* arr = new MyClass[3];  // 分配数组并调用构造函数
    delete[] arr;  // 逆序调用析构函数并释放内存

    // 使用allocator分配内存和构造对象
    std::allocator<MyClass> alloc;
    MyClass* mem = alloc.allocate(3);  // 分配未初始化内存
    alloc.construct(mem, MyClass());  // 默认初始化第一个对象
    alloc.construct(mem + 1, MyClass());  // 默认初始化第二个对象
    alloc.construct(mem + 2, MyClass());  // 默认初始化第三个对象

    // 销毁对象和释放内存
    alloc.destroy(mem);
    alloc.destroy(mem + 1);
    alloc.destroy(mem + 2);
    alloc.deallocate(mem, 3);

    return 0;
}

结论

以上示例和解释展示了 new/delete 与 malloc/free 在 C++ 中的不同以及正确使用方法。通过学习和理解这些内容,可以更好地管理动态内存,提高程序的安全性和稳定性。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值