উত্তর:
একটি ভাল উদাহরণ একটি ক্যাশে হবে।
সম্প্রতি অ্যাক্সেস করা অবজেক্টের জন্য, আপনি এগুলিকে স্মৃতিতে রাখতে চান, তাই আপনি তাদের কাছে শক্তিশালী পয়েন্টার রেখেছেন। পর্যায়ক্রমে, আপনি ক্যাশে স্ক্যান করেন এবং সিদ্ধান্ত নিন যে কোন জিনিসগুলিতে সম্প্রতি অ্যাক্সেস করা হয়নি। আপনার এগুলি স্মৃতিতে রাখার দরকার নেই, তাই আপনি শক্ত পয়েন্টার থেকে মুক্তি পাবেন।
তবে কী যদি সেই অবজেক্টটি ব্যবহার হয় এবং অন্য কোনও কোড এতে দৃ strong় পয়েন্টার ধরে থাকে? যদি ক্যাশে তার একমাত্র পয়েন্টারটি অবজেক্টটির থেকে মুক্তি দেয় তবে এটি আর কখনও খুঁজে পাবে না। সুতরাং ক্যাশে বস্তুগুলির জন্য একটি দুর্বল পয়েন্টার রাখে যা তাদের স্মৃতিতে থাকার জন্য ঘটে কিনা তা খুঁজে পাওয়া দরকার।
এটি হ'ল দুর্বল পয়েন্টারটি যা করে - এটি আপনাকে যদি কোনও আশেপাশে থাকে তবে এটি সনাক্ত করতে দেয় তবে অন্য কোনও কিছুর প্রয়োজন না থাকলে এটিকে চারপাশে রাখে না।
std::weak_ptr
ঝুঁকির পয়েন্টার সমস্যাটি সমাধান করার একটি খুব ভাল উপায় । কেবল কাঁচা পয়েন্টার ব্যবহার করে উল্লেখ করা অসম্ভব যে রেফারেন্স করা ডেটাটি বাতিল করা হয়েছে কি না। পরিবর্তে, std::shared_ptr
কোনও ডেটা পরিচালনা করার অনুমতি দিয়ে এবং ডেটা std::weak_ptr
ব্যবহারকারীদের সরবরাহ করে, ব্যবহারকারীরা কল করে expired()
বা এর মাধ্যমে তথ্যের বৈধতা পরীক্ষা করতে পারেন lock()
।
আপনি std::shared_ptr
একা এটি করতে পারেন নি , কারণ সমস্ত std::shared_ptr
দৃষ্টান্তগুলি ডেটার মালিকানা ভাগ করে নেয় যা সমস্ত দৃষ্টান্ত অপসারণের আগে সরানো হয় না std::shared_ptr
। এখানে কীভাবে ঝুঁকিপূর্ণ পয়েন্টার ব্যবহার করে পরীক্ষা করতে হয় তার উদাহরণ এখানে দেওয়া হয়েছে lock()
:
#include <iostream>
#include <memory>
int main()
{
// OLD, problem with dangling pointer
// PROBLEM: ref will point to undefined data!
int* ptr = new int(10);
int* ref = ptr;
delete ptr;
// NEW
// SOLUTION: check expired() or lock() to determine if pointer is valid
// empty definition
std::shared_ptr<int> sptr;
// takes ownership of pointer
sptr.reset(new int);
*sptr = 10;
// get pointer to data without taking ownership
std::weak_ptr<int> weak1 = sptr;
// deletes managed object, acquires new pointer
sptr.reset(new int);
*sptr = 5;
// get pointer to new data without taking ownership
std::weak_ptr<int> weak2 = sptr;
// weak1 is expired!
if(auto tmp = weak1.lock())
std::cout << *tmp << '\n';
else
std::cout << "weak1 is expired\n";
// weak2 points to new data (5)
if(auto tmp = weak2.lock())
std::cout << *tmp << '\n';
else
std::cout << "weak2 is expired\n";
}
std::weak_ptr::lock
একটি নতুন তৈরি করে std::shared_ptr
যা পরিচালিত অবজেক্টের মালিকানা ভাগ করে দেয়।
আর একটি উত্তর, আশা করি সহজ। (সহ গুগলারের জন্য)
মনে করুন আপনার কাছে Team
এবং Member
অবজেক্টস রয়েছে।
স্পষ্টতই এটি একটি সম্পর্ক: Team
অবজেক্টটির এটিতে পয়েন্টার থাকবে Members
। এবং এটি সম্ভবত সদস্যদের তাদের Team
বস্তুর পিছনে পয়েন্টার থাকবে ।
তারপরে আপনার একটি নির্ভরতা চক্র রয়েছে। আপনি যদি ব্যবহার করেন তবে আপনি shared_ptr
যখন তাদের উপর রেফারেন্স পরিত্যাগ করবেন তখন অবজেক্টগুলি আর স্বয়ংক্রিয়ভাবে মুক্ত হবে না, কারণ তারা একে অপরকে চক্রীয় উপায়ে রেফারেন্স করে। এটি একটি স্মৃতি ফাঁস।
আপনি এটি ব্যবহার করে বিরতি দিন weak_ptr
। "মালিক" সাধারণত এটি ব্যবহার করে shared_ptr
এবং "মালিকানাধীন" weak_ptr
তার পিতামাতার কাছে এটি ব্যবহার করে এবং যখন তার পিতামাতার অ্যাক্সেসের প্রয়োজন হয় তখন এটিকে অস্থায়ীভাবে রূপান্তরিত করে shared_ptr
।
একটি দুর্বল পিটিআর সংরক্ষণ করুন:
weak_ptr<Parent> parentWeakPtr_ = parentSharedPtr; // automatic conversion to weak from shared
তারপরে প্রয়োজনে এটি ব্যবহার করুন
shared_ptr<Parent> tempParentSharedPtr = parentWeakPtr_.lock(); // on the stack, from the weak ptr
if( !tempParentSharedPtr ) {
// yes, it may fail if the parent was freed since we stored weak_ptr
} else {
// do stuff
}
// tempParentSharedPtr is released when it goes out of scope
shared_ptr
হ'ল মালিকানা ভাগ করে নেওয়া, সুতরাং কারও কাছে মেমরিটি মুক্ত করার বিশেষ দায় নেই, যখন আর ব্যবহার না করা হয় এটি স্বয়ংক্রিয়ভাবে মুক্ত হয়। যদি কোনও লুপ না থাকে ... আপনার কাছে বেশ কয়েকটি দল একই প্লেয়ার (বিগত দলগুলি) ভাগ করে নিতে পারে? যদি দলটির সদস্যরা সদস্যদের "মালিকানাধীন" থাকে তবে shared_ptr
শুরু করার জন্য একটি ব্যবহার করার দরকার নেই ।
shared_ptr
তার "টিম সদস্যরা" দ্বারাও রেফারেন্স করা হয়, কখন এটি ধ্বংস হয়ে যাবে? আপনি যা বর্ণনা করছেন তা এমন কোনও ঘটনা যেখানে কোনও লুপ নেই।
এখানে একটি উদাহরণ যা @ জ্লেহি দ্বারা আমাকে দেওয়া হয়েছে: ধরুন আপনার কাছে কাজগুলির একটি সংগ্রহ রয়েছে, অ্যাসিঙ্ক্রোনালি সম্পাদন করা হয়েছে এবং একটি দ্বারা পরিচালিত std::shared_ptr<Task>
। আপনি এই কাজগুলি পর্যায়ক্রমে কিছু করতে চাইতে পারেন, তাই একটি টাইমার ইভেন্ট কোনওটিকে অবিচ্ছিন্ন করতে পারে std::vector<std::weak_ptr<Task>>
এবং কাজগুলিকে কিছু করতে দেয়। তবে, একই সাথে কোনও কাজ একযোগে সিদ্ধান্ত নিয়েছে যে এটির আর দরকার নেই এবং মারা যাবে। টাইমার এইভাবে দুর্বল পয়েন্টার থেকে একটি ভাগ করে নেওয়া পয়েন্টার তৈরি করে এবং সেই অংশীদারি পয়েন্টারটি ব্যবহার করে টাস্কটি এখনও বেঁচে আছে কিনা তা পরীক্ষা করতে পারে, তবে শর্ত থাকে যে এটি বাতিল নয়।
এগুলি বুস্ট.অ্যাসিওর সাথে দরকারী যখন যখন আপনার গ্যারান্টি দেওয়া হয় না যে অ্যাসিঙ্ক্রোনাস হ্যান্ডলারটি আহ্বান করা হয় তখনও কোনও টার্গেট অবজেক্ট উপস্থিত থাকে। কৌশলটি হ'ল weak_ptr
অ্যাসিঙ্কোনাস হ্যান্ডলার অবজেক্টটিতে বাঁধাই , ল্যাম্বদা std::bind
ক্যাপচারগুলি ব্যবহার করে।
void MyClass::startTimer()
{
std::weak_ptr<MyClass> weak = shared_from_this();
timer_.async_wait( [weak](const boost::system::error_code& ec)
{
auto self = weak.lock();
if (self)
{
self->handleTimeout();
}
else
{
std::cout << "Target object no longer exists!\n";
}
} );
}
এটি self = shared_from_this()
বুস্ট.অ্যাসিও উদাহরণগুলিতে প্রায়শই দেখা যায় এমন আইডিয়মের একটি রূপ , যেখানে একটি মুলতুবি অ্যাসিনক্রোনাস হ্যান্ডলার লক্ষ্য অবজেক্টটির আয়ু দীর্ঘায়িত করতে পারে না , তবুও লক্ষ্য অবজেক্ট মুছে ফেলা সত্ত্বেও নিরাপদ।
this
self = shared_from_this()
হ্যান্ডলার যখন একই বর্গের মধ্যে পদ্ধতিগুলি আহ্বান করে তখন আইডিয়মটি ব্যবহার করার সময় অভ্যাসের বল প্রয়োগ করুন।
shared_ptr : আসল অবজেক্ট ধরে holds
দুর্বল_সিটিআর : lock
প্রকৃত মালিকের সাথে সংযোগ করতে ব্যবহার করে বা shared_ptr
অন্যথায় একটি এনএলএল প্রদান করে ।
মোটামুটিভাবে বলতে গেলে, weak_ptr
ভূমিকা আবাসন সংস্থার ভূমিকার সাথে সমান । এজেন্ট ছাড়া, ভাড়া নিয়ে বাড়ি পেতে আমাদের শহরে এলোমেলো বাড়িগুলি চেক করতে হতে পারে। এজেন্টরা নিশ্চিত করে যে আমরা কেবলমাত্র সেই বাড়িগুলি ঘুরে দেখি যা এখনও অ্যাক্সেসযোগ্য এবং ভাড়ার জন্য উপলব্ধ ।
weak_ptr
কোনও বস্তুর সঠিক মুছে ফেলা পরীক্ষা করা ভাল - বিশেষত ইউনিট পরীক্ষায়। সাধারণ ব্যবহারের ক্ষেত্রে এটির মতো দেখতে পাওয়া যায়:
std::weak_ptr<X> weak_x{ shared_x };
shared_x.reset();
BOOST_CHECK(weak_x.lock());
... //do something that should remove all other copies of shared_x and hence destroy x
BOOST_CHECK(!weak_x.lock());
পয়েন্টারগুলি ব্যবহার করার সময় উপলব্ধ বিভিন্ন ধরণের পয়েন্টার উপলব্ধ হওয়া এবং এটি প্রতিটি ব্যবহার করার জন্য যখন বোধগম্য হয় তা গুরুত্বপূর্ণ। নিম্নলিখিত হিসাবে দুটি বিভাগে চার ধরণের পয়েন্টার রয়েছে:
SomeClass* ptrToSomeClass = new SomeClass();
]std::unique_ptr<SomeClass> uniquePtrToSomeClass ( new SomeClass() );
std::shared_ptr<SomeClass> sharedPtrToSomeClass ( new SomeClass() );
std::weak_ptr<SomeClass> weakPtrToSomeWeakOrSharedPtr ( weakOrSharedPtr );
কাঁচা পয়েন্টার (কখনও কখনও "উত্তরাধিকারের পয়েন্টার" বা "সি পয়েন্টার" হিসাবে পরিচিত) 'বেয়ার-হাড়' পয়েন্টার আচরণ সরবরাহ করে এবং বাগ এবং মেমরি ফাঁসের একটি সাধারণ উত্স। কাঁচা নির্দেশক সংস্থানগুলির মালিকানা ট্র্যাক করার কোনও উপায় সরবরাহ করে না এবং বিকাশকারীরা মেমরি ফাঁস তৈরি করছে না তা নিশ্চিত করতে ম্যানুয়ালি 'মুছুন' কল করতে হবে। যদি রিসোর্সটি ভাগ করা হয় তবে এটি কঠিন হয়ে পড়ে কারণ কোনও বস্তু এখনও সম্পদের দিকে ইশারা করছে কিনা তা চ্যালেঞ্জ হতে পারে। এই কারণে, কাঁচা পয়েন্টারগুলি সাধারণত এড়ানো উচিত এবং কেবল সীমিত সুযোগের সাথে কোডটির পারফরম্যান্স-সমালোচনা বিভাগগুলিতে ব্যবহার করা উচিত।
অনন্য পয়েন্টার হ'ল একটি প্রাথমিক স্মার্ট পয়েন্টার যা সংস্থার অন্তর্নিহিত কাঁচা পয়েন্টারটির 'মালিকানাধীন' এবং অনন্য পয়েন্টারটির বাইরে চলে যাওয়া অবজেক্টটি একবার 'অবৈধ পয়েন্টার' এর মালিকানাধীন অবজেক্টটিকে 'ডিলিট' করতে এবং বরাদ্দ হওয়া মেমরি মুক্ত করার জন্য দায়ী। 'অনন্য' নামটি এই সত্যটিকে বোঝায় যে একটি নির্দিষ্ট সময়ে সময়ে একটি মাত্র পন্য অনন্য পয়েন্টারটির 'মালিকানা' নিতে পারে। মুভি কমান্ডের মাধ্যমে মালিকানা অন্য কোনও জিনিসে স্থানান্তরিত হতে পারে তবে কোনও অনন্য পয়েন্টারটি কখনও অনুলিপি বা ভাগ করা যায় না। এই কারণগুলির জন্য, অনন্য পয়েন্টারগুলি কাঁচা পয়েন্টারগুলির ক্ষেত্রে একটি উপযুক্ত বিকল্প যে নির্দিষ্ট সময়ে কেবলমাত্র একটি পয়েন্টারটির জন্য পয়েন্টার প্রয়োজন হয়, এবং এটি বিকাশকারীকে তার নিজস্ব অবজেক্টের লাইফসাইকেলের শেষে মেমরি মুক্ত করার প্রয়োজন থেকে হ্রাস করে।
ভাগ করা পয়েন্টারগুলি হ'ল অন্য ধরণের স্মার্ট পয়েন্টার যা অনন্য পয়েন্টারগুলির সমান, তবে অনেকগুলি অবজেক্টের জন্য ভাগ করা পয়েন্টারগুলির মালিকানা পেতে দেয়। অনন্য পয়েন্টারগুলির মতো, ভাগ করা পয়েন্টারগুলি সমস্ত বস্তু সংস্থানটির দিকে ইঙ্গিত করার পরে বরাদ্দ মেমরি মুক্ত করার জন্য দায়ী। এটি রেফারেন্স কাউন্টিং নামে একটি কৌশল দিয়ে এটি সম্পাদন করে। প্রতিবার কোনও নতুন অবজেক্ট ভাগ করা পয়েন্টারের মালিকানা নিলে রেফারেন্স গণনা একে একে বাড়ানো হয়। একইভাবে, যখন কোনও বস্তু সুযোগের বাইরে চলে যায় বা উত্সটির দিকে ইশারা করে বন্ধ করে দেয়, রেফারেন্স গণনাটি একে একে হ্রাস পায়। রেফারেন্স গণনা শূন্যে পৌঁছে গেলে বরাদ্দ হওয়া মেমরিটি মুক্ত হয়। এই কারণে, ভাগ করা পয়েন্টারগুলি হ'ল একটি শক্তিশালী ধরণের স্মার্ট পয়েন্টার যা যে কোনও সময় একাধিক অবজেক্টকে একই উত্সকে নির্দেশ করতে হবে used
অবশেষে, দুর্বল পয়েন্টারগুলি হ'ল স্মার্ট পয়েন্টারগুলির অন্য ধরণের যা সরাসরি কোনও উত্সকে নির্দেশ করার পরিবর্তে তারা অন্য পয়েন্টারটির দিকে নির্দেশ করে (দুর্বল বা ভাগ করে নেওয়া)। দুর্বল পয়েন্টারগুলি সরাসরি কোনও বস্তু অ্যাক্সেস করতে পারে না তবে তারা জানাতে পারে যে অবজেক্টটি এখনও বিদ্যমান আছে বা এটির মেয়াদ শেষ হয়ে গেছে কিনা। পয়েন্ট-টু অবজেক্টে অ্যাক্সেস করার জন্য দুর্বল পয়েন্টারটিকে অস্থায়ীভাবে ভাগ করে নেওয়া পয়েন্টারে রূপান্তরিত করা যায় (শর্ত থাকে যে এটি এখনও বিদ্যমান)। উদাহরণস্বরূপ, নিম্নলিখিত উদাহরণটি বিবেচনা করুন:
উদাহরণস্বরূপ, বৈঠক বি সম্পর্কিত আপনার দুর্বল পয়েন্টার রয়েছে আপনি মিটিং বি তে কোনও "মালিক" নন যাতে এটি আপনাকে ছাড়া শেষ হতে পারে এবং আপনি যাচাই না করে জানেন না এটি শেষ হয়েছে কিনা তা আপনি জানেন না। যদি এটি শেষ না হয়, আপনি যোগ দিতে এবং অংশ নিতে পারেন, অন্যথায়, আপনি পারবেন না। এটি মিটিং বি-তে ভাগ করে নেওয়ার চেয়ে আলাদা কারণ কারণ আপনি মিটিং এ এবং মিটিং বি উভয়েরই "মালিক" হবেন (একই সাথে উভয় অংশ নেওয়া)।
উদাহরণটি ব্যাখ্যা করে যে কোনও দুর্বল পয়েন্টার কীভাবে কাজ করে এবং কার্যকর যখন কোনও বস্তুর বাইরের পর্যবেক্ষক হওয়া দরকার তবে মালিকানা ভাগ করে নেওয়ার দায়িত্ব চান না। এটি দৃশ্যে বিশেষভাবে কার্যকর যে দুটি বস্তুর একে অপরের দিকে নির্দেশ করা প্রয়োজন (ওরফে একটি বিজ্ঞপ্তি রেফারেন্স)। ভাগ করা পয়েন্টারগুলির সাথে, কোনও অবজেক্ট প্রকাশ করা যায় না কারণ তারা অন্য বস্তুর দ্বারা এখনও 'দৃ strongly়ভাবে' নির্দেশিত। যখন পয়েন্টারগুলির মধ্যে একটি দুর্বল পয়েন্টার হয় তখন দুর্বল পয়েন্টারটি ধারণ করে থাকা বস্তুটি যখন প্রয়োজন হয় তখন প্রয়োজনে অন্য বস্তুটি অ্যাক্সেস করতে পারে provided
ইতিমধ্যে উল্লিখিত অন্যান্য বৈধ ব্যবহারের ক্ষেত্রগুলি ছাড়াও std::weak_ptr
বহুবিবাহিত পরিবেশের একটি দুর্দান্ত সরঞ্জাম, কারণ
std::shared_ptr
একত্রে সঙ্গে std::weak_ptr
বিপরীত মধ্যে - পয়েন্টার আনত বিরুদ্ধে নিরাপদ std::unique_ptr
কাঁচা পয়েন্টার সাথেstd::weak_ptr::lock()
একটি পারমাণবিক অপারেশন ( দুর্বল_পিটারের থ্রেড-সুরক্ষা সম্পর্কেও দেখুন )ডিরেক্টরিগুলির সমস্ত চিত্র (~ 10.000) একসাথে মেমরিতে লোড করার জন্য কোনও কার্য বিবেচনা করুন (যেমন একটি থাম্বনেইল ক্যাশে হিসাবে)। অবশ্যই এটির সর্বোত্তম উপায় হ'ল একটি নিয়ন্ত্রণ থ্রেড, যা চিত্রগুলি পরিচালনা করে এবং পরিচালনা করে এবং একাধিক কর্মী থ্রেড, যা চিত্রগুলি লোড করে। এখন এটি একটি সহজ কাজ। এখানে খুব সরলকরণের বাস্তবায়ন রয়েছে ( join()
ইত্যাদি বাদ দেওয়া হয়েছে, থ্রেডগুলি বাস্তব বাস্তবায়নে আলাদাভাবে পরিচালনা করতে হবে ইত্যাদি)
// a simplified class to hold the thumbnail and data
struct ImageData {
std::string path;
std::unique_ptr<YourFavoriteImageLibData> image;
};
// a simplified reader fn
void read( std::vector<std::shared_ptr<ImageData>> imagesToLoad ) {
for( auto& imageData : imagesToLoad )
imageData->image = YourFavoriteImageLib::load( imageData->path );
}
// a simplified manager
class Manager {
std::vector<std::shared_ptr<ImageData>> m_imageDatas;
std::vector<std::unique_ptr<std::thread>> m_threads;
public:
void load( const std::string& folderPath ) {
std::vector<std::string> imagePaths = readFolder( folderPath );
m_imageDatas = createImageDatas( imagePaths );
const unsigned numThreads = std::thread::hardware_concurrency();
std::vector<std::vector<std::shared_ptr<ImageData>>> splitDatas =
splitImageDatas( m_imageDatas, numThreads );
for( auto& dataRangeToLoad : splitDatas )
m_threads.push_back( std::make_unique<std::thread>(read, dataRangeToLoad) );
}
};
তবে চিত্রগুলি লোড করতে বাধা দিতে চাইলে এটি আরও জটিল হয়ে যায়, উদাহরণস্বরূপ, কারণ ব্যবহারকারী একটি ভিন্ন ডিরেক্টরি চয়ন করেছেন। অথবা আপনি যদি পরিচালককে ধ্বংস করতে চান তবেও।
আপনার m_imageDatas
ক্ষেত্র পরিবর্তন করার আগে আপনার থ্রেড যোগাযোগের প্রয়োজন এবং সমস্ত লোডার থ্রেড বন্ধ করতে হবে । অন্যথায় লোডার সমস্ত চিত্র সম্পন্ন না হওয়া পর্যন্ত লোড চালিয়ে যাবে - এমনকি যদি তারা ইতিমধ্যে অপ্রচলিত হয়। সরল উদাহরণে, এটি খুব কঠিন হবে না, তবে একটি বাস্তব পরিবেশে জিনিসগুলি আরও জটিল হতে পারে।
থ্রেড সম্ভবত একটি থ্রেড পুল একাধিক পরিচালক, এর মধ্যে কয়েকটি বন্ধ হচ্ছে দ্বারা ব্যবহৃত অংশ হতে হবে, এবং কিছু নয় ইত্যাদি সহজ পরামিতি imagesToLoad
একটি লক কিউ, যা ঐ পরিচালকদের বিভিন্ন নিয়ন্ত্রণ থ্রেড থেকে তাদের চিত্র অনুরোধ ধাক্কা হবে পাঠকদের অনুরোধগুলি পপিংয়ের সাথে - একটি নির্বিচারে ক্রমে - অন্য প্রান্তে। এবং তাই যোগাযোগটি কঠিন, ধীর এবং ত্রুটি-প্রবণ হয়ে ওঠে। এই জাতীয় ক্ষেত্রে অতিরিক্ত কোনও যোগাযোগ এড়ানোর খুব মার্জিত উপায় হ'ল std::shared_ptr
এটির সাথে ব্যবহার করে std::weak_ptr
।
// a simplified reader fn
void read( std::vector<std::weak_ptr<ImageData>> imagesToLoad ) {
for( auto& imageDataWeak : imagesToLoad ) {
std::shared_ptr<ImageData> imageData = imageDataWeak.lock();
if( !imageData )
continue;
imageData->image = YourFavoriteImageLib::load( imageData->path );
}
}
// a simplified manager
class Manager {
std::vector<std::shared_ptr<ImageData>> m_imageDatas;
std::vector<std::unique_ptr<std::thread>> m_threads;
public:
void load( const std::string& folderPath ) {
std::vector<std::string> imagePaths = readFolder( folderPath );
m_imageDatas = createImageDatas( imagePaths );
const unsigned numThreads = std::thread::hardware_concurrency();
std::vector<std::vector<std::weak_ptr<ImageData>>> splitDatas =
splitImageDatasToWeak( m_imageDatas, numThreads );
for( auto& dataRangeToLoad : splitDatas )
m_threads.push_back( std::make_unique<std::thread>(read, dataRangeToLoad) );
}
};
এই বাস্তবায়নটি প্রথমটির মতো প্রায় সহজ, কোনও অতিরিক্ত থ্রেড যোগাযোগের প্রয়োজন নেই এবং এটি বাস্তবায়নের জন্য থ্রেড পুল / সারিটির অংশ হতে পারে। মেয়াদোত্তীর্ণ চিত্রগুলি এড়িয়ে যাওয়া, এবং অ-মেয়াদোত্তীর্ণ চিত্রগুলি প্রক্রিয়াজাত করা হয়, তাই স্বাভাবিক ক্রিয়াকলাপের সময় থ্রেডগুলি কখনও থামানো উচিত নয়। মালিকের পয়েন্টারটির মেয়াদ শেষ না হলে আপনি সর্বদা নিরাপদে পথ পরিবর্তন করতে বা আপনার পরিচালকদের ধ্বংস করতে পারেন the
http://en.cppreferences.com/w/cpp/memory/weak_ptr std :: দুর্বল_ptr একটি স্মার্ট পয়েন্টার যা স্ট্যান্ড :: শেয়ারড_পিটিআর দ্বারা পরিচালিত একটি অবজেক্টের একটি নন-মালিকানাধীন ("দুর্বল") রেফারেন্স ধরে। রেফারেন্সযুক্ত অবজেক্টটি অ্যাক্সেস করার জন্য এটি অবশ্যই std :: सामायिक_ptr এ রূপান্তর করতে হবে।
std :: দুর্বল_পিটার মডেলগুলি অস্থায়ী মালিকানা: যখন কোনও অ্যাক্সেস কেবল তখনই অ্যাক্সেস করার প্রয়োজন হয় এবং এটি অন্য কারও দ্বারা মুছে ফেলা হতে পারে, যখন std :: দুর্বল_ptr অবজেক্টটি ট্র্যাক করতে ব্যবহৃত হয় এবং এটি স্টেডি তে রূপান্তরিত হয়: : অস্থায়ী মালিকানা অনুমান করতে ভাগ করা_পিটার। যদি এই মুহুর্তে মূল স্ট্যান্ড :: শেয়ার্ড_পিটারটি ধ্বংস হয়ে যায়, অস্থায়ী স্টাড :: শেয়ার্ড_পিটার পাশাপাশি ধ্বংস হওয়া অবধি অবজেক্টের আজীবন প্রসারিত হবে।
তদতিরিক্ত, স্টাড :: দুর্বল_পিটিআর স্ট্যান্ড :: শেয়ার্ড_পিটারের বিজ্ঞপ্তি রেফারেন্স ভাঙতে ব্যবহৃত হয়।
ভাগ করে নেওয়া পয়েন্টারের একটি অপূর্ণতা রয়েছে: ভাগ করা_পয়েন্টার পিতামাতার-চক্র নির্ভরতা পরিচালনা করতে পারে না। এর অর্থ যদি পিতামাত্ত শ্রেণি একটি ভাগ করা পয়েন্টার ব্যবহার করে শিশু শ্রেণীর অবজেক্ট ব্যবহার করে তবে একই ফাইলটিতে যদি শিশু শ্রেণি পিতামাতার শ্রেণীর অবজেক্ট ব্যবহার করে। ভাগ করা পয়েন্টারটি সমস্ত অবজেক্টকে ধ্বংস করতে ব্যর্থ হবে, এমনকি ভাগ করা পয়েন্টার চক্র নির্ভরতার দৃশ্যে ডেস্ট্রাক্টরকে কল করা মোটেই নেই। মূলত ভাগ করা পয়েন্টার রেফারেন্স গণনা প্রক্রিয়া সমর্থন করে না।
এই ত্রুটিটি আমরা দুর্বল_পয়েন্টার ব্যবহার করে কাটিয়ে উঠতে পারি।
weak_ptr
প্রোগ্রামের যুক্তিতে কোন পরিবর্তন ছাড়াই একটি ড্রপ-ইন প্রতিস্থাপন হিসাবে একটি বিজ্ঞপ্তি নির্ভরতা কীভাবে ডিল করতে পারে shared_ptr
?" :-)
আমরা যখন বস্তুর মালিকানা নিতে চাই না:
উদা:
class A
{
shared_ptr<int> sPtr1;
weak_ptr<int> wPtr1;
}
উপরের শ্রেণিতে ডাব্লুপিটিআর 1 ডাব্লুপিটিআর 1 দ্বারা নির্দেশিত সংস্থানটির মালিক নয়। যদি রিসোর্সটি মুছে ফেলা হয় তবে ডাব্লুপিটিআর 1 এর মেয়াদ শেষ হয়ে গেছে।
বিজ্ঞপ্তি নির্ভরতা এড়াতে:
shard_ptr<A> <----| shared_ptr<B> <------
^ | ^ |
| | | |
| | | |
| | | |
| | | |
class A | class B |
| | | |
| ------------ |
| |
-------------------------------------
এখন যদি আমরা বি এবং এ শ্রেণীর ভাগ করা_প্টর করি তবে উভয় পয়েন্টারের ব্যবহার_সংখ্যা দুটি হবে।
যখন শেয়ার্ড_পিটার অদ্ভুত সুযোগের বাইরে চলে যায় তখন গণনাটি এখনও 1 টি থাকে এবং তাই A এবং B অবজেক্ট মুছে যায় না।
class B;
class A
{
shared_ptr<B> sP1; // use weak_ptr instead to avoid CD
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void setShared(shared_ptr<B>& p)
{
sP1 = p;
}
};
class B
{
shared_ptr<A> sP1;
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
void setShared(shared_ptr<A>& p)
{
sP1 = p;
}
};
int main()
{
shared_ptr<A> aPtr(new A);
shared_ptr<B> bPtr(new B);
aPtr->setShared(bPtr);
bPtr->setShared(aPtr);
return 0;
}
আউটপুট:
A()
B()
আমরা আউটপুট থেকে দেখতে পাচ্ছি যে এ এবং বি পয়েন্টার কখনই মুছে ফেলা হয় না এবং তাই মেমরি ফাঁস হয়।
এ জাতীয় সমস্যা এড়াতে কেবল ভাগ করা_পিটারের পরিবর্তে ক্লাস এ-তে দুর্বল_পিটার ব্যবহার করুন যা আরও অর্থবোধ করে।
আমি দেখতে std::weak_ptr<T>
হিসেবে হ্যান্ডেল একটি থেকে std::shared_ptr<T>
: এটা আমাকে করতে পারবেন std::shared_ptr<T>
যদি এটা এখনও বিদ্যমান, কিন্তু এটা তার সারা জীবনের প্রসারিত করা হবে না। এই জাতীয় দৃষ্টিকোণটি কার্যকর হলে বেশ কয়েকটি পরিস্থিতি রয়েছে:
// Some sort of image; very expensive to create.
std::shared_ptr< Texture > texture;
// A Widget should be able to quickly get a handle to a Texture. On the
// other hand, I don't want to keep Textures around just because a widget
// may need it.
struct Widget {
std::weak_ptr< Texture > texture_handle;
void render() {
if (auto texture = texture_handle.get(); texture) {
// do stuff with texture. Warning: `texture`
// is now extending the lifetime because it
// is a std::shared_ptr< Texture >.
} else {
// gracefully degrade; there's no texture.
}
}
};
আর একটি গুরুত্বপূর্ণ দৃশ্য হ'ল ডেটা স্ট্রাকচারে চক্র ভাঙ্গা।
// Asking for trouble because a node owns the next node, and the next node owns
// the previous node: memory leak; no destructors automatically called.
struct Node {
std::shared_ptr< Node > next;
std::shared_ptr< Node > prev;
};
// Asking for trouble because a parent owns its children and children own their
// parents: memory leak; no destructors automatically called.
struct Node {
std::shared_ptr< Node > parent;
std::shared_ptr< Node > left_child;
std::shared_ptr< Node > right_child;
};
// Better: break dependencies using a std::weak_ptr (but not best way to do it;
// see Herb Sutter's talk).
struct Node {
std::shared_ptr< Node > next;
std::weak_ptr< Node > prev;
};
// Better: break dependencies using a std::weak_ptr (but not best way to do it;
// see Herb Sutter's talk).
struct Node {
std::weak_ptr< Node > parent;
std::shared_ptr< Node > left_child;
std::shared_ptr< Node > right_child;
};
ভেষজ সুটারের একটি দুর্দান্ত কথা রয়েছে যা ডিফল্ট দ্বারা লিক ফ্রিডম নিশ্চিত করার জন্য ভাষার বৈশিষ্ট্যগুলির (এই ক্ষেত্রে স্মার্ট পয়েন্টারগুলি) সর্বোত্তম ব্যবহারের ব্যাখ্যা দেয় (যার অর্থ: নির্মাণের দ্বারা সমস্ত কিছু জায়গায় ক্লিক করা হয়; আপনি এটি খুব সহজেই এড়িয়ে যেতে পারেন)। এটা অবশ্যই দেখতে হবে।