Make_unique এবং নিখুঁত ফরোয়ার্ডিং


216

std::make_uniqueমানক সি ++ 11 লাইব্রেরিতে কেন কোনও ফাংশন টেম্পলেট নেই ? আমি খুজি

std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3));

কিছুটা ভার্জোজ। নিম্নলিখিত খুব ভাল না হবে?

auto p = std::make_unique<SomeUserDefinedType>(1, 2, 3);

এটি দুর্দান্তভাবে লুকায় newএবং কেবল একবারে টাইপের উল্লেখ করে।

যাইহোক, বাস্তবায়নের জন্য এখানে আমার প্রচেষ্টা make_unique:

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

সামগ্রীটি সংকলিত করতে আমার বেশ খানিকটা সময় লেগেছিল std::forwardতবে আমি এটি সঠিক কিনা তা নিশ্চিত নই। তাই কি? হুবুহু std::forward<Args>(args)...মানে কি? সংকলক এটি কি করে?


1
চমত্কার নিশ্চিত আমরা আগে ... এও নোট করুন যে এই আলোচনা ছিল unique_ptrথেকে আলাদা যে - একটি দ্বিতীয় টেমপ্লেট প্যারামিটার যা আপনি একরকম জন্য অনুমতি উচিত লাগে shared_ptr
কেরেক এসবি

5
@ কেরেক: আমি মনে করি না যে এটি make_uniqueএকটি কাস্টম মুছুনের সাথে প্যারামিটারাইজেশন করা বোধগম্য হবে, কারণ স্পষ্টতই এটি বরাদ্দ সাধারণ প্লেইনের মাধ্যমে newএবং সুতরাং অবশ্যই সরল পুরাতন ব্যবহার করতে হবেdelete :)
ফ্রেডওভারফ্লো

1
@ ফ্রেড: সত্য। সুতরাং, প্রস্তাবিত বরাদ্দের মধ্যে make_uniqueসীমাবদ্ধ থাকবে new... ভাল, আপনি যদি এটি লিখতে চান তবে এটি ঠিক আছে, তবে আমি দেখতে পাচ্ছি যে কেন এমন কিছু মানের অংশ নয়।
কেরেক এসবি

4
প্রকৃতপক্ষে, আমি কোনও make_uniqueটেম্পলেটটি ব্যবহার করতে পছন্দ করি যেহেতু এর std::unique_ptrনির্মাতা সুস্পষ্ট, এবং সুতরাং এটি unique_ptrকোনও ক্রিয়াকলাপ থেকে ফিরে আসা ভারবজ । এছাড়াও, আমি বরং ব্যবহার করতে চাই auto p = make_unique<foo>(bar, baz)চেয়ে std::unique_ptr<foo> p(new foo(bar, baz))
আলেকজান্দ্রি সি

উত্তর:


157

সি ++ স্ট্যান্ডার্ডাইজেশন কমিটির সভাপতি হার্ব সুটার তার ব্লগে লিখেছেন :

যে সি ++ 11 অন্তর্ভুক্ত নয় make_uniqueতা আংশিকভাবে একটি তদারকি এবং ভবিষ্যতে এটি অবশ্যই যুক্ত হবে।

তিনি এমন একটি বাস্তবায়নও দেন যা ওপি প্রদত্ত একটির সাথে সাদৃশ্যপূর্ণ।

সম্পাদনা করুন: std::make_unique এখন C ++ 14 এর অংশ ।


2
একটি make_uniqueফাংশন টেমপ্লেট নিজেই ব্যতিক্রম নিরাপদ কলগুলির গ্যারান্টি দেয় না। এটি কনভেনশন উপর নির্ভর করে, কলার এটি ব্যবহার করে। বিপরীতে, কঠোর স্ট্যাটিক টাইপ চেকিং (যা সি ++ এবং সি এর মধ্যে প্রধান পার্থক্য) বিভিন্ন ধরণের মাধ্যমে সুরক্ষা প্রয়োগের ধারণাটিতে নির্মিত । এবং তার জন্য, make_uniqueকেবল ফাংশনের পরিবর্তে ক্লাস হতে পারে। উদাহরণস্বরূপ, ২০১০ সালের মে থেকে আমার ব্লগ নিবন্ধটি দেখুন Her এটি হার্বের ব্লগের আলোচনা থেকেও যুক্ত।
চিয়ার্স এবং এইচটিএইচ - আলফ

