একটি অ্যারে তে শেয়ার্ড_প্রেটার: এটি ব্যবহার করা উচিত?


172

সম্পর্কিত একটি ছোট প্রশ্ন shared_ptr

shared_ptrঅ্যারে নির্দেশ করে ব্যবহার করা কি ভাল অভ্যাস ? উদাহরণ স্বরূপ,

shared_ptr<int> sp(new int[10]);

তা না হলে কেন হয় না? আমি ইতিমধ্যে সচেতন একটি কারণ হ'ল এটি কোনও বৃদ্ধি / হ্রাস করতে পারে না shared_ptr। সুতরাং এটি অ্যারেতে সাধারণ পয়েন্টারের মতো ব্যবহার করা যায় না।


2
FWIT, আপনি কেবল ব্যবহার বিবেচনা করতে পারেন std::vector। রেফারেন্সগুলি ব্যবহার করে আপনাকে অ্যারে পাস করার ক্ষেত্রে যত্নবান হতে হবে যাতে আপনি এটির অনুলিপিগুলি তৈরি না করেন। ডেটা অ্যাক্সেসের জন্য সিনট্যাক্স শেয়ার্ড_প্টারের চেয়ে পরিষ্কার এবং এটির আকার পরিবর্তন করা খুব সহজ। এবং আপনি সবসময় এটি চাইলে আপনি সমস্ত এসটিএল উপকার পাবেন।
নিকু স্টিড়কা

6
যদি সংকলনের সময় অ্যারের আকার নির্ধারণ করা হয় তবে আপনি ব্যবহারটি বিবেচনাও করতে পারেন std::array। এটি প্রায়শই কাঁচা অ্যারের মতো তবে বেশিরভাগ লাইব্রেরির উপাদানগুলিতে ব্যবহারের জন্য উপযুক্ত শব্দার্থবিজ্ঞানের সাথে। বিশেষত type ধরণের জিনিসগুলি deleteনা দিয়ে ধ্বংস হয় delete[]। এবং বিপরীতে vector, এটি সরাসরি অবজেক্টে ডেটা সঞ্চয় করে, তাই আপনি কোনও অতিরিক্ত বরাদ্দ পাবেন না।
celtschk

উত্তর:


268

সঙ্গে সি ++ 17 , shared_ptrএকটি পরিবর্তনশীল বরাদ্দ অ্যারের পরিচালনা করতে ব্যবহার করা যাবে। shared_ptrএই ক্ষেত্রে টেমপ্লেট যুক্তি থাকতে হবে T[N]বা T[]। সুতরাং আপনি লিখতে পারেন

shared_ptr<int[]> sp(new int[10]);

N4659 থেকে, [use.smartptr.shared.const]

  template<class Y> explicit shared_ptr(Y* p);

প্রয়োজনীয়: Y একটি সম্পূর্ণ ধরণের হবে। এক্সপ্রেশনটি delete[] pযখন Tকোনও অ্যারে টাইপ হয় বা delete pযখন Tঅ্যারে টাইপ হয় না তখন তার সুস্পষ্ট সংজ্ঞা দেওয়া আচরণ থাকতে পারে এবং ব্যতিক্রম ছুঁড়ে না ফেলে।
...
মন্তব্যসমূহ: যখন Tকোনও অ্যারে টাইপ হয়, এই delete[] pনির্মাতা ওভারলোড রেজোলিউশনে অংশ নেবে না যতক্ষণ না এক্সপ্রেশনটি সুসংহত হয় এবং হয় Tহয় U[N]এবং Y(*)[N]রূপান্তরিত হয় T*, বা Tহয় U[]এবং Y(*)[]রূপান্তরিত হয় T*। ...

এটি সমর্থন করার জন্য, সদস্যের ধরনটি element_typeএখন হিসাবে সংজ্ঞায়িত করা হয়েছে

using element_type = remove_extent_t<T>;

অ্যারে উপাদানগুলি ব্যবহার করে অ্যাক্সেস হতে পারে operator[]

  element_type& operator[](ptrdiff_t i) const;

