আমি কখন কোন ধরণের পয়েন্টার ব্যবহার করব?


228

ঠিক আছে, তাই আমি জীবিতের জন্য শেষবারের মতো সি ++ লিখেছিলাম, std::auto_ptrসমস্ত স্টাড লাইব ছিল, এবং boost::shared_ptrসমস্ত ক্রোধ ছিল। আমি সরবরাহিত অন্যান্য স্মার্ট পয়েন্টার ধরণের উত্সের দিকে সত্যই কখনও দেখিনি। আমি বুঝতে পেরেছি যে সি ++ 11 এখন উত্সাহিত কিছু প্রকারের সরবরাহ করে তবে সেগুলি সব নয়।

সুতরাং কার স্মার্ট পয়েন্টার কখন ব্যবহার করবেন তা নির্ধারণ করার জন্য কারও কাছে একটি সহজ অ্যালগরিদম রয়েছে? সাধারণত বোবা পয়েন্টার (কাঁচা পয়েন্টারগুলি পছন্দ করা T*) এবং বাকী বুস্ট স্মার্ট পয়েন্টার সম্পর্কিত পরামর্শ সহ । (যেমন কিছু এই মহান হতে হবে)।



1
আমি সত্যিই আশা করছি যে কেউ এই এসটিএল নির্বাচন ফ্লোচার্টের মতো একটি দুর্দান্ত হ্যান্ডস ফ্লোচার্ট নিয়ে আসে ।
অলোক

1
@ এলস: ওহ, এটি সত্যিই দুর্দান্ত! আমি এটি প্রায়শই জিজ্ঞাসা করেছি।
এসবিআই

6
@ ডিডুকিপ্লেটর এটি ডুপ্লিকেট হওয়ার কাছাকাছিও নয়। লিঙ্কযুক্ত প্রশ্নটি বলছে "আমি কখন একটি স্মার্ট পয়েন্টার ব্যবহার করব " এবং এই প্রশ্নটি হয় "আমি কখন এই স্মার্ট পয়েন্টারগুলি ব্যবহার করব?" অর্থাত্ এটি স্ট্যান্ডার্ড স্মার্ট পয়েন্টারগুলির বিভিন্ন ব্যবহারকে শ্রেণিবদ্ধ করছে। লিঙ্কযুক্ত প্রশ্ন এটি করে না। পার্থক্যটি আপাতদৃষ্টিতে সামান্য হলেও এটি একটি বড়।
Rapptz

উত্তর:


183

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

নোট করুন যে বুস্ট অতিরিক্তভাবে অফার করে shared_array, এটির জন্য উপযুক্ত বিকল্প হতে পারে shared_ptr<std::vector<T> const>

এরপরে, বুস্ট অফারগুলি হ'ল intrusive_ptrএটি একটি হালকা ওজনের সমাধান, যদি আপনার সংস্থানটি ইতিমধ্যে রেফারেন্স-গণনা করা ম্যানেজমেন্ট সরবরাহ করে এবং আপনি এটি আরএআইআই নীতিতে গ্রহণ করতে চান। এই এক মানক দ্বারা গ্রহণ করা হয়নি।

স্বতন্ত্র মালিকানা:
বুস্টের scoped_ptrএকটিও রয়েছে , যা অনুলিপিযোগ্য নয় এবং যার জন্য আপনি কোনও মুছক নির্দিষ্ট করতে পারবেন না। std::unique_ptrহয় boost::scoped_ptrস্টেরয়েড উপর এবং আপনার হওয়া উচিত ডিফল্ট পছন্দ যখন আপনি একটি স্মার্ট পয়েন্টার প্রয়োজন । এটা আপনি তার টেমপ্লেট আর্গুমেন্ট একটি deleter নির্দিষ্ট করার অনুমতি দেয় এবং অস্থাবর , অসদৃশ boost::scoped_ptr। এটি এসটিএল পাত্রে যতক্ষণ না আপনি কপিরাইটযোগ্য ধরণের (স্পষ্টতই) প্রয়োজন এমন অপারেশন ব্যবহার করবেন না ততক্ষণ এটি সম্পূর্ণরূপে ব্যবহারযোগ্য।

আবার নোট করুন, বুস্টের একটি অ্যারে সংস্করণ রয়েছে: scoped_arrayমানকটি std::unique_ptr<T[]>আংশিক বিশেষায়নের প্রয়োজনের দ্বারা একীভূত হয়েছে যা এটির delete[]পরিবর্তে পয়েন্টারটি delete( default_deleteআর) দিয়ে দেবে। std::unique_ptr<T[]>এছাড়াও উপলব্ধ করা হয় operator[]পরিবর্তে operator*এবং operator->

নোট করুন যে std::auto_ptrএখনও মান আছে, কিন্তু এটি অবচয় হয়§D.10 [depr.auto.ptr]

শ্রেণীর টেম্পলেটটি auto_ptrঅবচয় করা হয়েছে। [ দ্রষ্টব্য: শ্রেণীর টেম্পলেট unique_ptr(20.7.1) আরও ভাল সমাধান সরবরাহ করে। অন্তর্ভুক্ত নোট ]

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

আপনি যদি কোনও সংস্থার অ-মালিকানাধীন রেফারেন্স চান তবে আপনি জানেন না যে সংস্থানটি যে রেফারেন্সটির উল্লেখ রেখেছে সেটিকে আউটলাইভ করবে কিনা, রিসোর্সটি একটিতে প্যাক করুন shared_ptrএবং ব্যবহার করুন weak_ptr- আপনি পিতা-মাতা shared_ptrবেঁচে আছেন কিনা তা পরীক্ষা করতে পারবেন lock, যা হবে shared_ptrযদি রিসোর্সটি এখনও বিদ্যমান থাকে তবে এটি অ-শূন্য হয় return যদি উত্সটি মারা গেছে কিনা তা পরীক্ষা করতে চান, ব্যবহার করুন expired। দুটি একইরকম শোনাতে পারে তবে একই সাথে একযোগে কার্যকর করার ক্ষেত্রে খুব আলাদা, কারণ expiredকেবলমাত্র একক বিবৃতিতে তার ফেরতের মূল্যের গ্যারান্টি রয়েছে। একটি আপাতদৃষ্টিতে নিষ্পাপ পরীক্ষা

if(!wptr.expired())
  something_assuming_the_resource_is_still_alive();

একটি সম্ভাব্য রেসের শর্ত।


1
কোনও মালিকানা না পাওয়ার ক্ষেত্রে আপনার সম্ভবত মালিকানা এবং পুনর্নির্মাণের প্রয়োজন নেই যেখানে রেফারেন্সগুলি কাটবে না , আপনি সম্ভবত পয়েন্টারগুলির জন্য রেফারেন্সগুলিকে পছন্দ করতে পারেন, তারপরেও আপনি মূল বিষয়টিকে পুনরায় লেখার জন্য shared_ptrএবং অ-মালিকানাধীন পয়েন্টার হিসাবে বিবেচনা করতে চাইতে পারেন a weak_ptr...
ডেভিড রদ্রিগেজ - ড্রিবাস

2
আমি বলিনি পয়েন্টার রেফারেন্স , বরং রেফারেন্স পরিবর্তে পয়েন্টার। যদি কোনও মালিকানা না থাকে তবে যদি না আপনার পুনর্বাসনেরযোগ্যতা প্রয়োজন (বা nullability, তবে পুনরায় সেট করতে সক্ষম না হওয়ায় ন্যূনবিলিটি যথেষ্ট সীমাবদ্ধ হবে) আপনি প্রথমে কোনও পয়েন্টারের পরিবর্তে একটি সাধারণ রেফারেন্স ব্যবহার করতে পারেন।
ডেভিড রদ্রিগেজ - ড্রিবিস

1
@ ডেভিড: আহ, আমি দেখছি :) হ্যাঁ, রেফারেন্সগুলি এর জন্য খারাপ নয়, আমি ব্যক্তিগতভাবে এ জাতীয় ক্ষেত্রেও তাদের পছন্দ করি। আমি তাদের যুক্ত করব।
জিও

1
@ Xoo: না করার shared_array<T>বিকল্প : এটি বাড়তে পারে না। shared_ptr<T[]>shared_ptr<vector<T>>
আর মার্টিনহো ফার্নান্দেস

1
@ গ্রেগ্রয়ে কারিকারি: এটাই ... আমি ঠিক কী লিখেছি? আমি বলেছিলাম এটি একটি সম্ভাব্য জাতি শর্তের একটি উদাহরণ।
জিও

127

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

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


যদি আপনার অবজেক্টটির একমাত্র মালিকানা থাকে তবে ব্যবহার করুন std::unique_ptr<T>

আপনার যদি অবজেক্টটির মালিকানা ভাগ করা থাকে ...
- মালিকানাতে কোনও চক্র না থাকলে ব্যবহার করুন std::shared_ptr<T>
- যদি চক্র থাকে তবে একটি "দিকনির্দেশনা" সংজ্ঞায়িত করুন std::shared_ptr<T>এবং এক দিক এবং std::weak_ptr<T>অন্যদিকে ব্যবহার করুন।

যদি অবজেক্টটি আপনার মালিকানাধীন থাকে তবে মালিক না থাকার সম্ভাবনা থাকে তবে সাধারণ পয়েন্টার T*(যেমন প্যারেন্ট পয়েন্টার) ব্যবহার করুন।

যদি অবজেক্টটি আপনার মালিক (বা অন্যথায় তার অস্তিত্বের নিশ্চয়তা রয়েছে), তবে উল্লেখগুলি ব্যবহার করুন T&


