কীভাবে স্মার্ট পয়েন্টারগুলি (শেয়ারড_পিটার), রেফারেন্স বা মান অনুসারে ফিরিয়ে আনবেন?


97

আসুন আমি একটি পদ্ধতি যে একটি ফেরৎ দিয়ে একটি শ্রেণী আছে shared_ptr

এটিকে রেফারেন্স বা মান দিয়ে ফেরত দেওয়ার সম্ভাব্য সুবিধা এবং ত্রুটিগুলি কী কী?

দুটি সম্ভাব্য ক্লু:

  • প্রথম দিকে বস্তু ধ্বংস। আমি যদি shared_ptrবাই (রেজিস্ট্রেশন) রেফারেন্সটি ফিরিয়ে দিই , তবে রেফারেন্স কাউন্টারটি বাড়ানো হয় না, তাই অন্য প্রসঙ্গে (যেমন অন্য কোনও থ্রেড) সুযোগের বাইরে চলে গেলে অবজেক্টটি মুছে ফেলার ঝুঁকি থাকে। এটা কি সঠিক? পরিবেশটি যদি একতরফা হয় তবে এই পরিস্থিতিটিও কি ঘটতে পারে?
  • ব্যয়। পাস-বাই-মান অবশ্যই নিখরচায় নয়। এটা সম্ভব যখনই সম্ভব এড়ানো?

সবাইকে ধন্যবাদ.

উত্তর:


115

মান অনুসারে স্মার্ট পয়েন্টার ফিরিয়ে দিন।

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

মূল্য উদ্বেগ আজকাল মান অপ্টিমাইজেশনের (আরভিও) ধন্যবাদ জানাতে পারে, সুতরাং আপনি আধুনিক বর্ধকগুলির মধ্যে কোনও ইনক্রিমেন্ট-ইনক্রিমেন্ট-হ্রাস ক্রম বা এ জাতীয় কিছু ব্যয় করবেন না। সুতরাং কোনও ফেরতের সর্বোত্তম উপায় shared_ptrহ'ল মূল্য দিয়ে ফিরে আসা:

shared_ptr<T> Foo()
{
    return shared_ptr<T>(/* acquire something */);
};

