Bộ nhớ động C ++

Hiểu rõ về cách bộ nhớ động thực sự hoạt động trong C ++ là điều cần thiết để trở thành một lập trình viên C ++ giỏi. Bộ nhớ trong chương trình C ++ của bạn được chia thành hai phần:

  • The stack - Tất cả các biến được khai báo bên trong hàm sẽ chiếm bộ nhớ từ ngăn xếp.

  • The heap - Đây là bộ nhớ không sử dụng của chương trình và có thể được sử dụng để cấp phát động bộ nhớ khi chương trình chạy.

Nhiều khi bạn không biết trước mình sẽ cần bao nhiêu bộ nhớ để lưu trữ thông tin cụ thể trong một biến xác định và kích thước bộ nhớ cần thiết có thể được xác định tại thời điểm chạy.

Bạn có thể cấp phát bộ nhớ tại thời điểm chạy trong heap cho biến của một kiểu nhất định bằng cách sử dụng một toán tử đặc biệt trong C ++ trả về địa chỉ của không gian được cấp phát. Toán tử này được gọi lànew nhà điều hành.

Nếu bạn không cần bộ nhớ được cấp phát động nữa, bạn có thể sử dụng delete toán tử, loại bỏ cấp phát bộ nhớ đã được cấp phát trước đó bởi toán tử mới.

mới và xóa toán tử

Có cú pháp chung sau đây để sử dụng new toán tử để cấp phát bộ nhớ động cho bất kỳ kiểu dữ liệu nào.

new data-type;

Đây, data-typecó thể là bất kỳ kiểu dữ liệu tích hợp nào bao gồm một mảng hoặc bất kỳ kiểu dữ liệu nào do người dùng xác định bao gồm lớp hoặc cấu trúc. Hãy để chúng tôi bắt đầu với các kiểu dữ liệu tích hợp sẵn. Ví dụ, chúng ta có thể định nghĩa một con trỏ để gõ double và sau đó yêu cầu cấp phát bộ nhớ tại thời điểm thực thi. Chúng tôi có thể làm điều này bằng cách sử dụngnew toán tử với các câu lệnh sau:

double* pvalue  = NULL; // Pointer initialized with null
pvalue  = new double;   // Request memory for the variable

Bộ nhớ có thể đã không được cấp phát thành công, nếu bộ nhớ miễn phí đã được sử dụng hết. Vì vậy, bạn nên kiểm tra xem toán tử mới có trả về con trỏ NULL hay không và thực hiện hành động thích hợp như sau:

double* pvalue  = NULL;
if( !(pvalue  = new double )) {
   cout << "Error: out of memory." <<endl;
   exit(1);
}

Các malloc()hàm từ C, vẫn tồn tại trong C ++, nhưng bạn nên tránh sử dụng hàm malloc (). Ưu điểm chính của new so với malloc () là new không chỉ cấp phát bộ nhớ mà còn xây dựng các đối tượng là mục đích chính của C ++.

Tại bất kỳ thời điểm nào, khi bạn cảm thấy một biến đã được cấp phát động không còn cần thiết nữa, bạn có thể giải phóng bộ nhớ mà nó chiếm trong kho lưu trữ miễn phí bằng toán tử 'delete' như sau:

delete pvalue;        // Release memory pointed to by pvalue

Hãy để chúng tôi đặt các khái niệm ở trên và tạo thành ví dụ sau để cho thấy cách hoạt động của 'mới' và 'xóa' -

#include <iostream>
using namespace std;

int main () {
   double* pvalue  = NULL; // Pointer initialized with null
   pvalue  = new double;   // Request memory for the variable
 
   *pvalue = 29494.99;     // Store value at allocated address
   cout << "Value of pvalue : " << *pvalue << endl;

   delete pvalue;         // free up the memory.

   return 0;
}

Nếu chúng tôi biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Value of pvalue : 29495

Phân bổ bộ nhớ động cho mảng

Hãy xem xét bạn muốn cấp phát bộ nhớ cho một mảng ký tự, tức là chuỗi 20 ký tự. Sử dụng cùng một cú pháp mà chúng ta đã sử dụng ở trên, chúng ta có thể cấp phát bộ nhớ động như hình dưới đây.

char* pvalue  = NULL;         // Pointer initialized with null
pvalue  = new char[20];       // Request memory for the variable

Để xóa mảng mà chúng ta vừa tạo, câu lệnh sẽ giống như sau:

delete [] pvalue;             // Delete array pointed to by pvalue

Theo cú pháp chung tương tự của toán tử new, bạn có thể phân bổ cho một mảng nhiều chiều như sau:

double** pvalue  = NULL;      // Pointer initialized with null 
pvalue  = new double [3][4];  // Allocate memory for a 3x4 array

Tuy nhiên, cú pháp giải phóng bộ nhớ cho mảng đa chiều sẽ vẫn giống như trên:

delete [] pvalue;            // Delete array pointed to by pvalue

Phân bổ bộ nhớ động cho các đối tượng

Các đối tượng không khác gì các kiểu dữ liệu đơn giản. Ví dụ: hãy xem xét đoạn mã sau, nơi chúng ta sẽ sử dụng một mảng các đối tượng để làm rõ khái niệm:

#include <iostream>
using namespace std;

class Box {
   public:
      Box() { 
         cout << "Constructor called!" <<endl; 
      }
      ~Box() { 
         cout << "Destructor called!" <<endl; 
      }
};
int main() {
   Box* myBoxArray = new Box[4];
   delete [] myBoxArray; // Delete array

   return 0;
}

Nếu bạn phân bổ một mảng gồm bốn đối tượng Box, hàm tạo Đơn giản sẽ được gọi bốn lần và tương tự khi xóa các đối tượng này, hàm hủy cũng sẽ được gọi cùng một số lần.

Nếu chúng tôi biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!