اشاره گرهای هوشمند (Smart Pointers) در زبان C++
در این بخش به بررسی مبحث اشاره گرهای هوشمند (Smart Pointers) در زبان C++ می پردازیم که به منظور جلوگیری از نشت حافظه (Memory Leak) در استاندارد C++11 معرفی شد.
نشت حافظه (Memory Leak)
یک برنامه سی پلاس پلاس مسئول بازگردانند تمام منابع گرفته شده به سیستم عامل است. عدم بازگشت منابع بلااستفاده به سیستم عامل نشت (Leak) نامیده می شود. این منابع تا زمانی که فرآیند برنامه در حال اجرا است، نمی توانند در اختیار سایر فرآیندها قرار بگیریند. به این موضوع اصطلاحا نشت حافظه گفته می شود و یکی از دلایل رایج بوجودن آمدن باگ در برنامه نویسی C-Style است.
اشاره گر هوشمند (Smart Pointer)
در زبان هایی مثل سی شارپ زمانی که منابعی از سیستم گرفته می شود، لازم نیست برنامه نویس در مورد بازگرداندن آن منابع کاری انجام دهد زیرا خود زبان شامل سیستمی به نام Garbage Collector است که مسئول مدیریت منابع گرفته شده است و به طور خودکار در زمان مناسب منابع گرفته شده را آزاد می کند. در زبان هایی مثل C++ شما باید خودتان منابع اختصاص داده شده را مدیریت کنید و این موضوع در برنامه های بزرگ کار آسانی نیست و عدم موفقیت در آزاد سازی منابع باعث بوجود آمدن مشکل نشت حافظه می شود. به کد زیر توجه کنید:
1 2 3 4 5 6 7 8 9 | /* NOT RECOMMENDED */ void using_raw_pointer() { // create a raw pointer SampleClass sample = new SampleClass(); sample->do_stuff(); // release allocated memory delete sample; } |
در کد فوق ابتدا حافظه مورد نیاز به شیء اختصاص داده شده است و بعد از انجام کارها حتما باید آن حافظه را آزاد کنیم. اگر فضای استفاده شده را آزاد نکنید، برای سایر فرآیند ها نیز غیرقابل استفاده خواهد بود. یعنی یک بخشی از حافظه که نه خودتان استفاده می کنید نه می گذارید سایر فرآیندها از آن استفاده کنند. حال اگر کد فوق را با استفاده از اشاره گرهای هوشنمد بنویسیم به این شکل خواهد بود:
1 2 3 4 5 6 7 8 9 10 | void using_smart_pointer() { // create a smart pointer std::unique_ptr<SampleClass> sample = std::make_unique<SampleClass>(constructor, parameters, here); // or std::unique_ptr<SampleClass> sample(new SampleClass(constructor, parameters, here)) // or auto sample = std::make_unique<SampleClass>(constructor, parameters, here); sample->do_stuff(); } |
همانطور که مشاهده می کنید، هیچ آزاد سازی حافظه ای توسط برنامه نویس انجام نمی شود و زمانی که از آن scope خارج شویم، به طور خودکار فضای اختصاص داده شده آزاد می شود.
انواع اشاره گرهای هوشمند
در زیر می توانید انواع اشاره گرهای هوشمند را به همراه یک توضیح مختصر مشاهده کنید:
- unique_ptr : اجازه می دهد فقط یک صاحب (owner) برای یک اشاره گر وجود داشته باشد. یعنی فقط یک owner می تواند به آن اشاره کند و قابل کپی و اشتراک گذاری نیست. البته امکان جا به جایی owner توسط تابع std::move وجود دارد.
- shared_ptr : زمانی استفاده می شود که بخواهید یک اشاره گر را به چندین owner اختصاص دهید. زمانی که آخرین owner از بین برود یا با استفاده از عملگر = یا تابع reset() یک اشاره گر دیگری به آن اختصاص داده شود، اشاره گر فعلی از بین می رود.
- weak_ptr : برای دسترسی به یک شیء که دارای یک یا چند owner ایجاد شده با shared_ptr است، استفاده می شود. weak_ptr تعداد owner ها را افزایش نمی دهد.
استفاده از اشاره گرهای هوشمند
اشاره گرهای هوشمند در هدر فایل memory و فضای نام std تعریف شده اند. بنابراین برای استفاده از آن ها باید هدر فایل مربوطه را include کنید. در مثال های زیر نحوه استفاده از اشاره گرهای هوشمند را می توانید مشاهده کنید.
نحوه استفاده از unique_ptr :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include <iostream> #include <memory> class SampleClass { public: SampleClass() { std::cout << "SampleClass constructor called." << std::endl; } ~SampleClass() { std::cout << "SampleClass destructor called." << std::endl; } void do_stuff() { std::cout << "SampleClass do_stuff() method called." << std::endl; } }; int main() { { std::unique_ptr<SampleClass> sample(new SampleClass()); sample->do_stuff(); } std::cout << "==================================" << std::endl; { std::unique_ptr<SampleClass> sample = std::make_unique<SampleClass>(); sample->do_stuff(); } std::cout << "==================================" << std::endl; { auto sample = std::make_unique<SampleClass>(); sample->do_stuff(); } /* { std::unique_ptr<SampleClass> sample = std::make_unique<SampleClass>(); // compile-time error std::unique_ptr<SampleClass> another_sample = sample; } */ std::cout << "==================================" << std::endl; { std::unique_ptr<SampleClass> sample = std::make_unique<SampleClass>(); std::unique_ptr<SampleClass> another_sample = std::move(sample); another_sample->do_stuff(); } return 0; } |
نحوه استفاده از shared_ptr :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <iostream> #include <memory> class SampleClass { public: SampleClass() { std::cout << "SampleClass constructor called." << std::endl; } ~SampleClass() { std::cout << "SampleClass destructor called." << std::endl; } void do_stuff() { std::cout << "SampleClass do_stuff() method called." << std::endl; } }; int main() { { std::shared_ptr<SampleClass> sample(new SampleClass()); sample->do_stuff(); } std::cout << "==================================" << std::endl; { std::shared_ptr<SampleClass> sample = std::make_shared<SampleClass>(); sample->do_stuff(); } std::cout << "==================================" << std::endl; { auto sample = std::make_shared<SampleClass>(); sample->do_stuff(); } std::cout << "==================================" << std::endl; std::shared_ptr<SampleClass> out_of_scope_sample; { std::shared_ptr<SampleClass> sample = std::make_shared<SampleClass>(); std::shared_ptr<SampleClass> another_sample = sample; another_sample->do_stuff(); out_of_scope_sample = another_sample; } out_of_scope_sample->do_stuff(); return 0; } |
نحوه استفاده از weak_ptr :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <iostream> #include <memory> std::weak_ptr<int> global_weak_pointer; void observe() { std::cout << "use_count == " << global_weak_pointer.use_count() << ": "; auto shared_pointer = global_weak_pointer.lock(); if (shared_pointer) { std::cout << *shared_pointer << "n"; } else { std::cout << "global_weak_pointer is expiredn"; } } int main() { { auto sample_shared_pointer = std::make_shared<int>(42); global_weak_pointer = sample_shared_pointer; observe(); } observe(); } |
هیچ نظری ثبت نشده است