কেন ভাগ করা_পিটর <ভিওড> আইনী, যখন অনন্য_প্টর <void> খারাপ-গঠিত?


101

প্রশ্নটি সত্যই শিরোনামে ফিট করে: আমি জানতে আগ্রহী যে এই পার্থক্যের প্রযুক্তিগত কারণটি কী, তবে যুক্তিও কি?

std::shared_ptr<void> sharedToVoid; // legal;
std::unique_ptr<void> uniqueToVoid; // ill-formed;

উত্তর:


121

এটি কারণ std::shared_ptrটাইপ-মুছে ফেলা প্রয়োগ std::unique_ptrকরে , যখন না।


যেহেতু std::shared_ptrটাইপ-ইরেজোর প্রয়োগ করে, এটি আরও একটি আকর্ষণীয় সম্পত্তি সমর্থন করে , যেমন। এটা করে না deleter ধরণ প্রয়োজন টেমপ্লেট প্রকার আর্গুমেন্ট হিসাবে বর্গ টেমপ্লেটে। তাদের ঘোষণা দেখুন:

template<class T,class Deleter = std::default_delete<T> > 
class unique_ptr;

যা Deleterটাইপ প্যারামিটার হিসাবে আছে , যখন

template<class T> 
class shared_ptr;

এটা আছে না।

এখন প্রশ্ন হচ্ছে, shared_ptrটাইপ-ইরেজোর প্রয়োগ কেন ? ভাল, এটি এটি করে, কারণ এটি রেফারেন্স-গণনা সমর্থন করতে হবে, এবং এটি সমর্থন করার জন্য, এটি গাদা থেকে মেমরি বরাদ্দ করতে হয় এবং যেহেতু এটি যেভাবেই মেমরি বরাদ্দ করতে হয়, এটি আরও এক ধাপ এগিয়ে যায় এবং টাইপ-ইরেজরের প্রয়োগ করে - যার জন্য গাদা প্রয়োজন which বরাদ্দও। সুতরাং মূলত এটি কেবল সুবিধাবাদী হচ্ছে!

টাইপ-ইরেজরের কারণে, std::shared_ptrদুটি জিনিস সমর্থন করতে সক্ষম:

  • এটা তোলে কোন ধরনের বস্তু সংরক্ষণ করতে পারেন void*, কিন্তু এখনও এটি সঠিকভাবে ধ্বংস বস্তু মুছে ফেলতে সক্ষম হয় সঠিকভাবে দ্বারা তাদের বিনাশকারী invoking
  • মুছে ফেলার ধরণটি শ্রেণীর টেম্পলেটটিতে টাইপ আর্গুমেন্ট হিসাবে পাস করা হয় না, যার অর্থ প্রকার-সুরক্ষার সাথে আপস না করে সামান্য কিছুটা স্বাধীনতা ।

ঠিক আছে. এটি কীভাবে std::shared_ptrকাজ করে সে সম্পর্কে ।

এখন প্রশ্ন, std::unique_ptrজিনিস হিসাবে সংরক্ষণ করতে পারেন void*? ঠিক আছে, উত্তরটি হ্যাঁ - আপনি যদি যুক্তি হিসাবে একটি উপযুক্ত মুছকটি পাস করেন। এখানে এইরকম একটি বিক্ষোভ রয়েছে:

int main()
{
    auto deleter = [](void const * data ) {
        int const * p = static_cast<int const*>(data);
        std::cout << *p << " located at " << p <<  " is being deleted";
        delete p;
    };

    std::unique_ptr<void, decltype(deleter)> p(new int(959), deleter);

} //p will be deleted here, both p ;-)

আউটপুট ( অনলাইন ডেমো ):

959 located at 0x18aec20 is being deleted

আপনি মন্তব্যে একটি খুব আকর্ষণীয় প্রশ্ন জিজ্ঞাসা করেছেন:

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

যার প্রতি @ স্টিভ জেসোপ নিম্নলিখিত সমাধানের পরামর্শ দিয়েছেন

আমি আসলে এটি কখনও চেষ্টা করে দেখিনি, তবে সম্ভবত আপনি std::functionমুছে ফেলার মতো উপযুক্ত হিসাবে ব্যবহার করে তা অর্জন করতে পারেন unique_ptr? মনে করুন যে এটি আসলে আপনার কাজ হয়ে গেলে কাজ করে, একচেটিয়া মালিকানা এবং একটি টাইপ-মুছানো মুছক।

এই পরামর্শ অনুসরণ করে, আমি এটি বাস্তবায়ন করেছি (যদিও এটি std::functionপ্রয়োজনীয় বলে মনে হচ্ছে না এটি ব্যবহার করে না):

using unique_void_ptr = std::unique_ptr<void, void(*)(void const*)>;