1
@ ডেভিডরডগ্রিজেজ-ড্রিবিয়াস: ব্যতিক্রম সুরক্ষার বিষয়টি বুঝতে হার্বের ব্লগটি পড়ুন। "উত্সাহিত করার জন্য ডিজাইন করা হয়নি" সম্পর্কে ভুলে যান, এটি কেবল আবর্জনা। make_uniqueক্লাস করার বিষয়ে আমার পরামর্শের পরিবর্তে , এখন আমি এটির একটি ফাংশন তৈরি করা ভাল বলে মনে করি, এটির make_unique_tকারণটি সবচেয়ে বিকৃত পার্স :-) নিয়ে সমস্যা।
চিয়ার্স এবং এইচটিএইচ - আল্ফ

1
@ চিয়ারসান্থ.-আলফ: সম্ভবত আমরা একটি আলাদা নিবন্ধ পড়েছি, কারণ আমি স্রেফ পাঠ করেছি সেটিতে পরিষ্কারভাবে বলা হয়েছে যে make_uniqueশক্তিশালী ব্যতিক্রমের গ্যারান্টি সরবরাহ করে। অথবা হতে পারে আপনি সরঞ্জামটির ব্যবহারের সাথে মিশ্রণ করছেন, এই ক্ষেত্রে কোনও ফাংশন ব্যতিক্রম নিরাপদ নয়। বিবেচনা করুন void f( int *, int* ){}, স্পষ্টভাবে no throwগ্যারান্টি সরবরাহ করে তবে আপনার যুক্তি অনুসারে এটি ব্যতিক্রম নিরাপদ নয়, কারণ এটির অপব্যবহার করা যেতে পারে। সবচেয়ে খারাপ, void f( int, int ) {}ব্যতিক্রমটিও নিরাপদ নয় !: typedef unique_ptr<int> up; f( *up(new int(5)), *up(new int(10)))... ...
ডেভিড রদ্রিগেজ - ড্রিবিয়াস

2
@ Cheersandhth.-আলফ: আমি ব্যতিক্রম বিষয় সম্পর্কে জিজ্ঞাসা করা মধ্যে make_unique উপরে হিসাবে প্রয়োগ করা এবং আপনি আমাকে Sutter, নিবন্ধ যে আমার Google-Fu আমাকে রাজ্যের প্রতি ইঙ্গিত দ্বারা একটি নিবন্ধ নির্দেশ যে make_uniqueঅফার শক্তিশালী ব্যতিক্রম গ্যারান্টি , যা উপরে আপনার বিবৃতি contradicts। আপনি কি অন্য কিছু নিবন্ধ আছে যদি আমি আছি এটা পড়া আগ্রহী। সুতরাং আমার মূল প্রশ্নটি দাঁড়িয়েছে (উপরে সংজ্ঞায়িত হিসাবে) কীভাবে make_uniqueব্যতিক্রম নিরাপদ নয়? (সিডিনোট: হ্যাঁ, আমি মনে করি এটি যে জায়গাগুলিতে প্রয়োগ করা যেতে পারে সেখানে ব্যতিক্রম সুরক্ষার make_unique উন্নতি করে )
ডেভিড রদ্রিগেজ -

3
... এছাড়াও আমি make_uniqueফাংশনটি ব্যবহার করতে কম নিরাপদ চেষ্টা করছি না । প্রথমে আমি দেখতে পাচ্ছি না যে এটি কীভাবে অনিরাপদ এবং কোনও অতিরিক্ত প্রকার যোগ করা কীভাবে এটি নিরাপদ করে তুলবে তা আমি দেখছি না । আমি যা জানি তা হ'ল আমি এই বাস্তবায়ন করতে পারে এমন সমস্যাগুলি বুঝতে আগ্রহী - আমি কোনও দেখতে পাচ্ছি না - এবং বিকল্প বাস্তবায়ন কীভাবে তাদের সমাধান করবে would কি কি নিয়মাবলী যে make_uniqueউপর নির্ভর করে? সুরক্ষা প্রয়োগের জন্য আপনি কীভাবে টাইপ চেকিং ব্যবহার করবেন? এই দুটি প্রশ্ন যার জন্য আমি একটি উত্তর পছন্দ করব।
ডেভিড রদ্রিগেজ -

78

দুর্দান্ত, তবে স্টিফান টি। লাভভেজের (এসটিএল হিসাবে বেশি পরিচিত) এর আরও ভাল সমাধান রয়েছে make_unique, যা অ্যারে সংস্করণের জন্য সঠিকভাবে কাজ করে।

#include <memory>
#include <type_traits>
#include <utility>

template <typename T, typename... Args>
std::unique_ptr<T> make_unique_helper(std::false_type, Args&&... args) {
  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template <typename T, typename... Args>
std::unique_ptr<T> make_unique_helper(std::true_type, Args&&... args) {
   static_assert(std::extent<T>::value == 0,
       "make_unique<T[N]>() is forbidden, please use make_unique<T[]>().");

   typedef typename std::remove_extent<T>::type U;
   return std::unique_ptr<T>(new U[sizeof...(Args)]{std::forward<Args>(args)...});
}

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
   return make_unique_helper<T>(std::is_array<T>(), std::forward<Args>(args)...);
}

এটি তার কোর সি ++ 6 ভিডিওতে দেখা যাবে

মেক_উনিকের এসটিএল সংস্করণটির একটি আপডেট সংস্করণ এখন N3656 হিসাবে উপলভ্য । এই সংস্করণটি C ++ 14 খসড়াতে গৃহীত হয়েছে।


Make_unique পরবর্তী স্ট্যান্ড আপডেটে স্টিফেন টি লাভালেজ প্রস্তাব করেছেন।
টমিনেটর

এটি যুক্ত করার বিষয়ে তাঁর মতো একটি কথা এখানে রয়েছে। চ্যানেল
9.msdn.com/Series/C9-

সমস্ত অপ্রয়োজনীয় সম্পাদনাগুলি xeo করুন কেন, এটি ঠিক ছিল। এই কোডটি ঠিক স্টিফেন টি। লাভালেজ যেমন রেখেছিলেন ঠিক তেমনই ছিল এবং তিনি ডিংকমওয়ারের জন্য কাজ করেন যা স্ট্যান্ডের লাইব্রেরি রক্ষণাবেক্ষণ করে। আপনি ইতিমধ্যে wall দেয়ালে মন্তব্য করেছেন, যাতে আপনার জানা উচিত।
টমিনেটর

