একটি "কাঁচা" পয়েন্টারটি নিয়ন্ত্রণহীন । এটি হল, নিম্নলিখিত লাইন:
SomeKindOfObject *someKindOfObject = new SomeKindOfObject();
... delete
সঠিক সময়ে যদি সাথে করা হয় না তবে স্মৃতি ফাঁস হবে ।
auto_ptr
এই মামলাগুলি হ্রাস করার জন্য, std::auto_ptr<>
চালু করা হয়েছিল। ২০১১ এর মানদণ্ডের পূর্বে সি ++ এর সীমাবদ্ধতার কারণে, auto_ptr
মেমরি ফাঁস করা এখনও এটি খুব সহজ । এটি সীমিত ক্ষেত্রে যেমন যথেষ্ট তবে এটি যথেষ্ট:
void func() {
std::auto_ptr<SomeKindOfObject> sKOO_ptr(new SomeKindOfObject());
// do some work
// will not leak if you do not copy sKOO_ptr.
}
এর দুর্বলতম ব্যবহারগুলির একটি হ'ল পাত্রে। এটি কারণ যদি কোনও অনুলিপি auto_ptr<>
তৈরি করা হয় এবং পুরাতন অনুলিপিটি সাবধানে পুনরায় সেট না করা হয়, তবে ধারক পয়েন্টারটি মুছতে পারে এবং ডেটা হারাতে পারে।
unique_ptr
প্রতিস্থাপন হিসাবে, সি ++ 11 প্রবর্তিত std::unique_ptr<>
:
void func2() {
std::unique_ptr<SomeKindofObject> sKOO_unique(new SomeKindOfObject());
func3(sKOO_unique); // now func3() owns the pointer and sKOO_unique is no longer valid
}
যেমন unique_ptr<>
ফাংশনগুলির মধ্যে পাস করা হলেও এমনটি সঠিকভাবে পরিষ্কার করা হবে। এটি পয়েন্টারের "মালিকানা" শব্দার্থত উপস্থাপন করে এটি করে - "মালিক" এটি পরিষ্কার করে। এটি পাত্রে ব্যবহারের জন্য এটি আদর্শ করে তোলে:
std::vector<std::unique_ptr<SomeKindofObject>> sKOO_vector();
বিপরীতে auto_ptr<>
, unique_ptr<>
এখানে ভাল আচরণ করা হয় এবং যখন vector
আকার পরিবর্তন করা হয়, অনুলিপিযুক্তরূপে যখন vector
এর ব্যাকিং স্টোরটি অনুলিপি করা হয় তখন অবজেক্টগুলির কোনওটিই দুর্ঘটনাক্রমে মুছে ফেলা হবে না ।
shared_ptr
এবং weak_ptr
unique_ptr<>
এটি নিশ্চিত হওয়ার জন্য কার্যকর, তবে এমন কিছু ক্ষেত্রে রয়েছে যেখানে আপনি চান যে আপনার কোড বেসের দুটি অংশ একই বস্তুর উল্লেখ করতে এবং পয়েন্টারটি চারপাশে অনুলিপি করতে সক্ষম হবে, যদিও এখনও সঠিক পরিষ্কারের গ্যারান্টি রয়েছে। উদাহরণস্বরূপ, ব্যবহার করার সময় কোনও গাছ এ জাতীয় চেহারা দেখতে পারে std::shared_ptr<>
:
template<class T>
struct Node {
T value;
std::shared_ptr<Node<T>> left;
std::shared_ptr<Node<T>> right;
};
এই ক্ষেত্রে, আমরা এমনকি মূল নোডের একাধিক অনুলিপি ধরে রাখতে পারি, এবং যখন রুট নোডের সমস্ত অনুলিপিগুলি ধ্বংস হয়ে যায় তখন গাছটি সঠিকভাবে পরিষ্কার হয়ে যায়।
এটি কাজ করে কারণ প্রত্যেকে shared_ptr<>
কেবলমাত্র অবজেক্টের পয়েন্টার ধরে না, পাশাপাশি shared_ptr<>
একই পয়েন্টারটিকে নির্দেশ করে এমন সমস্ত বস্তুর একটি রেফারেন্স গণনা করে । যখন একটি নতুন তৈরি করা হয়, গণনাটি উপরে যায়। যখন একটি ধ্বংস হয়, গণনা হ্রাস পায়। গণনা শূন্যে পৌঁছে গেলে পয়েন্টারটি delete
d হয়।
সুতরাং এটি একটি সমস্যার পরিচয় করিয়ে দেয়: ডাবল-লিঙ্কযুক্ত কাঠামোগুলি বৃত্তাকার উল্লেখগুলির সাথে শেষ হয়। বলুন আমরা parent
আমাদের গাছে একটি পয়েন্টার যুক্ত করতে চাই Node
:
template<class T>
struct Node {
T value;
std::shared_ptr<Node<T>> parent;
std::shared_ptr<Node<T>> left;
std::shared_ptr<Node<T>> right;
};
এখন, আমরা যদি Node
কোনওটিকে সরিয়ে ফেলি, তবে এর সাথে একটি চক্রীয় রেফারেন্স রয়েছে। এটি কখনই delete
ডি হবে না কারণ এর রেফারেন্স গণনা কখনই শূন্য হবে না।
এই সমস্যাটি সমাধান করার জন্য, আপনি একটি ব্যবহার করুন std::weak_ptr<>
:
template<class T>
struct Node {
T value;
std::weak_ptr<Node<T>> parent;
std::shared_ptr<Node<T>> left;
std::shared_ptr<Node<T>> right;
};
এখন, জিনিসগুলি সঠিকভাবে কাজ করবে, এবং একটি নোড অপসারণ পিতামাতার নোডের আটকে রেফারেন্সগুলি ছাড়বে না। এটি গাছকে হাঁটাকে আরও জটিল করে তোলে, তবে:
std::shared_ptr<Node<T>> parent_of_this = node->parent.lock();
এইভাবে, আপনি নোডের একটি রেফারেন্স লক করতে পারেন এবং এটির কাজ করার সময় এটি অদৃশ্য হবে না এমন একটি যুক্তিসঙ্গত গ্যারান্টি রয়েছে, যেহেতু আপনি shared_ptr<>
এটির কোনও একটি ধরে রেখেছেন ।
make_shared
এবং make_unique
এখন, কিছু ছোটখাটো সমস্যা রয়েছে shared_ptr<>
এবং unique_ptr<>
এটি সমাধান করা উচিত। নিম্নলিখিত দুটি লাইনে একটি সমস্যা রয়েছে:
foo_unique(std::unique_ptr<SomeKindofObject>(new SomeKindOfObject()), thrower());
foo_shared(std::shared_ptr<SomeKindofObject>(new SomeKindOfObject()), thrower());
যদি thrower()
একটি ব্যতিক্রম ছুঁড়ে, উভয় লাইন মেমরি ফাঁস হবে। এবং তার চেয়েও বেশি বেশি, shared_ptr<>
রেফারেন্স গণনাটি তার অবজেক্টের থেকে দূরে চিহ্নিত করে এবং এটি দ্বিতীয় বরাদ্দের অর্থ হতে পারে)। এটি সাধারণত কাম্য নয়।
সি ++ 11 সরবরাহ করে std::make_shared<>()
এবং সি ++ 14 std::make_unique<>()
এই সমস্যাটি সমাধান করার জন্য সরবরাহ করে:
foo_unique(std::make_unique<SomeKindofObject>(), thrower());
foo_shared(std::make_shared<SomeKindofObject>(), thrower());
এখন, উভয় ক্ষেত্রেই, thrower()
ব্যতিক্রম ছুঁড়ে ফেলা হলেও , মেমরির ফাঁস হবে না। বোনাস হিসাবে, তার পরিচালিত অবজেক্টের মতো একই মেমরি স্পেসেmake_shared<>()
তার রেফারেন্স গণনা তৈরি করার সুযোগ রয়েছে , যা উভয়ই দ্রুততর হতে পারে এবং মেমরির কয়েকটি বাইট সংরক্ষণ করতে পারে, যখন আপনাকে একটি ব্যতিক্রমী সুরক্ষা গ্যারান্টি দেয়!
Qt সম্পর্কে নোটস
তবে এটি লক্ষ করা উচিত যে Qt, যা প্রি-সি ++ 11 সংকলককে অবশ্যই সমর্থন করে, তার নিজস্ব আবর্জনা সংগ্রহের মডেল রয়েছে: অনেকেরই QObject
এমন একটি ব্যবস্থা আছে যেখানে ব্যবহারকারীর প্রয়োজন ছাড়াই সেগুলি সঠিকভাবে ধ্বংস হয়ে delete
যায়।
আমি জানি না যে QObject
সি ++ 11 পরিচালিত পয়েন্টারগুলি পরিচালনা করে কীভাবে আচরণ করবে, তাই আমি বলতে পারি না shared_ptr<QDialog>
এটি একটি ভাল ধারণা। আমার কাছে নিশ্চিতভাবে বলতে কিউটিটির সাথে পর্যাপ্ত অভিজ্ঞতা নেই তবে আমি বিশ্বাস করি যে এই ব্যবহারের ক্ষেত্রে কিউটি 5 সামঞ্জস্য করা হয়েছে।