Std :: দুর্বল_পিটার কখন কার্যকর?


268

আমি সি ++ 11 এর স্মার্ট পয়েন্টারগুলি অধ্যয়ন শুরু করেছি এবং এর কোনও কার্যকর ব্যবহার দেখতে পাচ্ছি না std::weak_ptr। কেউ কখন আমাকে std::weak_ptrদরকারী / প্রয়োজনীয় যখন বলতে পারেন ?


উত্তর:


231

একটি ভাল উদাহরণ একটি ক্যাশে হবে।

সম্প্রতি অ্যাক্সেস করা অবজেক্টের জন্য, আপনি এগুলিকে স্মৃতিতে রাখতে চান, তাই আপনি তাদের কাছে শক্তিশালী পয়েন্টার রেখেছেন। পর্যায়ক্রমে, আপনি ক্যাশে স্ক্যান করেন এবং সিদ্ধান্ত নিন যে কোন জিনিসগুলিতে সম্প্রতি অ্যাক্সেস করা হয়নি। আপনার এগুলি স্মৃতিতে রাখার দরকার নেই, তাই আপনি শক্ত পয়েন্টার থেকে মুক্তি পাবেন।

তবে কী যদি সেই অবজেক্টটি ব্যবহার হয় এবং অন্য কোনও কোড এতে দৃ strong় পয়েন্টার ধরে থাকে? যদি ক্যাশে তার একমাত্র পয়েন্টারটি অবজেক্টটির থেকে মুক্তি দেয় তবে এটি আর কখনও খুঁজে পাবে না। সুতরাং ক্যাশে বস্তুগুলির জন্য একটি দুর্বল পয়েন্টার রাখে যা তাদের স্মৃতিতে থাকার জন্য ঘটে কিনা তা খুঁজে পাওয়া দরকার।

এটি হ'ল দুর্বল পয়েন্টারটি যা করে - এটি আপনাকে যদি কোনও আশেপাশে থাকে তবে এটি সনাক্ত করতে দেয় তবে অন্য কোনও কিছুর প্রয়োজন না থাকলে এটিকে চারপাশে রাখে না।


8
সুতরাং এসটিডি :: জাগো_পিটার কেবল তখনই নির্দেশ করতে পারে যেখানে অন্য পয়েন্টারটি পয়েন্ট করে এবং এটি নালপ্টারের দিকে নির্দেশ করে যখন অবজেক্ট পয়েন্টটি মুছে ফেলা হয় / অন্য কোনও পয়েন্টার দ্বারা নির্দেশিত হয় না?

27
@ আরএম: মূলত, হ্যাঁ আপনার যদি দুর্বল পয়েন্টার থাকে, আপনি এটিকে একটি শক্ত পয়েন্টারে উন্নীত করার চেষ্টা করতে পারেন। যদি সেই অবজেক্টটি এখনও বিদ্যমান থাকে (কারণ এটির জন্য কমপক্ষে একটি শক্ত পয়েন্টার এখনও বিদ্যমান) যা অপারেশন সফল হয় এবং আপনাকে এটিতে একটি শক্ত পয়েন্টার দেয়। যদি সেই বস্তুটি বিদ্যমান না থাকে (কারণ সমস্ত শক্তিশালী পয়েন্টার চলে যায়), তবে সেই ক্রিয়াটি ব্যর্থ হয় (এবং সাধারণত আপনি দুর্বল পয়েন্টারটি ফেলে দিয়ে প্রতিক্রিয়া জানান)।
ডেভিড শোয়ার্জ

12
শক্তিশালী পয়েন্টারটি কোনও অবজেক্টকে বাঁচিয়ে রাখার সময়, দুর্বল_পিটার এটি দেখতে পারে ... অবজেক্টের লাইফ টাইম নিয়ে মশকরা না করে।
ভিভানডিয়ের

3
আরেকটি উদাহরণ, যা আমি কমপক্ষে কয়েকবার ব্যবহার করেছি, এটি পর্যবেক্ষকরা প্রয়োগ করার সময়, কখনও কখনও বিষয়টিকে দুর্বল পয়েন্টারগুলির একটি তালিকা বজায় রাখা এবং তার নিজস্ব তালিকা পরিষ্কারের জন্য সুবিধাজনক হয়ে ওঠে। পর্যবেক্ষকরা মুছে ফেলা হলে এটি পরিষ্কারভাবে মুছে ফেলার জন্য এটি কিছুটা প্রচেষ্টা সাশ্রয় করে এবং আরও লক্ষণীয়ভাবে পর্যবেক্ষকদের ধ্বংস করার সময় যে বিষয়গুলি সাধারণভাবে অনেক সহজ করে দেয় সেগুলি সম্পর্কিত আপনার কাছে তথ্য থাকতে হবে না।
জেসন সি

3
অপেক্ষা করুন, ক্যাশে একটি শেয়ারড_পিটার ধারণ করে এবং মেমরি থেকে মুছে ফেলা হলে কেবল তালিকা থেকে এটিকে সরিয়ে ফেলতে সমস্যা হয়েছে কি? যে কোনও ব্যবহারকারীর একটি শেয়ারড_পিটার থাকবে এবং সমস্ত ব্যবহারকারী এটির সাথে এটি সম্পন্ন হওয়ার সাথে সাথে ক্যাশেড সংস্থানটি সাফ হয়ে যাবে।
রুবেনবিবি

299

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";
}

1
ঠিক আছে, এ যেন মনে হয় আপনি স্থানীয়ভাবে একটি (নিজস্ব) পয়েন্টারটি নাল (মেমরি মুছে ফেলুন) এ সেট করেছেন, একই স্মৃতিতে অন্য সমস্ত (দুর্বল) পয়েন্টারগুলিও বাতিল হয়ে গেছে
প্যাট-লাফ

std::weak_ptr::lockএকটি নতুন তৈরি করে std::shared_ptrযা পরিচালিত অবজেক্টের মালিকানা ভাগ করে দেয়।
সাহেব ইয়ার

129

আর একটি উত্তর, আশা করি সহজ। (সহ গুগলারের জন্য)

মনে করুন আপনার কাছে 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

1
এ কেমন স্মৃতি ফুটো? যদি দলটিকে ধ্বংস করা হয় তবে এটি তার সদস্যদের ধ্বংস করবে, সুতরাং এইভাবে ভাগ করা_পাত্র রেফের গণনা 0 হবে এবং ধ্বংসও হবে?
পলম

4
@ পলম টিম "এর" সদস্যদের ধ্বংস করবে না। পুরো বিষয়টি shared_ptrহ'ল মালিকানা ভাগ করে নেওয়া, সুতরাং কারও কাছে মেমরিটি মুক্ত করার বিশেষ দায় নেই, যখন আর ব্যবহার না করা হয় এটি স্বয়ংক্রিয়ভাবে মুক্ত হয়। যদি কোনও লুপ না থাকে ... আপনার কাছে বেশ কয়েকটি দল একই প্লেয়ার (বিগত দলগুলি) ভাগ করে নিতে পারে? যদি দলটির সদস্যরা সদস্যদের "মালিকানাধীন" থাকে তবে shared_ptrশুরু করার জন্য একটি ব্যবহার করার দরকার নেই ।
অফির্মমো

1
এটি তাদের ধ্বংস করবে না তবে এর ভাগ করা_পিটারটি এর সাথে স্কোপের বাইরে চলে যাবে, ব্যবহার_কাউন্টকে হ্রাস করবে, সুতরাং এই মুহুর্তে ব্যবহার_কাউন্ট 0 হয় এবং তাই ভাগ করা_পাত্র তার পয়েন্টিংটি কী মুছে ফেলবে?
পলম

2
@ পলম আপনি ঠিক বলেছেন তবে যেহেতু, উদাহরণস্বরূপ, দলটি shared_ptrতার "টিম সদস্যরা" দ্বারাও রেফারেন্স করা হয়, কখন এটি ধ্বংস হয়ে যাবে? আপনি যা বর্ণনা করছেন তা এমন কোনও ঘটনা যেখানে কোনও লুপ নেই।
অফিড়মো

14
এটি এতটা খারাপ নয়, আমি ভাবব। কোনও সদস্য যদি অনেক দলের অন্তর্ভুক্ত থাকতে পারে তবে একটি রেফারেন্স ব্যবহার করে কাজ হবে না।
মাজিওড

22