template<typename T>
auto unique_void(T * ptr) -> unique_void_ptr
{
    return unique_void_ptr(ptr, [](void const * data) {
         T const * p = static_cast<T const*>(data);
         std::cout << "{" << *p << "} located at [" << p <<  "] is being deleted.\n";
         delete p;
    });
}

int main()
{
    auto p1 = unique_void(new int(959));
    auto p2 = unique_void(new double(595.5));
    auto p3 = unique_void(new std::string("Hello World"));
}  

আউটপুট ( অনলাইন ডেমো ):

{Hello World} located at [0x2364c60] is being deleted.
{595.5} located at [0x2364c40] is being deleted.
{959} located at [0x2364c20] is being deleted.

আশা করি এইটি কাজ করবে.


13
ভাল উত্তর, +1। কিন্তু আপনি এটা আরও ভাল স্পষ্টভাবে উল্লেখ করে একটি দ্বারা করা হতে পারে std::unique_ptr<void, D>এখনও একটি উপযুক্ত প্রদানের মাধ্যমে সম্ভব D
অ্যাঞ্জিউ আর

4
@ অংগ্রু: খুব ভাল, আপনি আসল অন্তর্নিহিত প্রশ্নটি পেয়েছেন যা আমার প্রশ্নে লেখা হয়নি;)
বিজ্ঞাপন এন

@ নাওয়াজ: আপনাকে ধন্যবাদ আমার ক্ষেত্রে আমার একটি টাইপ মোছার মুছে ফেলার দরকার হবে তবে এটি সম্ভবত সম্ভব (কিছু গাদা বরাদ্দের ব্যয়ে)। মূলত, এর অর্থ কি তৃতীয় ধরণের স্মার্ট পয়েন্টারটির প্রকৃতপক্ষে একটি বিশেষ স্পট রয়েছে: ধরণের ক্ষয়ের সাথে একচেটিয়া মালিকানা স্মার্ট পয়েন্টার?
বিজ্ঞাপন এন

8
@ অ্যাডএন: আমি বাস্তবে এটি কখনও চেষ্টা করে দেখিনি, তবে সম্ভবত আপনি std::functionমুছে যাওয়ার ধরণ হিসাবে উপযুক্ত হিসাবে ব্যবহার করে এটি অর্জন করতে পারেন unique_ptr? মনে করুন যে এটি আসলে আপনার কাজ হয়ে গেলে কাজ করে, একচেটিয়া মালিকানা এবং একটি টাইপ-মুছানো মুছক।
স্টিভ জেসোপ

ব্যাকরণ নীট: "এক্স ক্রিয়াপদ Y কেন?" হওয়া উচিত "কেন করেন এক্স ক্রিয়া ওয়াই?" ইংরেজীতে.
zwol

7

যুক্তিগুলির মধ্যে একটির অনেকগুলি ব্যবহারের ক্ষেত্রে একটি হয় shared_ptr- যাকে আজীবন নির্দেশক বা প্রেরণিকা হিসাবে।

মূল বুস্ট ডকুমেন্টেশনে এটি উল্লেখ করা হয়েছিল:

auto register_callback(std::function<void()> closure, std::shared_ptr<void> pv)
{
    auto closure_target = { closure, std::weak_ptr<void>(pv) };
    ...
    // store the target somewhere, and later....
}

void call_closure(closure_target target)
{
    // test whether target of the closure still exists
    auto lock = target.sentinel.lock();
    if (lock) {
        // if so, call the closure
        target.closure();
    }
}

closure_targetএরকম কিছু যেখানে :

struct closure_target {
    std::function<void()> closure;
    std::weak_ptr<void> sentinel;
};

কলার এইরকম কিছু কলব্যাক রেজিস্ট্রেশন করবেন:

struct active_object : std::enable_shared_from_this<active_object>
{
    void start() {
      event_emitter_.register_callback([this] { this->on_callback(); }, 
                                       shared_from_this());
    }

    void on_callback()
    {
        // this is only ever called if we still exist 
    }
};

যেহেতু shared_ptr<X>সর্বদা রূপান্তরিত হয় shared_ptr<void>তাই ইভেন্ট_মিটার এখন যে ধরণের বস্তুতে আবার কল করছে তা আনন্দের সাথে অজানা থাকতে পারে।

এই ব্যবস্থাটি ক্রসিং কেসগুলি পরিচালনা করার বাধ্যবাধকতার ইভেন্ট ইমেটারের গ্রাহকদের মুক্তি দেয় (যদি সারি-এ কলব্যাক সক্রিয় থাকে, সক্রিয়_বজেক্ট চলে যাওয়ার সময় ব্যবস্থা নেওয়া হবে কি?) এবং এর অর্থ হ'ল আনসাবস্ক্রিপশন সিঙ্ক্রোনাইজ করার দরকার নেই। weak_ptr<void>::lockএকটি সিঙ্ক্রোনাইজড অপারেশন।

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