প্রয়োজন: get() != 0 && i >= 0। যদি Tহয় U[N], i < N। ...
মন্তব্যসমূহ: যখন Tকোনও অ্যারে টাইপ হয় না, তখন এই সদস্য ফাংশনটি ঘোষিত হয় কিনা তা অনির্দিষ্ট। যদি এটি ঘোষণা করা হয় তবে এটির ফেরতের প্রকারটি কী তা অনির্দিষ্ট নয়, ব্যতীত ফাংশনের ঘোষণাপত্রটি (যদিও সংজ্ঞায়নের অগত্যা নয়) ভালভাবে গঠন করা হবে।


সি ++ 17 এর আগে , shared_ptrপারে না পরিবর্তনশীল বরাদ্দ অ্যারে পরিচালনা ব্যবহৃত হবে না। ডিফল্টরূপে, পরিচালিত অবজেক্টটিতে shared_ptrকল deleteকরা হবে যখন এতে আর কোনও রেফারেন্স থাকে না। যাইহোক, আপনি যখন বরাদ্দ ব্যবহার করে new[]আপনার কল করা উচিত delete[], এবং না delete, রিসোর্সটি মুক্ত করার জন্য।

shared_ptrকোনও অ্যারের সাথে সঠিকভাবে ব্যবহার করার জন্য আপনাকে অবশ্যই একটি কাস্টম মুছুন সরবরাহকারী সরবরাহ করতে হবে।

template< typename T >
struct array_deleter
{
  void operator ()( T const * p)
  { 
    delete[] p; 
  }
};

নীচে শেয়ারড_পিটার তৈরি করুন:

std::shared_ptr<int> sp(new int[10], array_deleter<int>());

পরিচালিত অবজেক্টটি ধ্বংস shared_ptrকরার delete[]সময় এখন সঠিকভাবে কল করবে ।

উপরের কাস্টম মোছা দ্বারা প্রতিস্থাপন করা যেতে পারে

  • std::default_deleteঅ্যারে ধরনের জন্য আংশিক বিশেষজ্ঞতা

    std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
  • একটি ল্যাম্বডা এক্সপ্রেশন

    std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });

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

std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]

লাইব্রেরি ফান্ডামেন্টালগুলির জন্য সি ++ এক্সটেনশনগুলি দ্বারা পরিবর্তনগুলি প্রবর্তিত

উপরের তালিকাভুক্তগুলির সাথে আরও একটি প্রাক সি -++ বিকল্প লাইব্রেরি ফান্ডামেন্টালস টেকনিক্যাল স্পেসিফিকেশন দ্বারা সরবরাহ করা হয়েছিল , shared_ptrএটি যখন বস্তুর একটি অ্যারের মালিক তখন এটিগুলি বাক্সের বাইরে কাজ করার অনুমতি দিতে সহায়তা করে। এই টিএসেরshared_ptr জন্য পরিবর্তিত পরিবর্তনগুলির বর্তমান খসড়াটি N4082 এ পাওয়া যাবে । এই পরিবর্তনগুলি std::experimentalনেমস্পেসের মাধ্যমে অ্যাক্সেসযোগ্য এবং <experimental/memory>শিরোলেখের অন্তর্ভুক্ত থাকবে । shared_ptrঅ্যারের সমর্থনে প্রাসঙ্গিক কয়েকটি পরিবর্তন হ'ল:

- সদস্যের সংজ্ঞা element_typeপরিবর্তিত হয়

টাইপডেফ টি উপাদান_প্রকার;

 typedef typename remove_extent<T>::type element_type;

- সদস্য operator[]যোগ করা হচ্ছে

 element_type& operator[](ptrdiff_t i) const noexcept;

- ভিন্ন unique_ptrঅ্যারে জন্য আংশিক বিশেষজ্ঞতা, উভয় shared_ptr<T[]>এবং shared_ptr<T[N]>কার্যকর থাকবে এবং উভয় পরিণাম ডেকে আনবে delete[]বস্তুর পরিচালিত অ্যারের আহ্বান করা হচ্ছে।

 template<class Y> explicit shared_ptr(Y* p);