এখানে একটি উদাহরণ যা @ জ্লেহি দ্বারা আমাকে দেওয়া হয়েছে: ধরুন আপনার কাছে কাজগুলির একটি সংগ্রহ রয়েছে, অ্যাসিঙ্ক্রোনালি সম্পাদন করা হয়েছে এবং একটি দ্বারা পরিচালিত std::shared_ptr<Task>। আপনি এই কাজগুলি পর্যায়ক্রমে কিছু করতে চাইতে পারেন, তাই একটি টাইমার ইভেন্ট কোনওটিকে অবিচ্ছিন্ন করতে পারে std::vector<std::weak_ptr<Task>>এবং কাজগুলিকে কিছু করতে দেয়। তবে, একই সাথে কোনও কাজ একযোগে সিদ্ধান্ত নিয়েছে যে এটির আর দরকার নেই এবং মারা যাবে। টাইমার এইভাবে দুর্বল পয়েন্টার থেকে একটি ভাগ করে নেওয়া পয়েন্টার তৈরি করে এবং সেই অংশীদারি পয়েন্টারটি ব্যবহার করে টাস্কটি এখনও বেঁচে আছে কিনা তা পরীক্ষা করতে পারে, তবে শর্ত থাকে যে এটি বাতিল নয়।


4
: একটি ভাল উদাহরণের মতো মনে হচ্ছে তবে আপনি দয়া করে নিজের উদাহরণটি আরও কিছুটা ব্যাখ্যা করতে পারেন? আমি ভাবছি যখন কোনও কাজ শেষ হয়ে যায় তখন পর্যায়ক্রমিক চেক ছাড়াই এটি ইতিমধ্যে std :: ভেক্টর <std :: দুর্বল_ptr <টাস্ক>> থেকে সরানো উচিত। সুতরাং নিশ্চিত হন না যে এখানে এসটিডি :: ভেক্টর <স্টাড :: দুর্বল_পিটার <>> খুব সহায়ক।
গুব00 আস্ট

সারিগুলির সাথে অনুরূপ মন্তব্য: বলুন যে আপনার কাছে অবজেক্ট রয়েছে এবং কিছু সংস্থান হিসাবে আপনার সারি রয়েছে, অপেক্ষার সময় অবজেক্টগুলি মুছতে পারে। সুতরাং, যদি আপনি দুর্বল_পিটারগুলিকে সারি করেন তবে সেখান থেকে সারি থেকে প্রবেশকারীদের মুছে ফেলার বিষয়ে আপনাকে বিরক্ত করার দরকার নেই। দুর্বল_আপনারগুলি অবৈধ হবে এবং তারপরে এনকাউন্ট করা অবস্থায় ফেলে দেওয়া হবে।
zzz777

1
@ zzz777: যুক্তিগুলি যে অবজেক্টগুলিকে অবৈধ করে তোলে তা পর্যবেক্ষকদের সারি বা ভেক্টরের অস্তিত্ব সম্পর্কেও অবগত হতে পারে না। সুতরাং পর্যবেক্ষক দুর্বল পয়েন্টারগুলির উপর একটি পৃথক লুপ সম্পাদন করে, এখনও বেঁচে থাকা ব্যক্তির উপর অভিনয় করে এবং ধারক থেকে মৃতদের সরিয়ে দেয় ...
কেরেক এসবি

1
@ কেরেকএসবি: হ্যাঁ এবং কিউয়ের ক্ষেত্রে আপনাকে আলাদা লুপও করতে হবে না - তবে সংস্থানটি পাওয়া যায় আপনি মেয়াদ শেষ হওয়া দুর্বল_পটারগুলি (যদি থাকে) অবধি বাতিল করবেন যতক্ষণ না আপনি বৈধ (যদি কোনও) পান got
zzz777

আপনি থ্রেডগুলি সংগ্রহ থেকে নিজেকে সরিয়ে ফেলতে পারেন, তবে এটি নির্ভরতা তৈরি করতে এবং লকিংয়ের প্রয়োজন।
কৌতূহলী

16

এগুলি বুস্ট.অ্যাসিওর সাথে দরকারী যখন যখন আপনার গ্যারান্টি দেওয়া হয় না যে অ্যাসিঙ্ক্রোনাস হ্যান্ডলারটি আহ্বান করা হয় তখনও কোনও টার্গেট অবজেক্ট উপস্থিত থাকে। কৌশলটি হ'ল 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()হ্যান্ডলার যখন একই বর্গের মধ্যে পদ্ধতিগুলি আহ্বান করে তখন আইডিয়মটি ব্যবহার করার সময় অভ্যাসের বল প্রয়োগ করুন।
এমিল কর্মিয়ার

