حافظه پویا در ++C

درک مناسب از نحوه عملکرد حافظه پویا (داینامیک) کمک شایانی به برنامه نویسان ++C خواهد کرد. حافظه در برنامه ++C به دو بخش تقسیم خواهد شد.

  • Stack: همه متغیرهای تعریف شده درون تابع در حافظه stack ذخیره خواهند شد.
  • Heap: این بخش، حافظه استفاده نشده برنامه است و می‌توان در حین اجرای برنامه از آن برای تخصیص حافظه به صورت پویا استفاده کرد.

در بسیاری اوقات از ابتدا اطلاع دقیقی از میزان حافظه مورد نیاز برای ذخیره متغیرها در دسترس نیست و بنابراین می‌توان در زمان اجرا حافظه مورد نیاز را به آنها اختصاص داد.

در زمان اجرا، از حافظه heap می‌توان به متغیرهای داده شده، حافظه تخصیص داد. این کار با استفاده از یک عملگر ویژه که آدرس فضای اختصاص داده شده را برمی‌گرداند انجام می‌شود. این عملگر new است.

اگر به حافظه پویای اختصاص یافته دیگر نیازی نداشته باشید، می‌توانید با استفاده از عملگر delete آن را آزاد کنید.

عملگرهای new و delete

ساختار کلی برای استفاده از عملگر new برای تخصیص پویای حافظه به صورت زیر است.

new data-type;

در این عبارت، data-type می‌تواند هر نوع داده داخلی مانند آرایه یا هر نوع داده تعریف شده توسط کاربر مانند کلاس یا ساختار باشد. اجازه دهید با نوع داده داخلی شروع کنیم. برای مثال می‌توان یک اشاره‌گر به نوع double تعریف کرده و در زمان اجرا برای آن درخواست حافظه کنیم. می‌توان این کار را با استفاده از عملگر new انجام داد.

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

اگر حافظه آزاد کافی وجود نداشته باشد، فرآیند تخصیص حافظه ممکن است با شکست مواجه شود. بنابراین بهتر است بررسی کنیم که عملگر new اشاره‌گر NULL برگردانده یا نه و مطابق با آن عمل مناسب را در پیش گیریم.

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

تابع ()malloc از زبان C کماکان در ++C نیز قابل استفاده است، اما توصیه می‌شود که از آن استفاده نکنید. مزیت اصلی new نسبت به ()malloc این است که new نه تنها حافظه اختصاص می‌دهد، بلکه عمل ساخت شی، که از اهداف اولیه ++C بوده است را نیز انجام می‌دهد.

مطلب پیشنهادی:  اشاره‌گرها در ++C

هر زمان احساس کردید که دیگر نیازی به یک متغیر که حافظه آن به صورت داینامیکی اختصاص داده شده است ندارید، می‌توانید فضای تخصیص داده شده به آن را با عملگر delete آزاد کنید.

delete pvalue;        // Release memory pointed to by pvalue

اجازه دهید این مفهوم را با ارائه یک مثال و با نشان دادن نحوه عملکر new و delete روشن کنیم.

#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;
}

با اجرای کد بالا، خروجی زیر نتیجه می‌شود.

Value of pvalue : 29495

تخصیص حافظه پویا به آرایه‌ها

فرض کنید می‌خواهید برای یک آرایه از کارکترها، مثلاً 20 کارکتر، حافظه اختصاص دهید، با استفاده از ساختاری که در بالا استفاده کردیم می‌توان حافظه را به صورت داینامیکی اختصاص داد.

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

برای حذف آرایه‌ای که با دستور قبلی ایجاد کردیم از دستوری مانند دستور زیر استفاده می‌کنیم.

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

مطابق ساختار کلی عملگر new، می‌توان به یک آرایه چند بعدی حافظه اختصاص داد.

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

ساختار مورد استفاده برای آزاد کردن حافظه یک آرایه چند بعدی درست مانند حالت یک بعدی است.

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

تخصیص حافظه داینامیک به اشیا

اشیا تفاوتی با نوع داده‌های ساده ندارند. در مثال زیر برای روشن کردن این مفهوم از آرایه‌ای از اشیا استفاده کرده‌ایم.

#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;
}

اگر قرار بود به آرایه‌ای از چهار شی Box حافظه اختصاص دهیم، تابع سازنده معمولی چهار بار فراخوانده می‌شد و هنگام حذف کردن این اشیا، تخریب کننده به همان میزان فراخوانی می‌شد.

مطلب پیشنهادی:  اورلود کردن عملگرهای باینری در ++C

با اجرای کد فوق، نتیجه زیر حاصل می‌شود.

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

منبع: ترجمه از سایت tutorialspoint.com

در جلسه بعدی آموزش ++C با ما همراه باشید.

اگر این نوشته‌ برایتان مفید بود لطفا کامنت بنویسید.

مطالعه دیگر جلسات این آموزش<< جلسه قبلی                    جلسه بعدی >>

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *