在 C++ 中使用 malloc 与 new 的区别

Jinku Hu 2023年10月12日
  1. 在 C++ 中使用 new 操作符分配动态内存
  2. 使用 new 操作符和 std::unique_ptr 来分配 C++ 中的动态内存
  3. 使用 malloc 函数和 realloc/reallocarray 来分配动态内存
在 C++ 中使用 malloc 与 new 的区别

本文将讲解 C++ 中使用 mallocnew 分配内存的几种方法。

在 C++ 中使用 new 操作符分配动态内存

new 是 C++ 中直接管理动态内存的首选接口。它构造一个给定类型的对象并返回指向它的指针。使用 new 操作符分配的对象默认是初始化的,这意味着内置和复合类型的对象在使用前需要初始化垃圾值。

需要注意的是,new 可以用多种表示法来调用,以适应不同的需求,但在下面的例子中,我们分配的是大小为 10int 数组。因此,存储在 arr1 变量中的返回指针指向了 40 字节的内存块。initPrintIntVector 函数的实现只是为了更好地演示一个实际的编码例子。由于我们使用的是所谓的裸指针,所以在程序退出之前,用 delete 操作符释放分配的内存是很重要的。不过要注意,delete 后面的括号也是必要的,以释放数组中的每个位置。

#include <iomanip>
#include <iostream>
#include <random>
#include <vector>

using std::cout;
using std::endl;
using std::setw;
using std::vector;

constexpr int SIZE = 10;
constexpr int NEW_SIZE = 20;
constexpr int MIN = 1;
constexpr int MAX = 1000;

void initPrintIntVector(int *arr, const int &size) {
  std::random_device rd;
  std::default_random_engine eng(rd());
  std::uniform_int_distribution<int> distr(MIN, MAX);

  for (int i = 0; i < size; ++i) {
    arr[i] = distr(eng) % 1000;
    cout << setw(2) << arr[i] << "; ";
  }
  cout << endl;
}

int main() {
  int *arr1 = new int[SIZE];

  initPrintIntVector(arr1, SIZE);

  delete[] arr1;
  return EXIT_SUCCESS;
}

输出(*random):

 8; 380; 519; 536; 408; 666; 382; 244; 448; 165;

使用 new 操作符和 std::unique_ptr 来分配 C++ 中的动态内存

尽管 new 操作符似乎是一个很好的动态内存分配工具,但在具有密集内存操作的大型代码库中,它可能会变得相当容易出错。也就是说,在正确的时间对内存资源进行重新分配是一个相当困难的问题,而且大多会导致内存泄漏或意外的运行时错误。所以标准库从 C++ 11 版本开始,增加了智能指针,可以自动删除其指向的内存。std::unique_ptr 就是智能指针的一种,它只允许自己指向给定对象。需要注意的是,分配仍然是使用 new 操作符来完成的,在指针使用完毕后,我们可以不调用到 delete 就退出程序。

#include <iomanip>
#include <iostream>
#include <random>
#include <vector>

using std::cout;
using std::endl;
using std::setw;
using std::vector;

constexpr int SIZE = 10;
constexpr int NEW_SIZE = 20;
constexpr int MIN = 1;
constexpr int MAX = 1000;

void initPrintIntVector(int *arr, const int &size) {
  std::random_device rd;
  std::default_random_engine eng(rd());
  std::uniform_int_distribution<int> distr(MIN, MAX);

  for (int i = 0; i < size; ++i) {
    arr[i] = distr(eng) % 1000;
    cout << setw(2) << arr[i] << "; ";
  }
  cout << endl;
}

int main() {
  std::unique_ptr<int[]> arr2(new int[SIZE]);

  initPrintIntVector(arr2.get(), SIZE);

  return EXIT_SUCCESS;
}

输出:

985; 885; 622; 899; 616; 882; 117; 121; 354; 918;

使用 malloc 函数和 realloc/reallocarray 来分配动态内存

另一方面,C++ 代码可以调用原始的 C 式分配器函数-malloc,对于现代 C++ 标准来说,这是一种相当陈旧的动态内存操作方式。这并不是推荐的堆上分配对象的方式,但从好的方面来说,malloc 提供了更灵活的功能。

malloc 调用时只需要一个参数,指定 sizeof 对象,它返回的 void*应该投向 C++ 中的相应类型。malloc 分配的内存有一个优点,就是可以通过 reallocreallocarray 函数进行扩充/缩减。realloc 函数以对象的指针和新的大小作为参数,而 reallocarray 则以指针、元素数和每个元素的大小作为参数。需要注意的是,如果对象内存被扩充,旧的存储值保持不变,而新增加的元素则不被初始化。因此,下面的例子打印出扩展后的 arr3 元素只是为了演示,在实际程序中应该不会出现这种情况。

#include <iomanip>
#include <iostream>
#include <random>
#include <vector>

using std::cout;
using std::endl;
using std::setw;
using std::vector;

constexpr int SIZE = 10;
constexpr int NEW_SIZE = 20;
constexpr int MIN = 1;
constexpr int MAX = 1000;

void initPrintIntVector(int *arr, const int &size) {
  std::random_device rd;
  std::default_random_engine eng(rd());
  std::uniform_int_distribution<int> distr(MIN, MAX);

  for (int i = 0; i < size; ++i) {
    arr[i] = distr(eng) % 1000;
    cout << setw(2) << arr[i] << "; ";
  }
  cout << endl;
}

void printIntVector(int *arr, const int &size) {
  for (int i = 0; i < size; ++i) {
    cout << setw(2) << arr[i] << "; ";
  }
  cout << endl;
}

int main() {
  int *arr3 = static_cast<int *>(malloc(SIZE * sizeof(int)));
  //    int *arr3 = static_cast<int *>(malloc(SIZE * sizeof *arr3));
  //    int *arr3 = static_cast<int *>(malloc(sizeof(int[SIZE])));

  initPrintIntVector(arr3, SIZE);

  arr3 = static_cast<int *>(reallocarray(arr3, NEW_SIZE, sizeof(int)));
  // arr3 = static_cast<int *>(realloc(arr3, NEW_SIZE * sizeof(int)));
  printIntVector(arr3, NEW_SIZE);

  free(arr3);
  return EXIT_SUCCESS;
}

输出:

128; 346; 823; 134; 523; 487; 370; 584; 730; 268;
128; 346; 823; 134; 523; 487; 370; 584; 730; 268;  0;  0;  0;  0;  0;  0;  0;  0;  0;  0;
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 创始人。Jinku 在机器人和汽车行业工作了8多年。他在自动测试、远程测试及从耐久性测试中创建报告时磨练了自己的编程技能。他拥有电气/电子工程背景,但他也扩展了自己的兴趣到嵌入式电子、嵌入式编程以及前端和后端编程。

LinkedIn Facebook

相关文章 - C++ Memory