在 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