এটি আধুনিক সি ++ সংকলকগুলির জন্য একটি মৃত-সুস্পষ্ট আরভিও সুযোগ। আমি একটি বাস্তবতার জন্য জানি যে সমস্ত অপ্টিমাইজেশন বন্ধ থাকলেও ভিজ্যুয়াল সি ++ সংকলকরা আরভিও প্রয়োগ করে। এবং সি ++ 11 এর পদক্ষেপ শব্দার্থক শব্দগুলির সাথে, এই উদ্বেগটি আরও কম প্রাসঙ্গিক। (তবে নিশ্চিত হওয়ার একমাত্র উপায় হ'ল প্রোফাইল এবং পরীক্ষা)

আপনি যদি এখনও নিশ্চিত না হন, ডেভ আব্রাহামসের একটি নিবন্ধ আছে যা মান দিয়ে ফেরার জন্য একটি তর্ক করে। আমি এখানে একটি স্নিপেট পুনরুত্পাদন; আমি আপনাকে সুপারিশ করছি যে আপনি পুরো নিবন্ধটি পড়ুন:

সত্যবাদী হোন: নীচের কোডটি আপনাকে কীভাবে অনুভব করে?

std::vector<std::string> get_names();
...
std::vector<std::string> const names = get_names();

সত্যি বলতে, যদিও আমার আরও ভাল জানা উচিত, এটি আমাকে নার্ভাস করে তোলে। বস্তুত, যখন get_names() আয়, আমরা একটি কপি করতে vectorএর stringগুলি। তারপরে, যখন আমরা আরম্ভ করব তখনই এটি আবার অনুলিপি করা namesদরকার এবং আমাদের প্রথম অনুলিপিটি নষ্ট করতে হবে। যদি stringভেক্টরে এন থাকে তবে প্রতিটি অনুলিপিটির জন্য N + 1 মেমরির বরাদ্দ এবং ক্যাশে-বন্ধুত্বপূর্ণ ডেটা অ্যাক্সেসগুলি সম্পূর্ণ> যেমন স্ট্রিংয়ের বিষয়বস্তু অনুলিপি করা হতে পারে।

এই ধরণের উদ্বেগের মুখোমুখি হওয়ার পরিবর্তে অযথা অনুলিপিগুলি এড়াতে আমি প্রায়শই পাস-বাই-রেফারেন্সে ফিরে যাই:

get_names(std::vector<std::string>& out_param );
...
std::vector<std::string> names;
get_names( names );

দুর্ভাগ্যক্রমে, এই পদ্ধতির আদর্শ থেকে দূরে।

  • কোডটি 150% দ্বারা বৃদ্ধি পেয়েছে
  • আমাদের constনাম বাদ দিতে হবে কারণ আমাদের নাম বাদ দিতে হয়েছিল ।
  • ফাংশনাল প্রোগ্রামাররা যেমন আমাদের মনে করিয়ে দিতে চায়, মিউটেশন কোডটিকে আরও জটিল করে তোলে রেফারেন্টাল স্বচ্ছতা এবং সমীকরণীয় যুক্তি তল্লাশী করে about
  • নামের জন্য আর আমাদের কাছে কঠোর মান শব্দার্থক শব্দ নেই।

তবে দক্ষতা অর্জনের জন্য কি আমাদের কোডটি এইভাবে জগাখিচু করা দরকার? ভাগ্যক্রমে, উত্তরটি হ'ল না (এবং বিশেষত যদি আপনি সি ++ 0x ব্যবহার করেন না)।


আমি জানি না যে আমি বলব যে আরভিও প্রশ্নটি মুখ্য করে দেয় কারণ রেফারেন্স দ্বারা প্রত্যাবর্তন সিদ্ধান্ত নিয়ে সিদ্ধান্ত নিয়ে সিদ্ধান্ত নেওয়া आरভিওকে অসম্ভব করে তোলে।
এডওয়ার্ড স্ট্রেঞ্জ

@ ক্র্যাজিএডি: সত্য, আমি ওপি মূল্য দিয়ে ফিরে আসার প্রস্তাব দেওয়ার কারণগুলির মধ্যে এটি অন্যতম।
সিলিকোতে

স্ট্যান্ডার্ড দ্বারা অনুমোদিত আরভিও নিয়মটি কি স্ট্যান্ডার্ড দ্বারা গ্যারান্টিযুক্ত সম্পর্কের আগে সিঙ্ক্রোনাইজেশন / ঘটনার আগে সম্পর্কে নিয়মকে ট্রাম্প করে?
এডিএ-কিএ মর্ট-ওরা-y

4
@ এডিএ-কিএ মার্ট-ওরা-ওয়াই: আরভিওর পার্শ্ব-প্রতিক্রিয়া থাকলেও তা স্পষ্টভাবে অনুমোদিত। উদাহরণস্বরূপ, যদি আপনার cout << "Hello World!";ডিফল্ট এবং অনুলিপি নির্মাণকারীতে কোনও বিবৃতি থাকে, আপনি Hello World!আরভিও কার্যকর হওয়ার সময় দুটি দেখতে পাবেন না । তবে এটি সঠিকভাবে ডিজাইন করা স্মার্ট পয়েন্টার, এমনকি রিট সিঙ্ক্রোনাইজেশনের জন্য সমস্যা হওয়া উচিত নয়।
সিলিকো

23

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

দ্বিতীয়ত, আপনার স্মার্ট পয়েন্টারটির বাস্তবায়নটি দেখুন, যদি সম্ভব হয়। নির্মাণ ও ধ্বংস হ'ল নগন্য হওয়া উচিত। যদি এই ওভারহেডটি গ্রহণযোগ্য না হয়, তবে স্মার্ট পয়েন্টার ব্যবহার করবেন না! তবে এর বাইরে, আপনার যে সমঝোতা আর্কিটেকচারটি রয়েছে তাও পরীক্ষা করে দেখতে হবে, কারণ পয়েন্টারের ব্যবহারগুলি ট্র্যাক করে এমন ব্যবস্থায় পারস্পরিক এক্সক্লুসিভ অ্যাক্সেস আপনাকে ভাগ করে নেওয়া_আপনার অবজেক্টের নিছক নির্মাণের চেয়ে আরও ধীর করে দিচ্ছে।

সম্পাদনা করুন, 3 বছর পরে: সি ++-তে আরও আধুনিক বৈশিষ্ট্যগুলির আবির্ভাবের সাথে, আমি যখন আমার পক্ষে এমন একটি ল্যাম্বডা লিখেছি যা কলিং ফাংশনটির বাইরে কখনও বাস করে না, তখন কেসগুলি আরও গ্রহণযোগ্য হওয়ার জন্য আমি আমার উত্তরটি টুইট করতে পারি and অন্য কোথাও অনুলিপি করা। এখানে আপনি যদি ভাগ করা পয়েন্টারটি অনুলিপি করার খুব ন্যূনতম ওভারহেড সংরক্ষণ করতে চান তবে এটি ন্যায্য এবং নিরাপদ হবে। কেন? কারণ আপনি গ্যারান্টি দিতে পারবেন যে রেফারেন্সটি কখনও ভুল ব্যবহার হবে না।

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