3
এর বাস্তবায়নটি make_uniqueএকটি শিরোনামে চলে। শিরোনামের কোনও নামস্থান আমদানি করা উচিত নয় (সুটার / আলেকজান্দ্রেস্কুর "সি ++ কোডিং স্ট্যান্ডার্ডস" বইয়ের আইটেম # 59 দেখুন)। জিও এর পরিবর্তনগুলি খারাপ অভ্যাসগুলিকে উত্সাহিত করতে এড়াতে সহায়তা করে।
ব্রেট কুহন্স

দুর্ভাগ্যক্রমে, ভিসি 2010 দ্বারা সমর্থিত নয়, এমনকি ভিসি ২০১২ আমিও মনে করি, যা উভয়ই বৈচিত্রময় টেম্পলেট প্যারামিটার সমর্থন করে না
zhaorufei

19

std::make_sharedঠিক সাধারণভাবে সংক্ষেপে নয় std::shared_ptr<Type> ptr(new Type(...));। এটি এমন কিছু করে যা আপনি পারবেন না এটি ছাড়া ।

এর কাজটি করার জন্য, std::shared_ptrঅবশ্যই সত্যিকারের পয়েন্টারের জন্য সঞ্চয় রাখা ছাড়াও একটি ট্র্যাকিং ব্লক বরাদ্দ করতে হবে । যাইহোক, std::make_sharedপ্রকৃত বস্তু বরাদ্দ করার কারণে , এটি একই মেমরির একই ব্লকে std::make_sharedঅবজেক্ট এবং ট্র্যাকিং ব্লক উভয়কে বরাদ্দ করে ।

সুতরাং যখন std::shared_ptr<Type> ptr = new Type(...);দুটি মেমরি বরাদ্দ হবে ( ট্র্যাকিং ব্লকের একটির জন্য newএকটি std::shared_ptr), মেমরির একটি ব্লক std::make_shared<Type>(...)বরাদ্দ করবে ।

এটি অনেক সম্ভাব্য ব্যবহারকারীদের জন্য গুরুত্বপূর্ণ std::shared_ptr। কেবলমাত্র একটি জিনিসটি std::make_uniqueহ'ল কিছুটা সুবিধাজনক। এর চেয়ে বেশি কিছু না।


2
এটি প্রয়োজন হয় না। ইঙ্গিতযুক্ত, তবে প্রয়োজন নেই।
কুকুরছানা

3
এটি কেবল সুবিধার জন্য নয় , এটি কিছু ক্ষেত্রে ব্যতিক্রমী সুরক্ষাও উন্নত করবে। তার জন্য কেরেক এসবি এর উত্তর দেখুন।
পাইট্র৯৯

19

যদিও আপনাকে আপনার নিজের সহায়িকা লিখতে কোনও কিছুই বাধা দেয় না, আমি বিশ্বাস করি যে make_shared<T>লাইব্রেরিতে সরবরাহ করার মূল কারণ হ'ল এটি আসলে আলাদা shared_ptr<T>(new T)আলাদা বরাদ্দকৃত তুলনায় আলাদা আলাদা অভ্যন্তরীণ ভাগের পয়েন্টার তৈরি করে , এবং উত্সর্গীকৃত ছাড়া এটি অর্জন করার কোনও উপায় নেই সাহায্যকারী।

make_uniqueঅন্যদিকে আপনার মোড়ক একটি newঅভিব্যক্তির চারপাশে নিছক সিনট্যাকটিক চিনি , যাতে এটি চোখকে সন্তুষ্ট মনে newহলেও টেবিলে কিছু এনে দেয় না । সংশোধন: এটি বাস্তবে সত্য নয় : এটিকে মোড়ানোর জন্য একটি ফাংশন কল করাnew এক্সপ্রেশনটি ব্যতিক্রমের সুরক্ষা সরবরাহ করে, উদাহরণস্বরূপ যেখানে আপনি কোনও ফাংশন কল করবেন সেই ক্ষেত্রে void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&)newএকে অপরের প্রতি সম্মানহীন এমন দুটি কাঁচা অর্থ হ'ল যদি একটি নতুন এক্সপ্রেশন ব্যতিক্রম ব্যর্থ হয় তবে অন্যটি সংস্থানগুলি ফাঁস করতে পারে। কেন make_uniqueস্ট্যান্ডার্ডে নেই: এটি কেবল ভুলে গিয়েছিল। (এটি মাঝেমধ্যে ঘটে। বিশ্বব্যাপীও নেইstd::cbegin standard স্ট্যান্ডার্ড থাকা সত্ত্বেও মানকটিতে ))

এছাড়াও নোট করুন যে unique_ptrএটি একটি দ্বিতীয় টেম্পলেট প্যারামিটার নেয় যা আপনাকে কোনওভাবে অনুমতি দেওয়া উচিত; এই বিভিন্ন থেকে shared_ptr, যা করতে টাইপ করুন ইরেজিওর ব্যবহার দোকান ধরনের তাদের অংশ না করে কাস্টম deleters।


1
@ ফ্রেড ওভারফ্লো: ভাগ করা পয়েন্টারটি তুলনামূলকভাবে জটিল শ্রেণি; অভ্যন্তরীণভাবে এটি একটি পলিমারফিক রেফারেন্স নিয়ন্ত্রণ ব্লক রাখে, তবে বিভিন্ন ধরণের নিয়ন্ত্রণ ব্লক রয়েছে। shared_ptr<T>(new T)এর মধ্যে একটি ব্যবহার করে, অন্যটি make_shared<T>()ব্যবহার করে। এটি মজাদার জিনিস হিসাবে দেওয়া এবং মেক-ভাগ করা সংস্করণটি কিছুটা অর্থে আপনি পেতে পারেন সবচেয়ে হালকা ওজন ভাগ করে নেওয়া পয়েন্টার।
কেরেরেক এসবি

15
@ ফ্রেড ওভারফ্লো: shared_ptrআপনি একটি তৈরি করার সময় গণনা এবং "নিষ্পত্তিকারী" ক্রিয়া ধরে রাখতে গতিশীল মেমরির একটি ব্লক বরাদ্দ করে shared_ptr। আপনি যদি স্পষ্টভাবে পয়েন্টারটি পাস করেন তবে এটির জন্য "নতুন" ব্লক তৈরি করা দরকার, আপনি যদি make_sharedএটি ব্যবহার করেন তবে এটি আপনার অবজেক্ট এবং উপগ্রহ ডেটা বান্ডিল করতে পারে মেমরির একক ব্লকে (এক new) যার ফলে দ্রুত বরাদ্দ / অবনমন, কম খণ্ডিতকরণ এবং সাধারণত ) আরও ভাল ক্যাশে আচরণ।
ম্যাথিউ মিঃ

