উত্তর:
এটি আপনাকে একটি বৈধ shared_ptr
উদাহরণ পেতে সক্ষম করে this
, যখন আপনার সমস্ত কিছু থাকে this
। তা ছাড়া, আপনি যদি একটি পাবার কোন উপায় থাকবে shared_ptr
করার this
, যদি না আপনি ইতিমধ্যে একজন সদস্য হিসেবে এক ছিল। সক্ষম_শ্রেড_ফর্ম_এর জন্য বুস্ট ডকুমেন্টেশন থেকে এই উদাহরণ :
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_from_this();
}
}
int main()
{
shared_ptr<Y> p(new Y);
shared_ptr<Y> q = p->f();
assert(p == q);
assert(!(p < q || q < p)); // p and q must share ownership
}
পদ্ধতিটি f()
কোনও বৈধ ফেরত দেয় shared_ptr
, যদিও এর কোনও সদস্যের উদাহরণ নেই instance মনে রাখবেন আপনি কেবল এটি করতে পারবেন না:
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_ptr<Y>(this);
}
}
এই ভাগ করা পয়েন্টার যে এই ফিরে এসেছে তার "যথাযথ" একটির থেকে আলাদা রেফারেন্স গণনা থাকবে এবং অবজেক্টটি মোছার সাথে সাথে তার মধ্যে একটি হারাতে হবে এবং ঝুঁকতে থাকা রেফারেন্সটি ধারণ করবে।
enable_shared_from_this
সি ++ 11 মানের অংশে পরিণত হয়েছে। আপনি এটি সেখান থেকে পাশাপাশি বুস্ট থেকেও পেতে পারেন।
std::shared_ptr
std::enable_shared_from_this
std::shared_ptr
অন্যের দ্বারা ইতিমধ্যে পরিচালিত কোনও অবজেক্টের জন্য একটি নির্মাণ করা std::shared_ptr
অভ্যন্তরীণভাবে সঞ্চিত দুর্বল রেফারেন্সের সাথে পরামর্শ করবে না এবং এভাবে অপরিবর্তিত আচরণের দিকে পরিচালিত করবে।" ( en.cppreferences.com/w/cpp/memory/enable_shared_from_this )
shared_ptr<Y> q = p
?
std::make_shared<T>
।
দুর্বল পয়েন্টারগুলির বিষয়ে ডাঃ ডবস নিবন্ধ থেকে, আমি মনে করি এই উদাহরণটি বোঝা সহজ (উত্স: http://drdobbs.com/cpp/184402026 ):
... এর মতো কোড সঠিকভাবে কাজ করবে না:
int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);
দুজনের কেউই নেই shared_ptr
বস্তুর কোনওটিই অন্যটির সম্পর্কে জানে না, তাই উভয়ই যখন তারা ধ্বংস হয়ে যায় তখন সংস্থানটি ছেড়ে দেওয়ার চেষ্টা করবে। এটি সাধারণত সমস্যার দিকে পরিচালিত করে।
একইভাবে, যদি কোনও সদস্য ফাংশনটির জন্য এমন কোনও shared_ptr
বস্তুর প্রয়োজন হয় যা তার যে পণ্যটির উপর কল করা হচ্ছে তার মালিকানা পায়, তবে এটি কেবল ফ্লাইতে কোনও বস্তু তৈরি করতে পারে না:
struct S
{
shared_ptr<S> dangerous()
{
return shared_ptr<S>(this); // don't do this!
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->dangerous();
return 0;
}
এই কোডটির পূর্ববর্তী উদাহরণের মতো একই সমস্যা রয়েছে, যদিও আরও সূক্ষ্ম আকারে। যখন এটি নির্মিত হয়, shared_pt
আর অবজেক্টটি sp1
সদ্য বরাদ্দকৃত সংস্থার মালিকানায়। কোড সদস্য ফাংশন ভিতরে S::dangerous
যে কথা কে না জানে shared_ptr
বস্তু, তাই shared_ptr
বস্তুর এটি ফেরৎ থেকে স্বতন্ত্র sp1
। নতুন shared_ptr
অবজেক্টটি অনুলিপি করা sp2
সাহায্য করে না; যখন sp2
সুযোগের বাইরে চলে যায়, এটি সংস্থানটি প্রকাশ করবে এবং যখন sp1
সুযোগের বাইরে চলে যাবে তখন এটি পুনরায় সংস্থানটি প্রকাশ করবে।
এই সমস্যাটি এড়ানোর উপায় শ্রেণীর টেম্পলেটটি ব্যবহার করা enable_shared_from_this
। টেমপ্লেটটি একটি টেম্পলেট ধরণের আর্গুমেন্ট গ্রহণ করে, এটি শ্রেণীবদ্ধের নাম যা পরিচালিত সংস্থানটিকে সংজ্ঞায়িত করে। সেই শ্রেণিকে অবশ্যই পরিবর্তে টেম্পলেট থেকে প্রকাশ্যে নেওয়া উচিত; এটার মত:
struct S : enable_shared_from_this<S>
{
shared_ptr<S> not_dangerous()
{
return shared_from_this();
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->not_dangerous();
return 0;
}
আপনি যখন এটি করেন, মনে রাখবেন যে আপনি যে বস্তুর উপরে কল করবেন তা shared_from_this
অবশ্যই কোনও shared_ptr
অবজেক্টের মালিকানাধীন । এটি কাজ করবে না:
int main()
{
S *p = new S;
shared_ptr<S> sp2 = p->not_dangerous(); // don't do this
}
shared_ptr<S> sp1(new S);
এটির পক্ষে পছন্দ করা যেতে পারে shared_ptr<S> sp1 = make_shared<S>();
, উদাহরণস্বরূপ দেখুন stackoverflow.com/questions/18301511/…
shared_ptr<S> sp2 = p->not_dangerous();
কারণ এখানে সমস্যাটি হ'ল shared_from_this()
প্রথমবার কল করার আগে আপনাকে অবশ্যই একটি শেয়ারড_পিটার তৈরি করতে হবে ! এটি ভুল করা সত্যিই সহজ! সি ++ 17 আগে এটা UB ডাকতে shared_from_this()
: সামনে ঠিক একটি shared_ptr স্বাভাবিক ভাবেই তৈরি করা হয়েছে auto sptr = std::make_shared<S>();
বা shared_ptr<S> sptr(new S());
। ধন্যবাদ C ++ 17 এর পরে এমনটি করা ছুঁড়ে যাবে।
S* s = new S(); shared_ptr<S> ptr = s->not_dangerous();
<- এটি শুধুমাত্র পূর্ববর্তী শেয়ারকৃত অবজেক্টে, যেমন স্টাড :: শেয়ারড_পিটি <টি> দ্বারা পরিচালিত কোনও আইটেমে শেয়ারড_ফর্ম_থেকে কল করার অনুমতি রয়েছে। অন্যথায় আচরণটি অপরিজ্ঞাত করা হয়েছে (সি ++ 17 অবধি) স্টেড :: খারাপ_উইক_পিটার নিক্ষেপ করা হয়েছে (ডিফল্ট-নির্মিত-দুর্বল_এটি থেকে শেয়ার্ড_পিটার কনস্ট্রাক্টর দ্বারা) (সি ++ 17 থেকে)। । সুতরাং বাস্তবতা হ'ল এটি বলা উচিত always_dangerous()
, কারণ এটি ইতিমধ্যে ভাগ করা হয়েছে কিনা তা আপনার জ্ঞানের প্রয়োজন।
বাদাম এবং বল্টির দৃষ্টিকোণ থেকে আমার ব্যাখ্যা এখানে রয়েছে (শীর্ষ উত্তর আমার সাথে 'ক্লিক করেনি')। * মনে রাখবেন যে এটি ভাগ করা_পিটার এবং সক্ষম_শ্রেড_ফ্রম_সটি জন্য ভিজ্যুয়াল স্টুডিও ২০১২ এর সাথে উত্স অনুসন্ধানের ফলাফল Perhaps সম্ভবত অন্যান্য সংকলকগণ সক্ষম_শ্রেড_ফর্ম_এটি ভিন্নভাবে প্রয়োগ করে ... *
enable_shared_from_this<T>
weak_ptr<T>
উদাহরণস্বরূপ T
' একটি সত্য রেফারেন্স গণনা ' ধারণ করে এমন একটি ব্যক্তিগত উদাহরণ যুক্ত করে T
।
সুতরাং, আপনি যখন প্রথম shared_ptr<T>
কোনও নতুন টি * তে একটি তৈরি করেন, তখন টি-র অভ্যন্তরীণ দুর্বল_পিটারটি 1 এর পুনঃনিরোধক দিয়ে সূচনা হয় The নতুন shared_ptr
মূলত এটির পিছনে থাকে weak_ptr
।
T
তারপরে, তার পদ্ধতিগুলিতে, একই অভ্যন্তরীণভাবে সঞ্চিত রেফারেন্স গণনায় সেই ব্যাকগুলিরshared_from_this
একটি উদাহরণ পাওয়ার জন্য কল করতে পারে । এইভাবে, আপনার সর্বদা এক জায়গায় থাকে যেখানে একে অপরের সম্পর্কে না জেনে একাধিক উদাহরণ থাকার চেয়ে রেফ-কাউন্ট সংরক্ষণ করা হয় এবং প্রত্যেকে মনে করেন যে তারা তারাই রেফ গণনা এবং মুছে ফেলার দায়িত্বে আছে যখন তাদের রেফ হিসাব শূন্যে পৌঁছেছে।shared_ptr<T>
T*
shared_ptr
shared_ptr
T
So, when you first create...
কারণ এটি একটি প্রয়োজনীয়তা (যেমন আপনি বলছেন দুর্বল_সিপিটি আরম্ভ করা হয় না যতক্ষণ না আপনি অবজেক্ট পয়েন্টারকে একটি শেয়ার্ড_সিপিটি কর্টারে পাস না করেন!) এবং এই প্রয়োজনীয়তাটি যদি আপনি হন তবে জিনিসগুলি মারাত্মকভাবে ভুল হতে পারে where সাবধান না আপনি shared_from_this
ইউবি পাওয়ার আগে কল করার আগে যদি আপনি কোনও শেয়ারড_পিটার না তৈরি করেন - একইভাবে আপনি যদি একাধিক শেয়ারড_পিটার তৈরি করেন তবে আপনিও ইউবি পাবেন। আপনি একরকম নিশ্চিত করুন যে আপনি একটি shared_ptr তৈরি করতে হবে ঠিক একবার।
enable_shared_from_this
ভঙ্গুর, যেহেতু বিন্দুটি একটি shared_ptr<T>
থেকে একটি পেতে সক্ষম হতে পারে T*
তবে বাস্তবে আপনি যখন একটি পয়েন্টার T* t
পান তবে এটি ইতিমধ্যে ভাগ হয়ে গেছে বা না সে সম্পর্কে কিছুই অনুমান করা নিরাপদ নয় এবং ভুল অনুমান করা ইউবি হয়।
নোট করুন যে একটি বুস্ট :: ইন্টুসিভ_পিটার ব্যবহার করে এই সমস্যাটি ভুগছে না। এটি প্রায়শই এই সমস্যাটি ঘুরে দেখার আরও বেশি সুবিধাজনক উপায়।
enable_shared_from_this
আপনাকে এমন একটি এপিআই দিয়ে কাজ করতে দেয় যা বিশেষত গ্রহণ করে shared_ptr<>
। আমার মতে, এই জাতীয় একটি এপিআই হ'ল সাধারণত এটি করা ভুল হয় (কারণ স্ট্যাকের মধ্যে কিছু উচ্চতর মেমরির মালিকানা দেওয়া ভাল) তবে আপনি যদি এই জাতীয় কোনও এপিআইয়ের সাথে কাজ করতে বাধ্য হন তবে এটি একটি ভাল বিকল্প।
এটি সি ++ 11 এবং পরবর্তী ক্ষেত্রে ঠিক একই: এটি আপনাকে একটি কাঁচা পয়েন্টার দেয় বলে this
ভাগ করে নেওয়া পয়েন্টার হিসাবে ফিরে আসার ক্ষমতা সক্ষম করে this
।
অন্য কথায়, এটি আপনাকে এই জাতীয় কোড ঘুরিয়ে দেওয়ার অনুমতি দেয়
class Node {
public:
Node* getParent const() {
if (m_parent) {
return m_parent;
} else {
return this;
}
}
private:
Node * m_parent = nullptr;
};
এটিতে:
class Node : std::enable_shared_from_this<Node> {
public:
std::shared_ptr<Node> getParent const() {
std::shared_ptr<Node> parent = m_parent.lock();
if (parent) {
return parent;
} else {
return shared_from_this();
}
}
private:
std::weak_ptr<Node> m_parent;
};
shared_ptr
। আপনি ইন্টারফেসটি পরিবর্তন করতে চান এটি নিশ্চিত হওয়ার জন্য।
std::shared_ptr<Node> getParent const()
, আমি সাধারণত এটির NodePtr getParent const()
পরিবর্তে প্রকাশ করব । আপনার যদি অভ্যন্তরীণ কাঁচা পয়েন্টারটিতে একেবারে অ্যাক্সেসের প্রয়োজন হয় (সেরা উদাহরণ: একটি সি লাইব্রেরির সাথে ডিল করা), রয়েছেstd::shared_ptr<T>::get
জন্য এটি রয়েছে, যা উল্লেখ করা আমি ঘৃণা করি কারণ এই কাঁচা পয়েন্টার অ্যাক্সেসরটি ভুল কারণে অনেকবার ব্যবহার করেছি।
আরেকটি উপায় হ'ল একটি weak_ptr<Y> m_stub
সদস্যকে যুক্ত করুন class Y
। তারপর লিখ:
shared_ptr<Y> Y::f()
{
return m_stub.lock();
}
আপনি যখন ক্লাসটি সংগ্রহ করছেন তা পরিবর্তন করতে পারবেন না (যেমন অন্যান্য ব্যক্তির লাইব্রেরি প্রসারিত) যখন দরকারী। সদস্যকে সূচনা করতে ভুলবেন না, যেমন দ্বারাm_stub = shared_ptr<Y>(this)
, এটি কোনও নির্মাণকারীর সময়ও বৈধ।
উত্তরাধিকার শ্রেণিবিন্যাসে যদি এর মতো আরও কিছু স্টাব থাকে তবে এটি অবজেক্টের ধ্বংসকে আটকাবে না OK
সম্পাদনা: ব্যবহারকারী নোবার দ্বারা সঠিকভাবে নির্দেশিত হিসাবে, অ্যাসাইনমেন্টটি শেষ হয়ে গেলে এবং অস্থায়ী ভেরিয়েবলগুলি নষ্ট হয়ে গেলে কোডটি ওয়াই অবজেক্টটিকে ধ্বংস করবে। সুতরাং আমার উত্তরটি ভুল।
shared_ptr<>
যা এর পয়েন্টটি মুছে না, তবে এটি ওভারকিল। আপনি কেবল বলতে পারেন return shared_ptr<Y>(this, no_op_deleter);
যেখানে no_op_deleter
অযাচিত ফাংশন অবজেক্টটি Y*
কিছুই নিচ্ছে না এবং করছে।
m_stub = shared_ptr<Y>(this)
এটি থেকে অস্থায়ী শেয়ার্ড_পিটারটি নির্মাণ এবং তত্ক্ষণাত ধ্বংস করে দেবে। এই বিবৃতিটি শেষ হয়ে গেলে, this
মুছে ফেলা হবে এবং পরবর্তী সমস্ত রেফারেন্সগুলি জটলা হবে।
enable_shared_from_this
, এটি weak_ptr
নিজের মধ্যে একটি রাখে (কর্টারের দ্বারা জনবহুল), shared_ptr
যখন আপনি কল করবেন তখন ফিরে আসবে shared_from_this
। অন্য কথায়, আপনি enable_shared_from_this
ইতিমধ্যে সরবরাহ করে যা সদৃশ হয় ।