16

shared_ptr : আসল অবজেক্ট ধরে holds

দুর্বল_সিটিআর : lockপ্রকৃত মালিকের সাথে সংযোগ করতে ব্যবহার করে বা shared_ptrঅন্যথায় একটি এনএলএল প্রদান করে ।

দুর্বল ptr

মোটামুটিভাবে বলতে গেলে, weak_ptrভূমিকা আবাসন সংস্থার ভূমিকার সাথে সমান । এজেন্ট ছাড়া, ভাড়া নিয়ে বাড়ি পেতে আমাদের শহরে এলোমেলো বাড়িগুলি চেক করতে হতে পারে। এজেন্টরা নিশ্চিত করে যে আমরা কেবলমাত্র সেই বাড়িগুলি ঘুরে দেখি যা এখনও অ্যাক্সেসযোগ্য এবং ভাড়ার জন্য উপলব্ধ


14

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());

13

পয়েন্টারগুলি ব্যবহার করার সময় উপলব্ধ বিভিন্ন ধরণের পয়েন্টার উপলব্ধ হওয়া এবং এটি প্রতিটি ব্যবহার করার জন্য যখন বোধগম্য হয় তা গুরুত্বপূর্ণ। নিম্নলিখিত হিসাবে দুটি বিভাগে চার ধরণের পয়েন্টার রয়েছে:

  • কাঁচা পয়েন্টার:
    • কাঁচা পয়েন্টার [অর্থাত্ 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


6

ইতিমধ্যে উল্লিখিত অন্যান্য বৈধ ব্যবহারের ক্ষেত্রগুলি ছাড়াও 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


2

http://en.cppreferences.com/w/cpp/memory/weak_ptr std :: দুর্বল_ptr একটি স্মার্ট পয়েন্টার যা স্ট্যান্ড :: শেয়ারড_পিটিআর দ্বারা পরিচালিত একটি অবজেক্টের একটি নন-মালিকানাধীন ("দুর্বল") রেফারেন্স ধরে। রেফারেন্সযুক্ত অবজেক্টটি অ্যাক্সেস করার জন্য এটি অবশ্যই std :: सामायिक_ptr এ রূপান্তর করতে হবে।

std :: দুর্বল_পিটার মডেলগুলি অস্থায়ী মালিকানা: যখন কোনও অ্যাক্সেস কেবল তখনই অ্যাক্সেস করার প্রয়োজন হয় এবং এটি অন্য কারও দ্বারা মুছে ফেলা হতে পারে, যখন std :: দুর্বল_ptr অবজেক্টটি ট্র্যাক করতে ব্যবহৃত হয় এবং এটি স্টেডি তে রূপান্তরিত হয়: : অস্থায়ী মালিকানা অনুমান করতে ভাগ করা_পিটার। যদি এই মুহুর্তে মূল স্ট্যান্ড :: শেয়ার্ড_পিটারটি ধ্বংস হয়ে যায়, অস্থায়ী স্টাড :: শেয়ার্ড_পিটার পাশাপাশি ধ্বংস হওয়া অবধি অবজেক্টের আজীবন প্রসারিত হবে।

তদতিরিক্ত, স্টাড :: দুর্বল_পিটিআর স্ট্যান্ড :: শেয়ার্ড_পিটারের বিজ্ঞপ্তি রেফারেন্স ভাঙতে ব্যবহৃত হয়।


" বিজ্ঞপ্তি রেফারেন্স ভাঙতে " কিভাবে?
কৌতূহলী

2

ভাগ করে নেওয়া পয়েন্টারের একটি অপূর্ণতা রয়েছে: ভাগ করা_পয়েন্টার পিতামাতার-চক্র নির্ভরতা পরিচালনা করতে পারে না। এর অর্থ যদি পিতামাত্ত শ্রেণি একটি ভাগ করা পয়েন্টার ব্যবহার করে শিশু শ্রেণীর অবজেক্ট ব্যবহার করে তবে একই ফাইলটিতে যদি শিশু শ্রেণি পিতামাতার শ্রেণীর অবজেক্ট ব্যবহার করে। ভাগ করা পয়েন্টারটি সমস্ত অবজেক্টকে ধ্বংস করতে ব্যর্থ হবে, এমনকি ভাগ করা পয়েন্টার চক্র নির্ভরতার দৃশ্যে ডেস্ট্রাক্টরকে কল করা মোটেই নেই। মূলত ভাগ করা পয়েন্টার রেফারেন্স গণনা প্রক্রিয়া সমর্থন করে না।

এই ত্রুটিটি আমরা দুর্বল_পয়েন্টার ব্যবহার করে কাটিয়ে উঠতে পারি।


কোনও বৃত্তাকার নির্ভরতার সাথে দুর্বল রেফারেন্স কীভাবে ডিল করতে পারে?
কৌতূহলী

1
@ কুরিয়াসগুয়ে, কোনও শিশু পিতা-মাতার প্রতি দুর্বল রেফারেন্স ব্যবহার করে, তারপরে কোনও ভাগ করা (শক্তিশালী) রেফারেন্স না থাকলে পিতামাতাকে হ্রাস করা যেতে পারে। সুতরাং সন্তানের মাধ্যমে পিতামাতাকে অ্যাক্সেস করার সময়, পিতামাতার এখনও উপলব্ধ কিনা তা জানার জন্য দুর্বল রেফারেন্সটি পরীক্ষা করতে হবে। বিকল্প হিসাবে এই অতিরিক্ত শর্তটি এড়ানোর জন্য, একটি বিজ্ঞপ্তি রেফারেন্স ট্রেসিং মেকানিজম (মার্ক-সুইপ বা রিফকাউন্ট হ্রাস সম্পর্কে অনুসন্ধানী, উভয়ই খারাপ অ্যাসিপোটিক পারফরম্যান্স রয়েছে) বৃত্তাকার ভাগ করা রেফারেন্সগুলি ভেঙে ফেলতে পারে যখন পিতা-মাতার এবং সন্তানের একমাত্র ভাগ করা রেফারেন্স প্রতিটি থেকে থাকে অন্যান্য।
শেলবি মুর III

@ শেলবিমুরআইআইআই " এর জন্য পিতামাতার এখনও " হ্যাঁ " উপলব্ধ কিনা তা পরীক্ষা করে দেখতে হবে এবং অনুপলব্ধ মামলায় আপনাকে সঠিকভাবে প্রতিক্রিয়া জানাতে সক্ষম হতে হবে! যা প্রকৃত (অর্থাত্ শক্তিশালী) রেফের সাথে ঘটে না। যার অর্থ দুর্বল রেফারেন্স প্রতিস্থাপনের ড্রপ নয়: এর জন্য যুক্তিতে পরিবর্তন দরকার।
কৌতূহলী

2
@ কুরিয়াসগুয়ে আপনি জিজ্ঞাসা করেননি " weak_ptrপ্রোগ্রামের যুক্তিতে কোন পরিবর্তন ছাড়াই একটি ড্রপ-ইন প্রতিস্থাপন হিসাবে একটি বিজ্ঞপ্তি নির্ভরতা কীভাবে ডিল করতে পারে shared_ptr?" :-)
শেলবি মুর তৃতীয়

2

আমরা যখন বস্তুর মালিকানা নিতে চাই না:

উদা:

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()

আমরা আউটপুট থেকে দেখতে পাচ্ছি যে এ এবং বি পয়েন্টার কখনই মুছে ফেলা হয় না এবং তাই মেমরি ফাঁস হয়।

এ জাতীয় সমস্যা এড়াতে কেবল ভাগ করা_পিটারের পরিবর্তে ক্লাস এ-তে দুর্বল_পিটার ব্যবহার করুন যা আরও অর্থবোধ করে।


2

আমি দেখতে 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;
};

ভেষজ সুটারের একটি দুর্দান্ত কথা রয়েছে যা ডিফল্ট দ্বারা লিক ফ্রিডম নিশ্চিত করার জন্য ভাষার বৈশিষ্ট্যগুলির (এই ক্ষেত্রে স্মার্ট পয়েন্টারগুলি) সর্বোত্তম ব্যবহারের ব্যাখ্যা দেয় (যার অর্থ: নির্মাণের দ্বারা সমস্ত কিছু জায়গায় ক্লিক করা হয়; আপনি এটি খুব সহজেই এড়িয়ে যেতে পারেন)। এটা অবশ্যই দেখতে হবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.