ভাগ করা_প্টর <ডেরাইভড> কে শেয়ারড_প্টর <বেস> হিসাবে পাস করা হচ্ছে


93

একটি বেস টাইপ shared_ptrগ্রহণ করে এমন কোনও ফাংশনে ডেরাইভেড টাইপটি পাস করার সর্বোত্তম পদ্ধতি কী shared_ptr?

shared_ptrঅযথা অনুলিপি এড়াতে আমি সাধারণত রেফারেন্স দিয়ে পাস করি :

int foo(const shared_ptr<bar>& ptr);

তবে আমি যদি কিছু করার চেষ্টা করি তবে এটি কাজ করে না

int foo(const shared_ptr<Base>& ptr);

...

shared_ptr<Derived> bar = make_shared<Derived>();
foo(bar);

আমি ব্যবহার করতে পারে

foo(dynamic_pointer_cast<Base, Derived>(bar));

তবে এটি দুটি কারণে উপ-অনুকূল বলে মনে হচ্ছে:

  • একটি dynamic_castএকটি বিট একটি সহজ জন্য অত্যধিক উদ্ভূত টু বেস ঢালাই বলে মনে হয়।
  • যেহেতু আমি এটি বুঝতে পারি, dynamic_pointer_castফাংশনে যাওয়ার জন্য পয়েন্টারের একটি অনুলিপি (অস্থায়ী এক হলেও) তৈরি করে।

এর চেয়ে ভাল সমাধান কি আছে?

উত্তরোত্তর জন্য আপডেট:

এটি হারিয়ে যাওয়া শিরোনাম ফাইলটির একটি সমস্যা হিসাবে প্রমাণিত হয়েছিল। এছাড়াও, আমি এখানে যা করার চেষ্টা করছিলাম এটি একটি অ্যান্টিপ্যাটার্ন হিসাবে বিবেচিত হয়। সাধারণত

  • কোনও কার্যক্রমে যে কোনও বস্তুর আজীবন প্রভাবিত করে না (যেমন বস্তুর কার্যকালীন সময়ের জন্য বৈধ থাকে) একটি সাধারণ রেফারেন্স বা পয়েন্টার গ্রহণ করা উচিত, যেমন int foo(bar& b)

  • কার্যাবলী যে গ্রাস একটি বস্তু (যেমন একটি প্রদত্ত বস্তুর চূড়ান্ত ব্যবহারকারী) একটি গ্রহণ করা উচিত unique_ptrযেমন, মান int foo(unique_ptr<bar> b)। কলকারীদের std::moveফাংশনের মধ্যে মান হওয়া উচিত ।

  • কোনও বস্তুর আজীবন প্রসারিত ক্রিয়াকলাপগুলি shared_ptrমান হিসাবে নেওয়া উচিত , উদাহরণস্বরূপ int foo(shared_ptr<bar> b)বিজ্ঞপ্তি রেফারেন্স এড়ানোর জন্য সাধারণ পরামর্শ প্রযোজ্য।

বিশদগুলির জন্য হার্ব সটারের ব্যাক টু বেসিকগুলিতে দেখুন।


8
আপনি কেন পাস করতে চান shared_ptr? বারের কনস্ট্যান্ড রেফারেন্স কেন?
আইপিসি

4
যে কোনও dynamicকাস্ট কেবল ডাউন কাস্টিংয়ের জন্য প্রয়োজন। এছাড়াও, উত্পন্ন পয়েন্টারটি পাস করার জন্য ঠিক কাজ করা উচিত। এটি shared_ptrএকই পুনরায় গণনা (এবং এটি বাড়িয়ে) এবং বেসে একটি পয়েন্টার সহ একটি নতুন তৈরি করবে, যা কনস্টের রেফারেন্সের সাথে আবদ্ধ হয়। যেহেতু আপনি ইতিমধ্যে একটি রেফারেন্স নিচ্ছেন, তবে কেন আপনি কিছুটা নিতে চান তা আমি দেখতে পাচ্ছি না shared_ptr। একটি Base const&কল এবং কল foo(*bar)
Xeo

@ শিও: উত্সাহিত পয়েন্টারটি পাস করা (অর্থাত্‍ foo(bar)) কমপক্ষে এমএসভিসি 2010 তে কাজ করে না
ম্যাট ক্লিন

4
"স্পষ্টতই কাজ করে না" বলতে আপনার অর্থ কী? কোডটি সংকলন করে এবং সঠিকভাবে আচরণ করে; আপনি কি shared_ptrফাংশনটি পাস করার জন্য একটি অস্থায়ী তৈরি এড়ানোর জন্য জিজ্ঞাসা করছেন ? আমি মোটামুটি নিশ্চিত যে এড়ানোর কোনও উপায় নেই।
মাইক সিমুর 18

4
@ শেঠ: আমি একমত নই আমি মনে করি যে মূল্য অনুসারে ভাগ করে নেওয়া পয়েন্টারটি পাস করার কারণ রয়েছে, এবং রেফারেন্স দ্বারা ভাগ করা পয়েন্টারটি পাস করার খুব কম কারণ আছে (এবং এই সমস্ত কিছুই বিনা শৃঙ্খলার অনুলিপি ছাড়াই)। এখানে যুক্তি স্ট্যাকওভারফ্লো
আর মার্টিনহো ফার্নান্দেস

উত্তর:


47

যদিও Baseএবং Derivedহয় covariant এবং তাদের কাঁচা পয়েন্টার সেই অনুযায়ী কাজ, হবে shared_ptr<Base>এবং shared_ptr<Derived>হয় না covariant। dynamic_pointer_castএই সমস্যা হ্যান্ডেল করতে সঠিক ও সহজ উপায়।

( সম্পাদনা করুন: static_pointer_cast আরও উপযুক্ত হবে কারণ আপনি উত্পন্ন থেকে বেসে কাস্টিং করছেন যা নিরাপদ এবং রানটাইম চেকের প্রয়োজন নেই below নীচের মন্তব্য দেখুন))

তবে, যদি আপনার foo()ক্রিয়াকলাপটি আজীবন বাড়াতে অংশ নিতে চায় না (বা বরং, বস্তুর অংশীদারি মালিকানাতে অংশ নেয়), তবে এটি পাস const Base&করার shared_ptrসময় কোনওটিকে গ্রহণ করা এবং শ্রদ্ধার সাথে সম্মতি জানানো ভাল foo()

void foo(const Base& base);
[...]
shared_ptr<Derived> spDerived = getDerived();
foo(*spDerived);

একদিকে যেমন, shared_ptrপ্রকারগুলি সমবায়িক হতে পারে না , তাই প্রকারের ফেরত দেওয়ার সময় সমবায় রিটার্নের ধরণের ক্ষেত্রে অন্তর্ভুক্ত রূপান্তরগুলির নিয়ম প্রযোজ্য নয় shared_ptr<T>


39
এগুলি সমবায়িক নয়, তবে shared_ptr<Derived>এটি স্পষ্টতই রূপান্তরযোগ্য shared_ptr<Base>, সুতরাং কোডটি কোনও ingালাইয়ের শেননিগানগুলির সাথে কাজ করা উচিত নয়।
মাইক সিমুর

9
উম, এর shared_ptr<Ty>এমন একজন নির্মাতা রয়েছে যা নিখরচায় shared_ptr<Other>রূপান্তরযোগ্য হলে উপযুক্ত রূপান্তর গ্রহণ করে এবং গ্রহণ করে । এবং যদি একটি কাস্ট প্রয়োজন হয়, উপযুক্ত এখানে না । Ty*Other*static_pointer_castdynamic_pointer_cast
পিট বেকার 18

সত্য, তবে তাঁর রেফারেন্স প্যারামিটারের সাথে নয়, যেমনটি প্রশ্নের মধ্যে রয়েছে। নির্বিশেষে তাঁর একটি অনুলিপি করা দরকার। তবে, যদি তিনি shared_ptrরেফারেন্স গণনা এড়ানোর জন্য রেফ ব্যবহার করে shared_ptrথাকেন তবে প্রথমে এটি ব্যবহার করার কোনও ভাল কারণ নেই । const Base&পরিবর্তে এটি ব্যবহার করা ভাল।
ব্রেট কুহেন্স

@ পেটবেকার রূপান্তরকারী কনস্ট্রাক্টর সম্পর্কে মাইকে আমার মন্তব্য দেখুন। আমি সত্যই জানিনা static_pointer_cast, ধন্যবাদ।
ব্রেট কুহনস