ক্যাভেট: স্মার্ট পয়েন্টারগুলির ব্যয় সম্পর্কে সচেতন হন। মেমরি বা কর্মক্ষমতা সীমিত পরিবেশে, স্মৃতি পরিচালনার জন্য আরও ম্যানুয়াল স্কিম সহ সাধারণ পয়েন্টারগুলি ব্যবহার করা উপকারী হতে পারে।

মূল্য:

  • যদি আপনার একটি কাস্টম মোছা থাকে (যেমন আপনি বরাদ্দ পুলগুলি ব্যবহার করেন) তবে এটি পয়েন্টার প্রতি ওভারহেড বহন করবে যা ম্যানুয়াল মোছার ফলে সহজেই এড়ানো যায়।
  • std::shared_ptrঅনুলিপিটিতে একটি রেফারেন্স গণনা বৃদ্ধির ওভারহেড রয়েছে, এবং ধ্বংসে হ্রাস হ'ল তারপরে ধরে রাখা অবজেক্টটি মোছার সাথে 0-গণনা পরীক্ষা করে। বাস্তবায়নের উপর নির্ভর করে এটি আপনার কোডটি ফুলে উঠতে পারে এবং কার্য সম্পাদন সংক্রান্ত সমস্যার কারণ হতে পারে।
  • সংকলন সময়। সমস্ত টেম্পলেট হিসাবে, স্মার্ট পয়েন্টার সময় সংকলন নেতিবাচক অবদান।

উদাহরণ:

struct BinaryTree
{
    Tree* m_parent;
    std::unique_ptr<BinaryTree> m_children[2]; // or use std::array...
};

একটি বাইনারি গাছ তার পিতামাতার মালিক হয় না তবে গাছের অস্তিত্ব তার পিতামাতার অস্তিত্বকে বোঝায় (বা nullptrমূলের জন্য), যাতে এটি একটি সাধারণ পয়েন্টার ব্যবহার করে। একটি বাইনারি গাছ (মান শব্দার্থবিজ্ঞান সহ) এর বাচ্চাদের একমাত্র মালিকানা থাকে, তাই সেগুলি std::unique_ptr

struct ListNode
{
    std::shared_ptr<ListNode> m_next;
    std::weak_ptr<ListNode> m_prev;
};

এখানে, তালিকা নোড তার পরবর্তী এবং পূর্ববর্তী তালিকার মালিক, সুতরাং আমরা একটি দিক নির্ধারণ করি shared_ptrএবং weak_ptrচক্রটি ভাঙ্গতে পরবর্তী এবং পূর্বের জন্য ব্যবহার করি ।


3
বাইনারি গাছের উদাহরণের জন্য কিছু লোক shared_ptr<BinaryTree>বাচ্চাদের এবং weak_ptr<BinaryTree>পিতামাতার সম্পর্কের জন্য ব্যবহার করার পরামর্শ দেয় ।
ডেভিড রদ্রিগেজ - ড্রিবিস

@ ডেভিডরডগ্রিজেজ-ড্রিবিয়াস: এটি গাছের মান শব্দার্থক আছে কিনা তা নির্ভর করে। উত্স গাছটি নষ্ট হয়ে যাওয়ার পরেও যদি লোকেরা আপনার গাছটিকে বাহ্যিকভাবে উল্লেখ করে চলেছে তবে হ্যাঁ, ভাগ করা / দুর্বল পয়েন্টার কম্বো সবচেয়ে ভাল।
পিটার আলেকজান্ডার

যদি কোনও অবজেক্ট আপনার মালিকানাধীন এবং এটির নিশ্চয়তা থাকে তবে কেন রেফারেন্স নয়।
মার্টিন ইয়র্ক

1
আপনি যদি রেফারেন্স ব্যবহার করেন তবে আপনি পিতামাতাকে কখনও পরিবর্তন করতে পারবেন না, যা নকশাকে বাধা দিতে পারে বা নাও পারে। ভারসাম্যপূর্ণ গাছগুলির জন্য, এটি বাধা দেয়।
3'12

3
+1 তবে আপনার প্রথম লাইনে "মালিকানা" এর সংজ্ঞা যুক্ত করা উচিত। আমি প্রায়শই নিজেকে স্পষ্ট করে বলতে পারি যে এটি বস্তুর জীবন এবং মৃত্যুর বিষয়ে, আরও বেশি ডোমেন-নির্দিষ্ট অর্থের মালিকানা নয়।
ক্লাইম

19

আপনার unique_ptr<T>যখন রেফারেন্স গণনা প্রয়োজন তখন বাদে সর্বদা ব্যবহার করুন, সেক্ষেত্রে রেফারেন্স চক্রটি রোধ করতে shared_ptr<T>(এবং খুব বিরল ক্ষেত্রে weak_ptr<T>) ব্যবহার করুন। প্রায় প্রতিটি ক্ষেত্রেই, স্থানান্তরযোগ্য অনন্য মালিকানা ঠিক ঠিক।

