auto কিওয়ার্ডC++-এ auto কিওয়ার্ডটি C++11-এ যোগ হওয়া একটি শক্তিশালী ফিচার, যা দিয়ে অনুমিত ডেটা টাইপের ভ্যারিয়েবল ঘোষণা করা যায়।
কম্পাইলার ভ্যারিয়েবলটির ইনিশিয়ালাইজার দেখে তার টাইপ অনুমান করে, ফলে কোড আরও পাঠযোগ্য ও রক্ষণাবেক্ষণযোগ্য হয়ে ওঠে।
নিচের উদাহরণটি দেখুন, যেখানে auto দিয়ে ভ্যারিয়েবল ঘোষণা করা হয়েছে:
auto dragon_population{3}; // dragon_population is deduced as an integer
auto westeros{7.7777}; // westeros is deduced as a double
auto wedding_location{"The Twins"}; // wedding_location is deduced as a const char*, not std::string
প্রতিটি ক্ষেত্রেই ভ্যারিয়েবলের টাইপ তার যে মান দিয়ে আরম্ভ করা হয়েছে সেখান থেকেই অনুমান করা হয়।
auto কিওয়ার্ড স্পষ্ট টাইপ লেখার বাহুল্য কমিয়ে কোড আরও সংক্ষিপ্ত ও পাঠযোগ্য করতে সাহায্য করে।
const std::vector<std::string> pigeon_pie{"flour", "butter", "pigeon", "salt"};
auto purple_wedding_pie{pigeon_pie};
purple_wedding_pie.emplace_back("the strangler");
এই লুপে auto purple_wedding_pie-এর টাইপ std::vector<std::string> হিসেবে অনুমান করে, ফলে টাইপটি আবার আলাদা করে লিখতে হয় না।
auto কিওয়ার্ড C++-এর নানা কনস্ট্রাক্টের সাথে সামঞ্জস্যপূর্ণ, যা এটিকে আধুনিক C++ প্রোগ্রামিংয়ে একটি বহুমুখী টুলে পরিণত করেছে।
auto& element{array[0]}; // reference to an element
const auto object{otherObject}; // const type version of otherObject's type
auto* ptr{&x}; // pointer to x with the same type as x, but as a pointer.
পরবর্তী কনসেপ্টে আমরা প্রায়ই auto কিওয়ার্ডটি ল্যাম্বডা এক্সপ্রেশন, রেঞ্জ-ভিত্তিক for লুপ আর ইটারেটরের সাথে দেখব।
স্মার্ট পয়েন্টার হলো আধুনিক C++-এর একটি ফিচার, যা স্বয়ংক্রিয় মেমরি ম্যানেজমেন্টের সুবিধা দিতে তৈরি, এবং যা সাধারণত র' পয়েন্টারের সাথে যুক্ত মেমরি লিক ও ড্যাঙ্গলিং পয়েন্টার প্রতিরোধে সাহায্য করে। এগুলো র' পয়েন্টারের চারপাশে র্যাপার হিসেবে কাজ করে এবং পয়েন্টারটির আর প্রয়োজন না হলে স্বয়ংক্রিয়ভাবে মেমরি মুক্ত করা জাতীয় অতিরিক্ত কার্যকারিতা যোগ করে।
স্মার্ট পয়েন্টার সাধারণত C++ স্ট্যান্ডার্ড লাইব্রেরিতে ক্লাস টেমপ্লেট হিসেবে তৈরি করা হয়।
সবচেয়ে বেশি ব্যবহৃত দুটি স্মার্ট পয়েন্টার হলো std::unique_ptr ও std::shared_ptr।
std::unique_ptr একটি স্মার্ট পয়েন্টার, যা অবজেক্টটির একচেটিয়া মালিকানা রাখে।
এটি নিশ্চিত করে যে যেকোনো সময়ে কেবল একটি std::unique_ptr অবজেক্টই রিসোর্সটির মালিক থাকে।
মালিকানা রাখা std::unique_ptr ধ্বংস বা রিসেট হলে এটি স্বয়ংক্রিয়ভাবে অবজেক্টগুলো ধ্বংস করে এবং তার মেমরি মুক্ত করে।
#include <memory>
// Declaring and defining a unique pointer
auto rightful_king_of_england = std::make_unique<std::string>("Excalibur");
// Unique pointers cannot be copied or assigned
auto mordred = rightful_king_of_england; // Error: Cannot copy a unique_ptr
std::make_unique()-এর সুবিধাএকটি std::unique_ptr তৈরি করার সময় সরাসরি new দিয়ে মেমরি অ্যালোকেট করার বদলে std::make_unique() ব্যবহার করাই ভালো।
std::make_unique() কয়েকটি সুবিধা দেয়:
std::make_unique() এক্সেপশন সেফটির নিশ্চয়তা দেয়।
অবজেক্ট তৈরির সময় কোনো এক্সেপশন ছোড়া হলে মেমরি স্বয়ংক্রিয়ভাবে মুক্ত হয়ে যায়, ফলে মেমরি লিক প্রতিরোধ হয়।std::make_unique() ব্যবহার করলে কোড আরও স্পষ্ট ও সংক্ষিপ্ত হয়।
টেমপ্লেট আর্গুমেন্ট স্বয়ংক্রিয়ভাবে অনুমান করা হয় বলে কোন টাইপ অ্যালোকেট হচ্ছে তা আর আলাদা করে লিখতে হয় না।new দিয়ে মেমরি অ্যালোকেট করার তুলনায় কম্পাইলার std::make_unique()-কে আরও কার্যকরভাবে অপটিমাইজ করার সুযোগ পায়, যার ফলে পারফরম্যান্স উন্নত হতে পারে।std::unique_ptr হাতে হাতে তৈরি করা হলে এর অন্তর্নিহিত রিসোর্সটি ডিলিট করা সম্ভব হয়ে পড়ে।
আর স্কোপের শেষে std::unique_ptr যখন সেটি ডিলিট করার চেষ্টা করে, তখন সেটি আনডিফাইন্ড বিহেভিয়ারের দিকে নিয়ে যায়।std::shared_ptr একটি স্মার্ট পয়েন্টার, যা একাধিক std::shared_ptr অবজেক্টকে একই রিসোর্সের মালিকানা ভাগ করে নিতে দেয়।
কতগুলো শেয়ার্ড পয়েন্টার রিসোর্সটির রেফারেন্স রাখছে তা এটি হিসাব রাখে, এবং রিসোর্সটির মালিকানা রাখা শেষ শেয়ার্ড পয়েন্টারটি স্কোপের বাইরে চলে গেলে বা রিসেট হলে তবেই মেমরি মুক্ত করে।
// Declaring and defining a shared pointer to a dynamically allocated string
auto martian_congressional_republic = std::make_shared<std::string>("protomolecule");
// Creating more shared pointer that shares ownership
auto outer_planets_alliance = martian_congressional_republic;
auto united_nations = martian_congressional_republic;
C++17 ও তার নিচের ভার্সনে std::make_shared<T[]>-এর মাধ্যমে std::shared_ptr-কে অ্যারের সাথে ব্যবহার করা সরাসরি সমর্থিত নয়।
std::make_shared<T[]> দিয়ে অ্যারে অ্যালোকেট করা সম্ভব হলেও, সেগুলো থেকে সরাসরি শেয়ার্ড পয়েন্টার তৈরি করলে আনডিফাইন্ড বিহেভিয়ার দেখা দিতে পারে, কারণ একক অবজেক্ট আর অ্যারের মেমরি ম্যানেজমেন্টে পার্থক্য রয়েছে।
বদলে, শেয়ার্ড পয়েন্টার দিয়ে অ্যারে কার্যকরভাবে ম্যানেজ করতে std::vector বা কাস্টম ডিলিশন ফাংশন ব্যবহার করার কথা ভাবুন।
C++17-এ অ্যারে অ্যালোকেশন ও শেয়ার্ড পয়েন্টার নিয়ে কাজ করার সময় সবসময় আপনার কম্পাইলার ও স্ট্যান্ডার্ড লাইব্রেরি ইমপ্লিমেন্টেশনের সাথে সামঞ্জস্য নিশ্চিত করুন।
std::make_shared()-এর সুবিধাstd::make_unique()-এর মতোই std::make_shared() উন্নত মেমরি এফিশিয়েন্সি, এক্সেপশন সেফটি আর পাঠযোগ্যতার মতো সুবিধা দেয়।
এটি কন্ট্রোল ব্লক ও ম্যানেজড অবজেক্টের জন্য মেমরি অ্যালোকেশনকে একটিমাত্র কাজে মিলিয়ে দেয়, ফলে দক্ষতা বাড়ে এবং মেমরি লিকের ঝুঁকি কমে।
এছাড়া টেমপ্লেট আর্গুমেন্ট স্বয়ংক্রিয়ভাবে অনুমান হওয়ায় কোড সরল হয় ও পাঠযোগ্যতা বাড়ে।
C++-এ std::shared_ptr অবজেক্ট নিয়ে কাজ করার সময় std::make_shared() ব্যবহার করলে কোড আরও পরিচ্ছন্ন, নিরাপদ ও দক্ষ হয়।
ডিফল্ট হিসেবে স্মার্ট পয়েন্টার ব্যবহার করুন: একচেটিয়া মালিকানার জন্য std::unique_ptr আর ভাগ করা মালিকানার জন্য std::shared_ptr।
র' পয়েন্টার রেখে দিন কেবল মালিকানাহীন রেফারেন্সের জন্য বা লিগ্যাসি কোডের সাথে ইন্টারফেস করার সময়।
বেশিরভাগ ক্ষেত্রেই একচেটিয়া মালিকানার জন্য std::unique_ptr-ই যথেষ্ট, কারণ এটি রেফারেন্স কাউন্টিংয়ের বাড়তি ঝামেলা ছাড়াই হালকা মেমরি ম্যানেজমেন্ট দেয়।
সত্যিকারের ভাগ করা মালিকানার প্রয়োজন না থাকলে std::shared_ptr অল্পই ব্যবহার করা উচিত, কারণ এটি বাড়তি ঝামেলা ও জটিলতা নিয়ে আসে।
এই অনুশীলনী আপনাকে নিয়ে যাবে ট্রয়ের জগতে। এর মানুষের জীবন ভরা বিস্ময় আর জাদুতে। ট্রয়ের অনেক মানুষই পাওয়ার ধারণ করে, যা তারা দৈনন্দিন জীবনে প্রায়ই ব্যবহার করে। পাওয়ার দিয়ে জগৎকে নতুন রূপ দেওয়া হয়, বা ট্রয়ের প্রাণীজগৎ ও অন্য মানুষকে প্রভাবিত করা হয়। জাদু আরও প্রকাশ পায় অনন্য আর্টিফ্যাক্টে, যা অভিযাত্রী, কারিগর ও ঋষিদের কাছে খুব চাহিদার।
এই অনুশীলনীতে আপনি কোড লিখবেন ট্রয়ের মানুষ, তাদের ধারণ করা আর্টিফ্যাক্ট এবং পাওয়ারের পারস্পরিক ক্রিয়া মডেল করার জন্য।
আপনার সামনে ছয়টি কাজ আছে। প্রথমটি একজন মানুষ তৈরি করার সাথে সম্পর্কিত, বাকি পাঁচটি পাওয়ার ও আর্টিফ্যাক্ট নিয়ে কাজ করার।
আপনার ট্রয়ের মডেলে মানুষই সবচেয়ে গুরুত্বপূর্ণ অংশ। আপনার মডেলের মানুষটির অনন্য আর্টিফ্যাক্ট ধারণ করার ক্ষমতা থাকা উচিত। তাদের আবার একটি পাওয়ার প্রকাশ করার ক্ষমতাও থাকা উচিত। এই পাওয়ারগুলো অন্য মানুষকে প্রভাবিত করতে পারে, তাই কোনো মানুষ অন্য কোনো পাওয়ার দ্বারা প্রভাবিত কি না, সেটাও আপনার মডেল করতে হবে।
আপনাকে artifact ও power স্ট্রাক্টের প্রাথমিক বাস্তবায়ন দেওয়া হয়েছে।
এমন একটি human স্ট্রাক্ট (বা ক্লাস) বাস্তবায়ন করুন, যেখানে possession নামের একটি artifact মেম্বার ভ্যারিয়েবলের দিকে স্মার্ট পয়েন্টার থাকে।
যেকোনো সময়ে একটি আর্টিফ্যাক্ট একজন মানুষই কেবল ধারণ করতে পারে।
একটি human স্ট্রাক্টে আরও দুটি মেম্বার ভ্যারিয়েবল থাকতে হবে।
একটিতে থাকে তাদের own_power, আর অন্যটি হলো এমন একটি পাওয়ার যা দিয়ে তারা influenced_by।
own_power ও influenced_by দুটোই powers টাইপের স্মার্ট পয়েন্টার।
প্রতিটি power একজন মানুষই কেবল ধারণ করতে পারে, তবে একই সাথে অন্য মানুষকেও প্রভাবিত করতে পারে।
ডিফল্টভাবে মানুষ জন্মায় কোনো আর্টিফ্যাক্ট ছাড়াই, এবং তারা কোনো পাওয়ারেরও মালিক নয়, আবার কোনো পাওয়ার দ্বারা প্রভাবিতও নয়।
human mindy_mccready{};
mindy_mccready.possession;
// => nullptr
mindy_mccready.own_power;
// => nullptr
mindy_mccready.influenced_by;
// => nullptr
এর অংশগুলোর পারস্পরিক ক্রিয়া ছাড়া আপনার মডেলটা একঘেয়ে। আপনি অনন্য আর্টিফ্যাক্ট তৈরি করে নির্দিষ্ট মানুষকে দিতে চান।
give_new_artifact ফাংশনটি ডিফাইন করুন, যা কিছু রিটার্ন করে না, বরং একটি human ও একটি string টাইপের রেফারেন্স নেয়।
এই string দিয়ে এটি একটি নতুন artifact অবজেক্ট ডিফাইন করবে এবং সেই অনুযায়ী human অবজেক্টের possession পয়েন্টার সেট করবে।
ফাংশনটি কিছুই রিটার্ন করবে না।
human erik_magnus_lehnsherr{};
give_new_artifact(erik_magnus_lehnsherr, "Mind shielding helmet");
erik_magnus_lehnsherr.possession->name;
// "Mind shielding helmet"
ট্রয়ের জগৎটা পুরোটাই পারস্পরিক ক্রিয়ার জগৎ। আপনি চান মানুষ তাদের সম্পদ বিনিময় করে লেনদেন করুক।
exchange_artifacts নামের একটি ফাংশন লিখুন, যা কিছু রিটার্ন করে না, বরং জিনিসগুলো বিনিময় করার জন্য দুটি আর্টিফ্যাক্ট স্মার্ট পয়েন্টার নেয়।
মনে রাখবেন, আপনি একটি unique_ptr কপি করতে পারেন না।
এর মধ্যে ফাংশন প্যারামিটারে ব্যবহারও অন্তর্ভুক্ত।
পরিবর্তে ওই unique_ptr টাইপের একটি রেফারেন্স ব্যবহার করুন।
human uchiha{};
give_new_artifact(uchiha, "konoha headband");
human uzumaki{};
give_new_artifact(uzumaki, "forehead protector");
exchange_artifacts(uchiha.possession, uzumaki.possession);
uchiha.possession->name;
// "forehead protector"
uzumaki.possession->name;
// "konoha headband"
ট্রয়ের সবচেয়ে রোমাঞ্চকর দিক হলো সেই বিশেষ পাওয়ারগুলো, যা মানুষ ব্যবহার করতে পারে। কেউ কেউ শুধু চিন্তা দিয়েই লোহা গলাতে পারে, আবার কেউ রাতের বেলা যেকোনো ক্ষত তৎক্ষণাৎ সারিয়ে তুলতে পারে।
manifest_power ফাংশনটি ডিফাইন করুন, যা কিছু রিটার্ন করে না, বরং একটি human ও একটি string টাইপের রেফারেন্স নেয়।
এই string দিয়ে এটি একটি নতুন power অবজেক্ট ডিফাইন করবে এবং সেই অনুযায়ী human অবজেক্টের own_power পয়েন্টার সেট করবে।
ফাংশনটি কিছুই রিটার্ন করবে না।
human eleven {};
manifest_power(eleven, "psychokinesis");
eleven.own_power->effect;
// "psychokinesis"
সবচেয়ে মহান পাওয়ারও কী কাজে আসে, যদি আপনি তা ব্যবহার করতে না পারেন। আপনার মডেল মূলত মানুষকে নিয়ে, তাই আপনি পাওয়ারের প্রভাব নজরে রাখতে চান।
একটি void ফাংশন use_power লিখুন, যা দুইজন মানুষের রেফারেন্স নেয়।
প্রথম মানুষটি হলো পাওয়ার ব্যবহারকারী, আর দ্বিতীয়টি লক্ষ্যবস্তু।
লক্ষ্যবস্তুর influenced_by পয়েন্টারটি ব্যবহারকারীর পাওয়ারের দিকে নির্দেশ করানো উচিত।
সরলতার জন্য, একজন মানুষ একটি মাত্র পাওয়ার দ্বারা প্রভাবিত হতে পারে। যে মানুষটি পাওয়ারটি ব্যবহার করেছিল সে আর না থাকলেও এই প্রভাব থেকে যায়।
human pamela_isley{};
manifest_power(pamela_isley, "control pheromones");
human count_vertigo{};
use_power(pamela_isley, count_vertigo);
count_vertigo.influenced_by->effect;
// "control pheromones"
কিছু পাওয়ার যখন কয়েকজন মানুষের উপর প্রয়োগ করা হয়, তখন আপনার সিমুলেশনে তাদের শক্তি কমে যায় বা নির্দিষ্ট কিছু প্রভাব তৈরি হয়। আপনি প্রতিটি পাওয়ারের সাথে যুক্ত মানুষের সংখ্যা নজরে রাখতে চান।
power_intensity ফাংশনটি ডিফাইন করুন, যা একজন মানুষ নেয় এবং তার পাওয়ারের তীব্রতা একটি int হিসেবে রিটার্ন করে।
যদি ব্যক্তির কোনো পাওয়ার না থাকে, তবে রিটার্ন ভ্যালু 0 হবে।
অন্যথায় তীব্রতা নির্দেশ করবে পাওয়ার ব্যবহারকারী এবং বর্তমানে প্রভাবিত সব মানুষকে।
human jean_grey{};
manifest_power(jean_grey, "uplifting personality");
human scott{};
human logan{};
human ororo{};
use_power(jean_grey, ororo);
use_power(jean_grey, logan);
use_power(jean_grey, scott);
power_intensity(jean_grey);
// 4
Exercism-এ সাইন আপ করুন, C++ ট্র্যাকের 19টি কনসেপ্ট100টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।