C++ স্ট্যান্ডার্ড লাইব্রেরির ইউটিলিটি লাইব্রেরি (Utility Library) বিভিন্ন ছোটো ছোটো কাজের জন্য ব্যবহৃত ফাংশন ও ক্লাস সরবরাহ করে, যা সাধারণত প্রোগ্রামিংয়ে প্রয়োজনীয় কাজগুলো সহজ করে। C++ এ <utility> হেডার ফাইলটি ইউটিলিটি লাইব্রেরি সরবরাহ করে এবং এতে বিভিন্ন ফাংশন, ক্লাস এবং টেমপ্লেট থাকে, যেগুলো ডেটা ম্যানিপুলেশন এবং অন্যান্য কমন কাজের জন্য ব্যবহৃত হয়।
ইউটিলিটি লাইব্রেরির কিছু গুরুত্বপূর্ণ উপাদান হল:
std::pairstd::tuplestd::moveএবংstd::forwardstd::swapstd::function
এই উপাদানগুলো C++ প্রোগ্রামিংয়ে সাধারণভাবে ব্যবহৃত হয় এবং কোডের কার্যকারিতা এবং কার্যক্ষমতা বাড়ায়।
১. std::pair
std::pair একটি কনটেইনার ক্লাস যা দুটি মান (যেকোনো ধরনের) একসাথে সংরক্ষণ করে। এটি সাধারণত কী-ভ্যালু জোড়া বা দুটি সম্পর্কিত উপাদান সংরক্ষণের জন্য ব্যবহৃত হয়।
উদাহরণ (std::pair):
#include <iostream>
#include <utility> // pair
int main() {
// std::pair তৈরি করা
std::pair<int, std::string> p = {1, "Apple"};
// std::pair এর মান অ্যাক্সেস করা
std::cout << "First: " << p.first << ", Second: " << p.second << std::endl;
return 0;
}ব্যাখ্যা:
std::pairদুটি ভ্যালু (যেমন একটি পূর্ণসংখ্যা এবং একটি স্ট্রিং) সংরক্ষণ করে।firstএবংsecondএর মাধ্যমে পেয়ারটির উপাদান অ্যাক্সেস করা হয়।
২. std::tuple
std::tuple একটি ভিন্ন ধরনের কনটেইনার যা একাধিক উপাদান (যে কোনো ডেটা টাইপের) সংরক্ষণ করতে পারে। এটি std::pair এর মতো, তবে tuple একাধিক উপাদান ধারণ করতে সক্ষম।
উদাহরণ (std::tuple):
#include <iostream>
#include <tuple> // tuple
int main() {
// std::tuple তৈরি করা
std::tuple<int, double, std::string> t = {1, 3.14, "Hello"};
// std::tuple এর মান অ্যাক্সেস করা
std::cout << "First: " << std::get<0>(t) << ", Second: " << std::get<1>(t) << ", Third: " << std::get<2>(t) << std::endl;
return 0;
}ব্যাখ্যা:
std::tupleএকাধিক উপাদান ধারণ করতে পারে, যা বিভিন্ন টাইপের হতে পারে (যেমন,int,double,string)।std::get<index>(tuple)ব্যবহার করে টাপলের উপাদান অ্যাক্সেস করা হয়, যেখানেindexহল উপাদানের অবস্থান।
৩. std::move এবং std::forward
C++11 এ std::move এবং std::forward ফাংশনগুলো মুভ সেমান্টিক্স ও প্রপারলি ফাংশন রেফারেন্স হ্যান্ডলিং এর জন্য ব্যবহৃত হয়।
std::move(): এটি একটি ভ্যালু বা অবজেক্টকে রিসোর্স স্থানান্তর করার জন্য ব্যবহার করা হয়। এটি মূলত রেফারেন্সকেrvalueরেফারেন্সে কনভার্ট করে।std::forward(): এটি প্যারামিটার ফরওয়ার্ড করার জন্য ব্যবহৃত হয়, বিশেষ করে টেমপ্লেট ফাংশনের মধ্যে।
উদাহরণ (std::move):
#include <iostream>
#include <utility> // move
void func(std::string&& str) {
std::cout << "Moved string: " << str << std::endl;
}
int main() {
std::string s = "Hello, World!";
// std::move() ব্যবহার করে ডেটা স্থানান্তর করা
func(std::move(s));
// এখন 's' এর মান অপরিবর্তিত নয়
std::cout << "Original string after move: " << s << std::endl;
return 0;
}ব্যাখ্যা:
std::move()ব্যবহার করেsকেrvalueরেফারেন্সে কনভার্ট করা হয়েছে, যার মাধ্যমে ডেটাfunc()ফাংশনে মুভ হয়েছে।
৪. std::swap
std::swap একটি সহজ ফাংশন যা দুটি ভ্যারিয়েবলের মান পরিবর্তন করতে ব্যবহৃত হয়। এটি সাধারণত দুইটি মান একে অপরের মধ্যে বিনিময় করার জন্য ব্যবহৃত হয়।
উদাহরণ (std::swap):
#include <iostream>
#include <utility> // swap
int main() {
int a = 5, b = 10;
// std::swap ব্যবহার করে মান বিনিময় করা
std::swap(a, b);
std::cout << "a = " << a << ", b = " << b << std::endl;
return 0;
}ব্যাখ্যা:
std::swap(a, b)ফাংশনটিaএবংbএর মান বিনিময় করে।
৫. std::function
std::function হলো একটি ক্লাস টেমপ্লেট যা একটি কলেবল অবজেক্ট (যেমন ফাংশন পয়েন্টার, ল্যাম্বডা এক্সপ্রেশন, ফাংশন অবজেক্ট) ধারণ করতে পারে। এটি একটি সাধারণ ইন্টারফেস সরবরাহ করে এবং ফাংশন, ফাংশন পয়েন্টার, এবং ল্যাম্বডার মতো অবজেক্টগুলোর জন্য ব্যবহৃত হয়।
উদাহরণ (std::function):
#include <iostream>
#include <functional> // function
void greet() {
std::cout << "Hello, World!" << std::endl;
}
int main() {
// std::function তৈরি করা
std::function<void()> func = greet;
// ফাংশন কল করা
func();
return 0;
}ব্যাখ্যা:
std::function<void()>একটি ফাংশন টাইপ সংজ্ঞায়িত করে যা কোনো আর্গুমেন্ট নেয় না এবংvoidরিটার্ন করে।- এটি একাধিক ফাংশন টাইপের জন্য সাধারণ একটি ইন্টারফেস সরবরাহ করে।
উপসংহার
C++ এর ইউটিলিটি লাইব্রেরি খুবই গুরুত্বপূর্ণ কারণ এটি এমন টুলস এবং ক্লাস সরবরাহ করে যা দৈনন্দিন প্রোগ্রামিং কাজগুলো সহজ করে তোলে। std::pair, std::tuple, std::move, std::swap, এবং std::function এর মতো উপাদানগুলি প্রোগ্রামিংয়ের কার্যক্ষমতা বৃদ্ধি করে, কোডের পাঠযোগ্যতা উন্নত করে এবং ডেটা ম্যানিপুলেশনে সহায়ক হয়। C++ প্রোগ্রামিংয়ের কার্যকারিতা বাড়ানোর জন্য এই ইউটিলিটি ফাংশনগুলো অত্যন্ত গুরুত্বপূর্ণ।
std::pair এবং std::tuple C++ স্ট্যান্ডার্ড লাইব্রেরির দুটি গুরুত্বপূর্ণ ডেটা স্ট্রাকচার, যা একাধিক ভ্যালুকে একটি একক ইউনিট হিসেবে সংরক্ষণ করতে সহায়তা করে। std::pair দুইটি ভ্যালু সংরক্ষণ করে, যেখানে std::tuple এর মাধ্যমে একাধিক (২ বা ততোধিক) ভ্যালু সংরক্ষণ করা যায়। এই ডেটা স্ট্রাকচারগুলো জটিল ডেটা ম্যানিপুলেশনের সময় ব্যবহৃত হয় এবং কোডকে আরও সহজ ও পঠনযোগ্য করে।
std::pair এর ধারণা এবং ব্যবহার
std::pair এমন একটি ডেটা স্ট্রাকচার, যা দুটি ভিন্ন বা একই ধরনের ডেটা ধরে রাখতে পারে। এটি সাধারণত কী-ভ্যালু জোড়া (key-value pair) তৈরি করতে ব্যবহৃত হয়।
std::pair তৈরি করার উপায়
std::pair তৈরি করতে std::make_pair() ফাংশন বা সরাসরি std::pair অবজেক্ট তৈরি করা যায়।
উদাহরণ:
#include <iostream>
#include <utility> // std::pair অন্তর্ভুক্ত করার জন্য
int main() {
std::pair<int, std::string> person;
person = std::make_pair(1, "Alice"); // std::make_pair ব্যবহার করে তৈরি
// std::pair থেকে মান প্রিন্ট করা
std::cout << "ID: " << person.first << ", Name: " << person.second << std::endl;
return 0;
}আউটপুট:
ID: 1, Name: Alicestd::pair এর সাথে ব্যবহৃত বৈশিষ্ট্যসমূহ
- first: প্রথম মানটি অ্যাক্সেস করতে
firstব্যবহার করা হয়। - second: দ্বিতীয় মানটি অ্যাক্সেস করতে
secondব্যবহার করা হয়।
std::tuple এর ধারণা এবং ব্যবহার
std::tuple হলো এমন একটি ডেটা স্ট্রাকচার, যা তিন বা ততোধিক ভিন্ন বা একই ধরনের মান সংরক্ষণ করতে পারে। এটি std::pair এর তুলনায় আরও বেশি নমনীয়, কারণ std::tuple এর মাধ্যমে বিভিন্ন সংখ্যার ডেটা একসাথে সংরক্ষণ করা সম্ভব।
std::tuple তৈরি করার উপায়
std::tuple তৈরি করতে std::make_tuple() ফাংশন বা সরাসরি std::tuple অবজেক্ট তৈরি করা যায়।
উদাহরণ:
#include <iostream>
#include <tuple> // std::tuple অন্তর্ভুক্ত করার জন্য
int main() {
std::tuple<int, std::string, float> student;
student = std::make_tuple(1, "Bob", 95.5f); // std::make_tuple ব্যবহার করে তৈরি
// std::tuple থেকে মান বের করা
std::cout << "ID: " << std::get<0>(student) << ", Name: " << std::get<1>(student)
<< ", Grade: " << std::get<2>(student) << std::endl;
return 0;
}আউটপুট:
ID: 1, Name: Bob, Grade: 95.5std::tuple এর সাথে ব্যবহৃত বৈশিষ্ট্যসমূহ
- std::get
(tuple) :Nসংখ্যক ইন্ডেক্সে থাকা মান বের করতেstd::getব্যবহার করা হয়। উদাহরণস্বরূপ,std::get<0>(student)প্রথম উপাদানটি প্রদান করবে। - std::tie:
std::tieব্যবহার করেtupleএর উপাদানগুলোকে আলাদা আলাদা ভেরিয়েবলে আনপ্যাক করা যায়।
std::pair এবং std::tuple এর তুলনা
| বৈশিষ্ট্য | std::pair | std::tuple |
|---|---|---|
| উপাদানের সংখ্যা | সর্বদা ২টি | ২ বা ততোধিক (যেকোনো সংখ্যা) |
| অ্যাক্সেস মেথড | first, second | std::get<N>() |
| ব্যবহার | সাধারণত কী-ভ্যালু জোড়ার জন্য | একাধিক ভিন্ন ডেটা টাইপের মান সংরক্ষণের জন্য |
std::pair এবং std::tuple ব্যবহার করার কিছু উদাহরণ
উদাহরণ: std::pair এবং std::tuple এর ব্যবহার একসাথে
#include <iostream>
#include <tuple>
#include <utility>
int main() {
// std::pair ব্যবহার
std::pair<int, std::string> person = std::make_pair(1, "Alice");
// std::tuple ব্যবহার
std::tuple<int, std::string, double> employee = std::make_tuple(2, "Bob", 75000.0);
// std::pair থেকে মান প্রিন্ট
std::cout << "Person ID: " << person.first << ", Name: " << person.second << std::endl;
// std::tuple থেকে মান প্রিন্ট
std::cout << "Employee ID: " << std::get<0>(employee) << ", Name: " << std::get<1>(employee)
<< ", Salary: " << std::get<2>(employee) << std::endl;
return 0;
}উদাহরণ: std::tie এর ব্যবহার
#include <iostream>
#include <tuple>
int main() {
std::tuple<int, std::string, float> student = std::make_tuple(1, "Carol", 88.5f);
int id;
std::string name;
float grade;
// std::tie ব্যবহার করে tuple এর উপাদানগুলো আলাদা আলাদা ভেরিয়েবলে আনপ্যাক করা
std::tie(id, name, grade) = student;
std::cout << "ID: " << id << ", Name: " << name << ", Grade: " << grade << std::endl;
return 0;
}আউটপুট:
ID: 1, Name: Carol, Grade: 88.5উপসংহার
std::pair এবং std::tuple C++ প্রোগ্রামিংয়ে একাধিক ভ্যালুকে একত্রে সংরক্ষণ করতে ব্যবহৃত হয়। std::pair সাধারণত দুটি ভ্যালু সংরক্ষণ করতে ব্যবহার করা হয়, যেখানে std::tuple যেকোনো সংখ্যার ভ্যালু সংরক্ষণ করতে পারে। std::pair এবং std::tuple ব্যবহার করে জটিল ডেটা গঠন সহজ করা যায় এবং কোড আরও পাঠযোগ্য করা যায়।
C++11 এবং পরবর্তী সংস্করণে, C++ স্ট্যান্ডার্ড লাইব্রেরিতে নতুন কিছু টেমপ্লেট ক্লাস যোগ করা হয়েছে যা ডেটা ম্যানিপুলেশনকে আরও সহজ এবং নিরাপদ করেছে। এগুলোর মধ্যে std::any, std::variant, এবং std::optional অন্তর্ভুক্ত। এই ক্লাসগুলো ব্যবহারকারীদের অনেক ধরনের ডেটা ও তাদের অবস্থা পরিচালনা করতে সাহায্য করে।
এখানে এই তিনটি ক্লাসের ব্যবহার এবং তাদের মূল বৈশিষ্ট্যগুলো আলোচনা করা হলো:
১. std::any
std::any একটি নতুন ডেটা টাইপ যা C++17 এ অন্তর্ভুক্ত করা হয়েছে এবং এটি যে কোনও টাইপের মান ধারণ করতে পারে। এটি একটি "type-safe container" যেখানে আপনি যে কোনও ধরনের ডেটা (যেমন, int, double, std::string, ইত্যাদি) সংরক্ষণ করতে পারেন। std::any ব্যবহার করার সময় আপনাকে ডেটা টাইপটি জানার প্রয়োজন হয় না, তবে এর জন্য কিছু ফাংশন রয়েছে যার মাধ্যমে আপনি ডেটা টাইপের তথ্য পেতে পারেন এবং টাইপকে নিরাপদে ব্যবহার করতে পারেন।
উদাহরণ (std::any):
#include <iostream>
#include <any>
#include <string>
int main() {
std::any data;
// বিভিন্ন টাইপের ডেটা `std::any` তে সংরক্ষণ
data = 10; // integer
std::cout << "Integer: " << std::any_cast<int>(data) << std::endl;
data = 3.14; // double
std::cout << "Double: " << std::any_cast<double>(data) << std::endl;
data = std::string("Hello, World!"); // string
std::cout << "String: " << std::any_cast<std::string>(data) << std::endl;
return 0;
}আউটপুট:
Integer: 10
Double: 3.14
String: Hello, World!এখানে, std::any int, double, এবং std::string এর মান ধারণ করেছে। আপনি যখন std::any_cast<T>() ফাংশন ব্যবহার করবেন, তখন আপনাকে টাইপটি সঠিকভাবে জানাতে হবে, অথবা এটি একটি std::bad_any_cast ত্রুটি দেবে।
২. std::variant
std::variant একটি সি++17 বৈশিষ্ট্য যা একই সময়ে একাধিক প্রকারের মান ধারণ করতে পারে। এটি একটি সুরক্ষিত ইউনিয়ন (type-safe union) যা একটি সময়ে কেবল একটি মান ধারণ করে এবং আপনি জানেন কোন টাইপটি বর্তমানে ব্যবহৃত হচ্ছে। std::variant ডেটা টাইপের নিরাপত্তা প্রদান করে এবং টাইপ চেকের জন্য কিছু ফাংশন সরবরাহ করে।
উদাহরণ (std::variant):
#include <iostream>
#include <variant>
int main() {
std::variant<int, float, std::string> var;
// int সেট করা
var = 10;
std::cout << "Integer: " << std::get<int>(var) << std::endl;
// float সেট করা
var = 3.14f;
std::cout << "Float: " << std::get<float>(var) << std::endl;
// string সেট করা
var = "Hello, Variant!";
std::cout << "String: " << std::get<std::string>(var) << std::endl;
return 0;
}আউটপুট:
Integer: 10
Float: 3.14
String: Hello, Variant!এখানে, std::variant একটি int, float, বা std::string ধারণ করতে পারে, কিন্তু প্রতিবার কেবল একটি টাইপের মান থাকতে পারে। আপনি std::get<T>() ব্যবহার করে সঠিক টাইপ থেকে মান পেতে পারেন। যদি আপনি ভুল টাইপে অ্যাক্সেস করার চেষ্টা করেন, তাহলে এটি একটি std::bad_variant_access ত্রুটি ছুঁড়ে ফেলবে।
৩. std::optional
std::optional একটি C++17 বৈশিষ্ট্য যা একটি মানের উপস্থিতি বা অনুপস্থিতি নির্দেশ করতে ব্যবহৃত হয়। এটি বিশেষভাবে দরকারী যখন আপনি এমন একটি মান ধারণ করতে চান যা অপশনাল বা ঐচ্ছিক, যেমন ডেটাবেসের ফলাফল বা ইউজার ইনপুট যেখানে মানটি প্রযোজ্য নাও হতে পারে। এটি সাধারণত null বা "no value" পরিস্থিতি পরিচালনা করতে ব্যবহৃত হয়, তবে std::nullopt ব্যবহার করে এটি নির্দেশ করা হয়।
উদাহরণ (std::optional):
#include <iostream>
#include <optional>
std::optional<int> divide(int a, int b) {
if (b == 0) {
return std::nullopt; // Division by zero, return no value
}
return a / b; // Return the result
}
int main() {
auto result = divide(10, 2);
if (result) {
std::cout << "Result: " << *result << std::endl;
} else {
std::cout << "Division by zero!" << std::endl;
}
result = divide(10, 0);
if (result) {
std::cout << "Result: " << *result << std::endl;
} else {
std::cout << "Division by zero!" << std::endl;
}
return 0;
}আউটপুট:
Result: 5
Division by zero!এখানে, std::optional<int> একটি অপশনাল মান ধারণ করে। যদি ভাগফল সম্ভব না হয় (যেমন ভাগফল শূন্যের সাথে), তাহলে std::nullopt ব্যবহার করে কোনো মান ফেরত দেওয়া হয় না। আপনি *result দিয়ে ঐচ্ছিক মানটি বের করতে পারেন, তবে আপনি আগে নিশ্চিত করতে হবে যে মানটি উপস্থিত রয়েছে।
সারাংশ
std::any: যে কোন টাইপের মান ধারণ করতে পারে। এটি টাইপ নিরাপত্তা প্রদান করে এবং টাইপ কাস্টিং করতে পারে।std::variant: একাধিক সম্ভাব্য টাইপের মধ্যে একটি টাইপ ধারণ করতে পারে। এটি টাইপ নিরাপত্তা প্রদান করে এবং কেবলমাত্র একটি টাইপ ধারণ করতে দেয়।std::optional: একটি অপশনাল মান ধারণ করতে পারে, যা একটি মানের উপস্থিতি বা অনুপস্থিতি নির্দেশ করে। এটি সাধারণতnulloptব্যবহার করে মানের অনুপস্থিতি নির্দেশ করে।
এই তিনটি ক্লাস C++ প্রোগ্রামিংয়ে টাইপ নিরাপত্তা, অপশনাল ডেটা, এবং বহুমুখী টাইপ ব্যবহারের সুবিধা প্রদান করে।
C++-এ স্মার্ট পয়েন্টার (Smart Pointers) এমন পয়েন্টার যা মেমরি ম্যানেজমেন্ট সহজ করে এবং স্মৃতি রিকল (memory leaks) বা ডাবল ডিলিট (double delete) সমস্যা প্রতিরোধ করে। C++11 থেকে, std::unique_ptr, std::shared_ptr, এবং std::weak_ptr এই তিনটি স্মার্ট পয়েন্টার স্ট্যান্ডার্ড লাইব্রেরির অংশ হিসেবে অন্তর্ভুক্ত হয়েছে, এবং তারা মেমরি পরিচালনার ক্ষেত্রে অনেক সুবিধা প্রদান করে। এই স্মার্ট পয়েন্টারগুলি স্বয়ংক্রিয়ভাবে মেমরি রিলিজ করে, যখন এটি আর ব্যবহৃত হয় না।
নিচে এই স্মার্ট পয়েন্টারগুলির ব্যাখ্যা এবং উদাহরণ দেওয়া হলো:
১. std::unique_ptr
std::unique_ptr একটি স্মার্ট পয়েন্টার যা একক মালিকানায় একটি অবজেক্টের মালিকানার প্রতিনিধিত্ব করে। এটি এমন একটি পয়েন্টার যা এক সময়ে শুধুমাত্র একটি অবজেক্টের মালিক হতে পারে। মালিকানার স্থানান্তর করা যেতে পারে, তবে একাধিক unique_ptr একই অবজেক্টের মালিক হতে পারে না।
বৈশিষ্ট্য:
- একক মালিকানা: শুধুমাত্র একটি
unique_ptrএক সময়ে একটি অবজেক্টের মালিক হতে পারে। - অটো ডিলিট: যখন
unique_ptrজীবনাবসান ঘটে, তখন এটি নিজে থেকেই সংশ্লিষ্ট অবজেক্টকে ডিলিট করে। - মালিকানা স্থানান্তর: মালিকানা এক
unique_ptrথেকে অন্যunique_ptrএ স্থানান্তর করা যেতে পারে, তবে এটি কপি করা সম্ভব নয়।
উদাহরণ:
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "Constructor called!" << std::endl; }
~MyClass() { std::cout << "Destructor called!" << std::endl; }
void show() { std::cout << "MyClass object is here!" << std::endl; }
};
int main() {
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(); // unique_ptr তৈরি
ptr1->show(); // অবজেক্টের মেথড কল
// মালিকানা স্থানান্তর করা
std::unique_ptr<MyClass> ptr2 = std::move(ptr1); // ptr1 থেকে ptr2 তে মালিকানা স্থানান্তর
if (!ptr1) {
std::cout << "ptr1 no longer owns the object." << std::endl;
}
return 0;
}আউটপুট:
Constructor called!
MyClass object is here!
Destructor called!২. std::shared_ptr
std::shared_ptr একটি স্মার্ট পয়েন্টার যা অনেকগুলি মালিকানায় একটি অবজেক্টের মালিকানা প্রতিনিধিত্ব করে। এটি একই অবজেক্টের জন্য একাধিক shared_ptr তৈরি করতে দেয় এবং সমস্ত shared_ptr যখন অবজেক্টটি আর ব্যবহার করা হয় না, তখন ঐ অবজেক্টের মেমরি মুক্ত করা হয়। এটি রেফারেন্স কাউন্টিং ব্যবহার করে, যাতে একটি অবজেক্টের জন্য কতগুলি shared_ptr রয়েছে তা ট্র্যাক করা হয়।
বৈশিষ্ট্য:
- অনেক মালিকানা: একাধিক
shared_ptrএকই অবজেক্টের মালিক হতে পারে। - রেফারেন্স কাউন্টিং: অবজেক্টের মালিকানার সংখ্যা ট্র্যাক করা হয় এবং সব মালিকানার পর অবজেক্ট মুছে ফেলা হয়।
উদাহরণ:
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "Constructor called!" << std::endl; }
~MyClass() { std::cout << "Destructor called!" << std::endl; }
void show() { std::cout << "MyClass object is here!" << std::endl; }
};
int main() {
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(); // shared_ptr তৈরি
ptr1->show();
{
std::shared_ptr<MyClass> ptr2 = ptr1; // ptr1 এর মালিকানা ptr2 তে স্থানান্তর
std::cout << "Inside block, use_count: " << ptr1.use_count() << std::endl;
} // ptr2 বাহির হয়ে যায়
std::cout << "Outside block, use_count: " << ptr1.use_count() << std::endl;
return 0;
}আউটপুট:
Constructor called!
MyClass object is here!
Inside block, use_count: 2
Outside block, use_count: 1
Destructor called!৩. std::weak_ptr
std::weak_ptr একটি স্মার্ট পয়েন্টার যা shared_ptr এর মালিকানার অংশীদার হিসেবে কাজ করে, কিন্তু এটি রেফারেন্স কাউন্টিংয়ে অংশগ্রহণ করে না। এটি মূলত সাইক্লিক রেফারেন্স (circular references) এড়াতে ব্যবহৃত হয়। যখন একটি weak_ptr থেকে অবজেক্ট অ্যাক্সেস করা হয়, তখন এটি একটি shared_ptr তৈরি করতে পারে, তবে এটি কোনো রেফারেন্স কাউন্টিং বাড়ায় না।
বৈশিষ্ট্য:
- রেফারেন্স কাউন্টিংয়ে অংশগ্রহণ করে না:
weak_ptrরেফারেন্স কাউন্টিং বাড়ায় না, তাই এটি সাইক্লিক রেফারেন্সের সমস্যা সৃষ্টি করে না। shared_ptrথেকে অ্যাক্সেস:weak_ptrথেকে অবজেক্ট অ্যাক্সেস করতে হলে, একটিshared_ptrতৈরি করতে হয়।
উদাহরণ:
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "Constructor called!" << std::endl; }
~MyClass() { std::cout << "Destructor called!" << std::endl; }
void show() { std::cout << "MyClass object is here!" << std::endl; }
};
int main() {
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(); // shared_ptr তৈরি
std::weak_ptr<MyClass> weakPtr = ptr1; // weak_ptr তৈরি
std::cout << "Use count before: " << ptr1.use_count() << std::endl;
if (auto temp = weakPtr.lock()) { // weak_ptr থেকে shared_ptr তৈরি
temp->show();
} else {
std::cout << "Object no longer exists!" << std::endl;
}
ptr1.reset(); // shared_ptr এর মালিকানা শেষ
std::cout << "Use count after: " << ptr1.use_count() << std::endl;
if (auto temp = weakPtr.lock()) {
temp->show();
} else {
std::cout << "Object no longer exists!" << std::endl;
}
return 0;
}আউটপুট:
Constructor called!
Use count before: 1
MyClass object is here!
Use count after: 0
Object no longer exists!
Destructor called!স্মার্ট পয়েন্টারের উপকারিতা:
- অটোমেটিক মেমরি ম্যানেজমেন্ট: স্মার্ট পয়েন্টারগুলি ম্যানুয়ালি মেমরি ম্যানেজমেন্টের প্রয়োজন কমিয়ে দেয়, যেমন মেমরি রিকল বা ডাবল ডিলিট সমস্যা।
- সাইক্লিক রেফারেন্স এড়ানো:
std::weak_ptrসাইক্লিক রেফারেন্সের সমস্যা প্রতিরোধ করে, যাstd::shared_ptrএর মাধ্যমে তৈরি হতে পারে। - বিনামূল্যে অবজেক্ট রিলিজ: যখন স্মার্ট পয়েন্টারটি স্কোপের বাইরে চলে যায়, এটি অবজেক্টের মেমরি মুক্ত করে দেয়।
উপসংহার:
std::unique_ptr: একক মালিকানার পয়েন্টার, যা মালিকানার স্থানান্তর করতে পারে, কিন্তু কপি করা যায় না।std::shared_ptr: একাধিক মালিকানার পয়েন্টার, যা রেফারেন্স কাউন্টিং ব্যবহার করে অবজেক্টটি মুছে ফেলা হয় যখন সমস্তshared_ptrশেষ হয়।std::weak_ptr:shared_ptrথেকে সম্পর্কিত পয়েন্টার, তবে এটি রেফারেন্স কাউন্টিংয়ে অংশগ্রহণ করে না, যা সাইক্লিক রেফারেন্স এড়াতে সাহায্য করে।
এই স্মার্ট পয়েন্টারগুলি C++ কোডে মেমরি ম্যানেজমেন্ট সহজ, নিরাপদ, এবং দক্ষ করে তোলে।
সি++ এ সময় এবং তারিখ ম্যানিপুলেশনের জন্য C++11 থেকে std::chrono লাইব্রেরি যোগ করা হয়েছে, যা সময় নির্ধারণ, পরিমাপ, এবং সময়কাল সম্পর্কিত কাজগুলো সহজে করতে সহায়তা করে। C++20 এ std::chrono::date যুক্ত করা হয়েছে, যা আরও উন্নত সময় ও তারিখ ম্যানিপুলেশন সুবিধা প্রদান করে। এখানে std::chrono, std::date, এবং std::duration এর প্রধান উপাদান ও ব্যবহার নিয়ে আলোচনা করা হলো।
১. std::chrono
std::chrono হল C++ স্ট্যান্ডার্ড লাইব্রেরির একটি অংশ যা সময় ম্যানিপুলেশন ও পরিমাপের জন্য ব্যবহৃত হয়। এতে বিভিন্ন ক্লাস ও ফাংশন রয়েছে যা টাইম পয়েন্ট, টাইম ডিউরেশন এবং ক্লক ব্যবহার করে সময়ের বিভিন্ন পরিসীমা নিয়ে কাজ করতে সক্ষম করে।
প্রধান উপাদানগুলো:
- Clocks:
std::chrono::system_clock,std::chrono::steady_clock, এবংstd::chrono::high_resolution_clock। - Time Point: একটি নির্দিষ্ট সময় নির্দেশ করে।
- Duration: সময়ের একটি নির্দিষ্ট সময়কাল।
উদাহরণ:
#include <iostream>
#include <chrono>
int main() {
// বর্তমান সময় পাওয়া
auto start = std::chrono::system_clock::now();
// কিছু বিলম্বের জন্য একটি লুপ
for (int i = 0; i < 1000000; ++i) {}
// বিলম্ব পরবর্তী সময় পাওয়া
auto end = std::chrono::system_clock::now();
// সময়ের ব্যবধান গণনা করা
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Elapsed time: " << elapsed.count() << " milliseconds" << std::endl;
return 0;
}এখানে system_clock বর্তমান সময় সংগ্রহ করে এবং duration_cast ব্যবহার করে সময়ের ব্যবধান গণনা করে।
২. std::chrono::date (C++20 থেকে)
std::chrono::date C++20 এ যোগ করা হয়, যা তারিখ ম্যানিপুলেশন সহজ করে। এটি তারিখ ও সময় সম্পর্কিত কাজগুলোতে সহায়ক, যেমন নির্দিষ্ট তারিখ সেট করা, সময়ের ব্যবধান হিসাব করা, এবং ক্যালেন্ডার ভিত্তিক ম্যানিপুলেশন।
উদাহরণ:
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
using namespace std::chrono_literals;
// নির্দিষ্ট তারিখ এবং সময় সেট করা
year_month_day today = floor<days>(system_clock::now());
std::cout << "Today's date: " << today << std::endl;
// নির্দিষ্ট সময় পরবর্তী তারিখ
year_month_day next_week = today + days{7};
std::cout << "Next week's date: " << next_week << std::endl;
return 0;
}উপরের উদাহরণে, year_month_day এবং days টাইপ ব্যবহার করে বর্তমান তারিখ পাওয়া হয়েছে এবং এক সপ্তাহ পরে তারিখ গণনা করা হয়েছে।
৩. std::chrono::duration
std::chrono::duration বিভিন্ন সময়কালকে গণনা করতে ব্যবহৃত হয়। এটি সাধারণত std::chrono-এর অন্য টাইপগুলোর সাথে ব্যবধান মাপতে ব্যবহার করা হয়, যেমন সেকেন্ড, মিনিট, ঘন্টা, মিলিসেকেন্ড ইত্যাদি।
প্রধান টাইপ:
- seconds: সেকেন্ডে সময়কাল।
- milliseconds: মিলিসেকেন্ডে সময়কাল।
- microseconds: মাইক্রোসেকেন্ডে সময়কাল।
- nanoseconds: ন্যানোসেকেন্ডে সময়কাল।
উদাহরণ:
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
// 3 সেকেন্ড সময়কাল
duration<int> three_seconds(3);
std::cout << "Three seconds: " << three_seconds.count() << " seconds" << std::endl;
// মাইক্রোসেকেন্ডের একটি সময়কাল তৈরি করা
auto time_in_milliseconds = duration_cast<milliseconds>(three_seconds);
std::cout << "Three seconds in milliseconds: " << time_in_milliseconds.count() << " milliseconds" << std::endl;
return 0;
}এখানে duration একটি সময়কাল হিসেবে কাজ করে এবং duration_cast ব্যবহার করে এটিকে ভিন্ন টাইম ইউনিটে রূপান্তর করা হয়েছে।
সময় ও তারিখ ম্যানিপুলেশন: কিছু সাধারণ ব্যবহার
১. টাইম পয়েন্ট মাপা: std::chrono::system_clock এবং std::chrono::steady_clock ব্যবহার করে নির্দিষ্ট টাইম পয়েন্ট মাপা।
২. টাইম ইন্টারভ্যাল পরিমাপ: নির্দিষ্ট সময়ের ব্যবধান বের করতে duration ব্যবহার করা।
৩. তারিখ ক্যালকুলেশন: std::chrono::date ব্যবহার করে নির্দিষ্ট তারিখ ম্যানিপুলেশন করা।
৪. কনভার্সন: duration_cast ব্যবহার করে সময়ের ভিন্ন ইউনিটে রূপান্তর করা।
সারাংশ
std::chrono: সময় নির্ধারণ, পরিমাপ, এবং ম্যানিপুলেশনের জন্য ব্যবহৃত হয়।std::chrono::date: তারিখ নির্ধারণ ও ক্যালেন্ডার সম্পর্কিত কাজের জন্য C++20 থেকে সংযুক্ত।std::chrono::duration: সময়কাল মাপার জন্য ব্যবহৃত, যা বিভিন্ন ইউনিটে রূপান্তরযোগ্য।
std::chrono, std::date, এবং std::duration C++ এ সময় ও তারিখ ম্যানিপুলেশনের শক্তিশালী টুল এবং এগুলো সময়মিতিবিষয়ক কাজগুলিকে সহজতর ও আরও নির্ভরযোগ্য করে তোলে।
Read more