4
পছন্দ করুন সম্ভবত এটি 2012 সালে সংকলন করতে ব্যর্থ হয়েছে? (বিশেষত ভিজ্যুয়াল স্টুডিও 2010 বা 2012 ব্যবহার করে)। তবে আপনি একদম ঠিক বলেছেন, কোনও / প্রকাশ্যভাবে উত্পন্ন / শ্রেণীর সম্পূর্ণ সংজ্ঞা সংকলকটিতে দৃশ্যমান হলে ওপির কোডটি একেবারে সংকলন করা উচিত।
ব্রেট কুহন্স

32

আপনি যদি উদ্ভূত শ্রেণিতে জনসাধারণের উত্তরাধিকার নির্দিষ্ট করতে ভুলে গিয়ে থাকেন তবে এটিও ঘটবে , যেমন আমার মতো যদি আপনি এটি লেখেন:

class Derived : Base
{
};

classটেমপ্লেট পরামিতি জন্য; structক্লাস সংজ্ঞায়িত করার জন্য। (এটি সর্বাধিক 45% একটি রসিকতা))
ডেভিস হেরিং

এটি অবশ্যই সমাধান হিসাবে বিবেচনা করা উচিত, কোনও কাস্টের প্রয়োজন নেই কারণ এটি কেবল জনসাধারণের অনুপস্থিত।
অ্যালেক্সিস পাকস

12

মনে হচ্ছে আপনি খুব চেষ্টা করছেন। shared_ptrঅনুলিপি করা সস্তা; এটি এর অন্যতম লক্ষ্য। রেফারেন্সের মাধ্যমে এগুলি অতিক্রম করা সত্যিকার অর্থে খুব বেশি কার্যকর হয় না। আপনি যদি ভাগ করতে চান না, কাঁচা পয়েন্টারটি পাস করুন।

এটি বলেছিল, এটি করার দুটি উপায় আছে যা আমি আমার মাথার উপরের অংশটিকে ভাবতে পারি:

foo(shared_ptr<Base>(bar));
foo(static_pointer_cast<Base>(bar));

9
না, তারা অনুলিপি করার পক্ষে সস্তা নয়, যখনই সম্ভব তাদের রেফারেন্স দিয়ে পাস করা উচিত।
শেঠ কার্নেগি

6
@ শেঠ কার্নেগি - ভেষজ কি আপনার কোডটি প্রোফাইলটি দিয়ে দেখেছেন যে মান দ্বারা পাস করা কোনও বাধা?
পিট বেকার

25
@ শেঠ কার্নেগি - এটি আমার জিজ্ঞাসা করা প্রশ্নের উত্তর দেয় না। এবং, এটির মূল্য কী, আমি shared_ptrমাইক্রোসফ্ট শিপিংয়ের প্রয়োগটি লিখেছিলাম ।
পিট বেকার

6
@ শেঠ কার্নেগি - আপনি পেছনের দিক থেকে হিরিস্টিক পেয়েছেন। হাতের অপ্টিমাইজেশন সাধারণত উচিত নয় সম্পন্ন করা যদি না আপনি দেখাতে পারেন যে, তারা প্রয়োজন হয়।
পিট বেকার

21
আপনার যদি এটির কাজ করার দরকার হয় তবে এটি কেবলমাত্র "অকাল" অপটিমাইজেশন। আমি অদক্ষদের চেয়ে দক্ষ আইডিয়াম গ্রহণে কোনও সমস্যা দেখছি না, এটি কোনও নির্দিষ্ট প্রসঙ্গে কোনও পার্থক্য তৈরি করে কিনা।
মার্ক র্যানসোম

11

এছাড়াও পরীক্ষা করে নিন যে #includeউত্সযুক্ত শ্রেণীর সম্পূর্ণ ঘোষণাযুক্ত শিরোলেখ ফাইলটি আপনার উত্স ফাইলে রয়েছে।

আমার এই সমস্যা ছিল std::shared<derived>কাস্ট না std::shared<base>। আমি উভয় ক্লাস ফরোয়ার্ড করে দিয়েছিলাম যাতে আমি তাদের কাছে পয়েন্টার ধরে রাখতে পারি, তবে #includeসংকলকটি না থাকায় দেখতে পেলাম না যে একটি শ্রেণি অন্য শ্রেণীর থেকে নেওয়া হয়েছিল।


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

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