কাঁচা নির্দেশক: কেবলমাত্র আপনার যদি সমবায় রিটার্ন দরকার হয় তবে অ-মালিকানার নির্দেশক যা ঘটতে পারে need এগুলি অন্যথায় ভীতিজনকভাবে কার্যকর নয়।

অ্যারে পয়েন্টার: unique_ptrএর একটি বিশেষীকরণ রয়েছে T[]যার জন্য স্বয়ংক্রিয়ভাবে delete[]ফলাফলটি কল করে, তাই আপনি unique_ptr<int[]> p(new int[42]);উদাহরণস্বরূপ নিরাপদে করতে পারেন । shared_ptrআপনার এখনও একটি কাস্টম মোছার প্রয়োজন, তবে আপনার কোনও বিশেষ ভাগ করা বা অনন্য অ্যারে পয়েন্টার লাগবে না। অবশ্যই, এই জাতীয় জিনিস সাধারণত std::vectorযেভাবেই প্রতিস্থাপন করা হয়। দুর্ভাগ্যবশত shared_ptrএকটি অ্যারের এক্সেস ফাংশন প্রদান করে না, তাই আপনি এখনও ম্যানুয়ালি কল আছে চাই get(), কিন্তু unique_ptr<T[]>উপলব্ধ operator[]পরিবর্তে operator*এবং operator->। যাই হোক না কেন, আপনাকে নিজের পরীক্ষা করতে হবে। এটি shared_ptrকিছুটা কম ব্যবহারকারী-বান্ধব করে তোলে , যদিও যুক্তিযুক্তভাবে জেনেরিক সুবিধা এবং কোনও বুস্ট নির্ভরতা তৈরি করে না unique_ptrএবং shared_ptrআবার বিজয়ীরাও।

স্কোপড পয়েন্টারস: unique_ptrঠিক যেমন পছন্দ করে অপ্রাসঙ্গিক তৈরি auto_ptr

এটির আর আসলে কিছুই নেই। সি ++ 03 এ পদক্ষেপ বিনা শব্দার্থে এই পরিস্থিতিটি খুব জটিল ছিল, তবে সি ++ 11 এ পরামর্শটি খুব সহজ।

অন্যান্য স্মার্ট পয়েন্টার, যেমন intrusive_ptrবা এর জন্য এখনও ব্যবহার রয়েছে interprocess_ptr। তবে এগুলি সাধারণ ক্ষেত্রে অত্যন্ত কুলুঙ্গি এবং সম্পূর্ণ অপ্রয়োজনীয়।


এছাড়াও, পুনরাবৃত্তির জন্য কাঁচা পয়েন্টার। এবং আউটপুট প্যারামিটার বাফারগুলির জন্য, যেখানে বাফার কলারের মালিকানাধীন।
বেন ভয়েগট

হুম, আমি যেভাবে পড়লাম, এটি এমন পরিস্থিতি যা উভয়ই সমাগত ফেরা এবং অ-মালিকানা নয়। পুনর্লিখনটি ভাল হতে পারে যদি আপনি ছেদ করার চেয়ে ইউনিয়ন বোঝাতে চেয়েছিলেন। আমি আরও বলব যে পুনরাবৃত্তিটিও বিশেষভাবে উল্লেখযোগ্য।
বেন ভয়েগট

2
std::unique_ptr<T[]>এর operator[]পরিবর্তে operator*এবং সরবরাহ করে operator->। এটি সত্য যে আপনাকে এখনও নিজেকে বেঁধে পরীক্ষা করতে হবে।
Xoo

8

কখন ব্যবহার করবেন সে ক্ষেত্রে unique_ptr:

  • কারখানা পদ্ধতি
  • পয়েন্টারযুক্ত সদস্য (পিম্পল অন্তর্ভুক্ত)
  • স্টিল পাত্রে পয়েন্টার সংরক্ষণ করা (চালগুলি এড়াতে)
  • বৃহত স্থানীয় গতিশীল বস্তুর ব্যবহার

কখন ব্যবহার করবেন সে ক্ষেত্রে shared_ptr:

  • থ্রেড জুড়ে অবজেক্টগুলি ভাগ করা
  • সাধারণভাবে বস্তু ভাগ করে নেওয়া

কখন ব্যবহার করবেন সে ক্ষেত্রে weak_ptr:

  • বড় মানচিত্র যা সাধারণ রেফারেন্স হিসাবে কাজ করে (উদাঃ সমস্ত উন্মুক্ত সকেটের মানচিত্র)

নিখরচায় সম্পাদনা করুন এবং আরও যোগ করুন


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