2
আমি মনে করি আমার ভাগ করা_পিটার এবং বন্ধুদের পুনরায় দেখার দরকার ...
ফ্রেডওভারফ্লো

4
-1 "অন্যদিকে আপনার মেক_ ইউনিক র‍্যাপারটি একটি নতুন এক্সপ্রেশনটির চারপাশে নিছক সিনট্যাকটিক চিনি, যাতে এটি চোখে আনন্দিত লাগতে পারে, এটি টেবিলে নতুন কিছু আনেনি।" ভূল. এটি ব্যতিক্রম নিরাপদ ফাংশন প্রার্থনার সম্ভাবনা নিয়ে আসে। এটি কোনও গ্যারান্টি আনবে না; তার জন্য, এটি শ্রেণি হওয়া দরকার যাতে the শ্রেণীর বিষয়ে আনুষ্ঠানিক যুক্তিগুলি ঘোষিত হতে পারে (হার্ব বর্ণনা করেছেন যে অপ্ট-ইন এবং অপ্ট-আউটের মধ্যে পার্থক্য হিসাবে)।
চিয়ার্স এবং এইচটিএইচ - আলফ

1
@ চিয়ারসান্থথ.-আলফ: হ্যাঁ, এটা সত্য। আমি তখন থেকে বুঝতে পেরেছি। আমি উত্তরটি সম্পাদনা করব।
কেরেক এসবি 12'12

13

সি ++ 11 এ ... "প্যাক সম্প্রসারণ" এর জন্য (টেমপ্লেট কোডে) ব্যবহৃত হয়।

প্রয়োজনীয়তা হ'ল আপনি এটিকে প্যারামিটারের একটি অপরিবর্তিত প্যাকেজযুক্ত একটি অভিব্যক্তিটির প্রত্যয় হিসাবে ব্যবহার করুন এবং এটি প্যাকের প্রতিটি উপাদানগুলিতে সহজেই অভিব্যক্তিটি প্রয়োগ করবে।

উদাহরণস্বরূপ, আপনার উদাহরণের উপর ভিত্তি করে:

std::forward<Args>(args)... -> std::forward<int>(1), std::forward<int>(2),
                                                     std::forward<int>(3)

std::forward<Args...>(args...) -> std::forward<int, int, int>(1,2,3)

পরেরটি ভুল বলে আমি মনে করি।

এছাড়াও, যুক্তিগুলির প্যাকটি অপরিবর্তিত কোনও ফাংশনে দেওয়া হবে না। আমি টেম্পলেট প্যারামিটারগুলির একটি প্যাক সম্পর্কে অনিশ্চিত।


1
এই বানানটি দেখে ভাল লাগল। বৈকল্পিক টেম্পলেট প্যারামিটারটিও কেন অন্তর্ভুক্ত করবেন না?
কেরেক এসবি

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

বাক্য std::forward<Args>(args)...গঠনটি যা প্রসারিত হয় forward<T1>(x1), forward<T2>(x2), ...
কেরেরেক এসবি

1
: আমি মনে করি forwardআসলে সবসময় একটি টেম্পলেট প্যারামিটার প্রয়োজন, তাই না?
কেরেক এসবি

1
@ হাওয়ার্ড: ঠিক! জোরপূর্বক ইনস্ট্যান্টেশন সতর্কবার্তাটি ট্রিগার করে ( আইডিয়োনা / জিডিএনএইচবি )
এম।

5

স্টিফান টি। লাভভেজের বাস্তবায়ন দ্বারা অনুপ্রাণিত হয়ে, আমি ভেবেছিলাম যে মেক_উনিকটি অ্যারে এক্সটেন্টগুলিকে সমর্থন করেছিল, এটি গিথুবে রয়েছে এবং আমি এটি সম্পর্কে মন্তব্য করতে পছন্দ করব। এটি আপনাকে এটি করতে দেয়:

// create unique_ptr to an array of 100 integers
auto a = make_unique<int[100]>();

// create a unique_ptr to an array of 100 integers and
// set the first three elements to 1,2,3
auto b = make_unique<int[100]>(1,2,3); 
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.