পার্থক্যটি হ'ল std::make_shared
একটি গাদা-বরাদ্দ সম্পাদন করে, যেখানে std::shared_ptr
কনস্ট্রাক্টরকে কল করা দুটি সম্পাদন করে।
গাদা-বরাদ্দ কোথায় ঘটে?
std::shared_ptr
দুটি সত্ত্বা পরিচালনা করে:
- নিয়ন্ত্রণ ব্লক (মেটা ডেটা যেমন রেফ-কাউন্ট, টাইপ-মোছা মুছনকারী ইত্যাদি সঞ্চয় করে)
- বস্তু পরিচালিত হচ্ছে
std::make_shared
নিয়ন্ত্রণ ব্লক এবং ডেটা উভয়ের জন্য প্রয়োজনীয় জায়গার জন্য একক গাদা-বরাদ্দ অ্যাকাউন্টিং সম্পাদন করে। অন্য ক্ষেত্রে, new Obj("foo")
পরিচালিত ডেটার জন্য একটি গাদা-বরাদ্দের অনুরোধ করে এবং std::shared_ptr
কনস্ট্রাক্টর নিয়ন্ত্রণ ব্লকের জন্য আরেকটি সঞ্চালন করে।
আরও তথ্যের জন্য, cppreferences এ প্রয়োগকরণ নোটগুলি পরীক্ষা করে দেখুন ।
আপডেট আমি: ব্যতিক্রম-সুরক্ষা
দ্রষ্টব্য (2019/08/30) : ফাংশন আর্গুমেন্টগুলির মূল্যায়ন আদেশের পরিবর্তনের কারণে সি ++ 17 থেকে এটি কোনও সমস্যা নয়। বিশেষত, অন্য কোনও যুক্তি মূল্যায়নের আগে কোনও ক্রিয়াকলাপের প্রতিটি যুক্তি পুরোপুরি কার্যকর করা প্রয়োজন।
যেহেতু ওপি জিনিসগুলির ব্যতিক্রম-সুরক্ষা দিকটি নিয়ে ভাবছে বলে মনে হচ্ছে, তাই আমি আমার উত্তর আপডেট করেছি।
এই উদাহরণটি বিবেচনা করুন,
void F(const std::shared_ptr<Lhs> &lhs, const std::shared_ptr<Rhs> &rhs) { /* ... */ }
F(std::shared_ptr<Lhs>(new Lhs("foo")),
std::shared_ptr<Rhs>(new Rhs("bar")));
যেহেতু সি ++ স্বেচ্ছাসেবীগুলির মূল্যায়নের স্বেচ্ছাসেবী আদেশের অনুমতি দেয়, একটি সম্ভাব্য অর্ডারিং হ'ল:
new Lhs("foo"))
new Rhs("bar"))
std::shared_ptr<Lhs>
std::shared_ptr<Rhs>
এখন, ধরুন আমরা পদক্ষেপ 2 এ ছোঁড়া একটি ব্যতিক্রম পেয়েছি (উদাহরণস্বরূপ, মেমরির ব্যতিক্রমের বাইরে, Rhs
নির্মাণকারী কিছু ব্যতিক্রম ছুঁড়ে দিয়েছেন)। এরপরে আমরা 1 ম পদক্ষেপে বরাদ্দ থাকা স্মৃতি হারিয়ে ফেলি কারণ কোনও কিছুই এটিকে পরিষ্কার করার সুযোগ পাবে না। এখানে সমস্যার মূল বিষয়টি হ'ল কাঁচা পয়েন্টারটি সাথে সাথে std::shared_ptr
কনস্ট্রাক্টরের কাছে পৌঁছে দেওয়া হয়নি ।
এটির সমাধানের একটি উপায় হ'ল এগুলি পৃথক লাইনে করা যাতে এই স্বেচ্ছাসেবী অর্ডার না ঘটে।
auto lhs = std::shared_ptr<Lhs>(new Lhs("foo"));
auto rhs = std::shared_ptr<Rhs>(new Rhs("bar"));
F(lhs, rhs);
অবশ্যই এটি সমাধান করার জন্য পছন্দের উপায়টি std::make_shared
পরিবর্তে ব্যবহার করা।
F(std::make_shared<Lhs>("foo"), std::make_shared<Rhs>("bar"));
আপডেট দ্বিতীয়: এর অসুবিধা std::make_shared
ক্যাসির মন্তব্য উদ্ধৃত :
যেহেতু এখানে কেবলমাত্র একটি বরাদ্দ রয়েছে, যতক্ষণ না নিয়ন্ত্রণ ব্লক ব্যবহার না করা হয় ততক্ষণ পয়েন্টটির স্মৃতিশক্তি হ্রাস করা যায় না। ক weak_ptr
কন্ট্রোল ব্লককে অনির্দিষ্টকালের জন্য বাঁচিয়ে রাখতে পারে।
weak_ptr
এর উদাহরণগুলি কেন নিয়ন্ত্রণ ব্লককে বাঁচিয়ে রাখে?
weak_ptr
পরিচালিত অবজেক্টটি এখনও বৈধ কিনা তা নির্ধারণ করার জন্য অবশ্যই একটি উপায় থাকতে হবে (উদাহরণস্বরূপ lock
)। shared_ptr
কন্ট্রোল ব্লকে সংরক্ষণ করা ম্যানেজড অবজেক্টের মালিকানাধীন সংখ্যার পরীক্ষা করে তারা এটি করে । ফলাফলটি হ'ল কন্ট্রোল ব্লকগুলি shared_ptr
গণনা এবং অবধি বেঁচে থাকেweak_ptr
গণনা দুটি হিট করে hit
আবার std::make_shared
যেহেতু std::make_shared
নিয়ন্ত্রণ ব্লক এবং পরিচালিত বস্তু উভয়ের জন্য একক হিপ-বরাদ্দ করে, তাই নিয়ন্ত্রণ ব্লক এবং পরিচালিত বস্তুর জন্য মেমরিটি স্বাধীনভাবে মুক্ত করার কোনও উপায় নেই। আমাদের নিয়ন্ত্রণ ব্লক এবং পরিচালিত অবজেক্ট উভয়ই মুক্ত না করা পর্যন্ত আমাদের অপেক্ষা করতে হবে, যা কোনও shared_ptr
এস বা weak_ptr
এস জীবিত না হওয়া পর্যন্ত ঘটে ।
মনে করুন পরিবর্তে আমরা নিয়ন্ত্রণ ব্লক এবং পরিচালকের মাধ্যমে new
এবং shared_ptr
কনস্ট্রাক্টরের জন্য দুটি হ্যাপ-বরাদ্দ সম্পাদন করেছি । তারপরে আমরা কোনও shared_ptr
জীবিত না থাকা অবস্থায় পরিচালিত অবজেক্টের (সম্ভবত আগে) স্মৃতি মুক্ত করি এবং যখন কোনও weak_ptr
জীবন্ত থাকে না তখন নিয়ন্ত্রণ ব্লকের (সম্ভবত পরে) মেমরি মুক্ত করি ।