প্রয়োজনীয় : Yএকটি সম্পূর্ণ ধরণের হবে। এক্সপ্রেশনটি delete[] pযখন Tঅ্যারে টাইপ হয়, বা delete pযখন Tঅ্যারে টাইপ হয় না , তখন সুগঠিত হবে, তার সঠিক সংজ্ঞা দেওয়া আচরণ হবে এবং ব্যতিক্রম ছুঁড়ে দেওয়া হবে না। যখন Tহয় U[N], তখন Y(*)[N]রূপান্তরিত হবে T*; কখন Tহবে U[], Y(*)[]রূপান্তরিত হবে T*; অন্যথায়, Y*রূপান্তরযোগ্য হবে T*


9
+1, মন্তব্য: বুস্টেরও আছে shared-array
jogojapan

5
@ tshah06 shared_ptr::getপরিচালিত অবজেক্টটিতে একটি পয়েন্টার দেয়। সুতরাং আপনি এটি হিসাবে ব্যবহার করতে পারেনsp.get()[0] = 1; ... sp.get()[9] = 10;
প্রিটোরিয়ান

55
ALT: std::shared_ptr<int> sp( new int[10], std::default_delete<int[]>() );এছাড়াও দেখুন en.cppreferences.com/w/cpp/memory/default_delete
yohjp

2
@ জেরেমি যদি সংকলনের সময় আকারটি জানা থাকে তবে এর জন্য কোনও ক্লাস লেখার দরকার নেই, std::shared_ptr<std::array<int,N>>যথেষ্ট হওয়া উচিত।
প্রিটোরিয়ান

13
কেন unique_ptrযে আংশিক বিশেষীকরণ পান কিন্তু shared_ptrনা?
অ্যাডাম

28

আপনি সম্ভবত ব্যবহার করতে সক্ষম হবেন সম্ভবত একটি সহজ বিকল্প shared_ptr<vector<int>>


5
হ্যাঁ তাই হয়। বা ভেক্টর একটি অ্যারের সুপারস্টার - এটির মেমোরি উপস্থাপনা (প্লাস মেটাডেটা) একই রকম তবে এটি পুনরায় আকার পরিবর্তনযোগ্য। সত্যিই এমন কোনও পরিস্থিতি নেই যেখানে আপনি অ্যারে চান তবে ভেক্টর ব্যবহার করতে পারবেন না।
টিএমএমএম

2
পার্থক্যটি, এখানে, ভেক্টরের আকারটি আরও স্থির এবং ডেটা অ্যাক্সেস দ্বিগুণ প্রেরণা দিয়ে সম্পন্ন হবে। যদি পারফরম্যান্স সমালোচনামূলক সমস্যা না হয় তবে এটি কাজ করে, অন্যথায় অ্যারে ভাগ করে নেওয়ার নিজস্ব কারণ থাকতে পারে।
এমিলিও গারাভাগলিয়া

4
তাহলে আপনি সম্ভবত ব্যবহার করতে পারেন shared_ptr<array<int, 6>>
টিম্ম্ম্ম

10
অন্য পার্থক্য হ'ল এটি একটি কাঁচা অ্যারের চেয়ে কিছুটা বড় এবং ধীর। সাধারণত সত্যই সমস্যা হয় না তবে আসুন 1 == 1.1 এর ভান করা উচিত না।
অ্যান্ড্রু

2
এমন পরিস্থিতি রয়েছে যেখানে অ্যারের মধ্যে ডেটার উত্সের অর্থ হ'ল এটি ভেক্টরে রূপান্তর করা অযাচিত বা অপ্রয়োজনীয়; যেমন কোনও ক্যামেরা থেকে ফ্রেম পাওয়ার সময়। (বা, এটি যাইহোক, আমার বোধগম্য)
নার্ফানেটর
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.