std :: ভেক্টর (আব) স্বয়ংক্রিয় স্টোরেজ ব্যবহার করে


46

নিম্নলিখিত স্নিপেট বিবেচনা করুন:

#include <array>
int main() {
  using huge_type = std::array<char, 20*1024*1024>;
  huge_type t;
}

স্পষ্টতই এটি বেশিরভাগ প্ল্যাটফর্মে ক্রাশ হবে কারণ ডিফল্ট স্ট্যাকের আকারটি সাধারণত 20MB এর চেয়ে কম থাকে।

এখন নিম্নলিখিত কোড বিবেচনা করুন:

#include <array>
#include <vector>

int main() {
  using huge_type = std::array<char, 20*1024*1024>;
  std::vector<huge_type> v(1);
}

আশ্চর্যরূপে এটি ক্রাশও হয়! ট্রেসব্যাক (সাম্প্রতিক libstdc ++ সংস্করণগুলির একটিতে) include/bits/stl_uninitialized.hফাইলের দিকে পরিচালিত করে , যেখানে আমরা নীচের লাইনগুলি দেখতে পারি:

typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
std::fill(__first, __last, _ValueType());

আকার পরিবর্তনকারী vectorকনস্ট্রাক্টরের অবশ্যই উপাদানগুলিকে ডিফল্ট-আরম্ভ করতে হবে এবং এটি এভাবেই প্রয়োগ করা হয়। স্পষ্টতই, _ValueType()অস্থায়ী স্ট্যাকটি ক্র্যাশ করে।

প্রশ্নটি এটি কার্যকরভাবে বাস্তবায়ন কিনা। যদি হ্যাঁ, তবে এর অর্থ হ'ল বিশাল ধরণের ভেক্টরের ব্যবহার বেশ সীমাবদ্ধ, তাই না?


একটিকে অ্যারের প্রকারে বিশাল আকারের জিনিস সংরক্ষণ করা উচিত নয়। এটি করার জন্য সম্ভাব্য মেমরির একটি খুব বড় অঞ্চল প্রয়োজন যা উপস্থিত নাও থাকতে পারে। পরিবর্তে, পয়েন্টারগুলির একটি ভেক্টর রাখুন (স্ট্যান্ড :: অনন্য_পাত্র সাধারণত) যাতে আপনি আপনার স্মৃতিতে এত বেশি চাহিদা না রাখেন।
নাথান অলিভার

2
শুধু স্মৃতি। C ++ বাস্তবায়ন চলছে যা ভার্চুয়াল মেমরি ব্যবহার করে না।
নাথান অলিভার

3
কোন সংকলক, বিটিডব্লিউ? আমি ভিএস 2019 (16.4.2)
ক্রিসএমএম

3
Libstdc ++ কোডটি দেখে, এই প্রয়োগটি কেবল তখনই ব্যবহৃত হয় যদি উপাদান টাইপের তুচ্ছ এবং অনুলিপিযোগ্যযোগ্য হয় এবং যদি ডিফল্ট std::allocatorব্যবহার হয়।
আখরোট

1
@ ড্যামন যেমন আমি উপরে উল্লেখ করেছি এটি কেবলমাত্র ডিফল্ট বরাদ্দকারীর সাথে তুচ্ছ প্রকারের জন্য ব্যবহৃত হবে বলে মনে হয়, যাতে কোনও পর্যবেক্ষণযোগ্য পার্থক্য হওয়া উচিত নয়।
আখরোট

উত্তর:


19

কোনও স্টাডি এপিআই কত স্বয়ংক্রিয় স্টোরেজ ব্যবহার করে তার কোনও সীমা নেই।

তাদের সকলের জন্য 12 টেরাবাইট স্ট্যাক স্পেসের প্রয়োজন হতে পারে।

তবে, সেই এপিআই কেবল প্রয়োজন Cpp17DefaultInsertable, এবং আপনার বাস্তবায়ন কনস্ট্রাক্টর দ্বারা প্রয়োজনীয় কিসের উপরে একটি অতিরিক্ত উদাহরণ তৈরি করে। অবজেক্টটি সনাক্তকরণের পিছনে এটি দ্বিধাগ্রস্থ না করা হলে তুচ্ছ।


8
Libstdc ++ কোডটি দেখে, এই প্রয়োগটি কেবল তখনই ব্যবহৃত হয় যদি উপাদান টাইপের তুচ্ছ এবং অনুলিপিযোগ্যযোগ্য হয় এবং যদি ডিফল্ট std::allocatorব্যবহার হয়। এই বিশেষ মামলাটি কেন প্রথম স্থানে তৈরি হয়েছে তা আমি নিশ্চিত নই।
আখরোট

3
@ ওয়ালান্ট যার অর্থ সংকলক প্রকৃতপক্ষে অস্থায়ী অবজেক্টটি তৈরি না করে মুক্ত; আমি অনুমান করছি যে এটি তৈরি হয় না এমন একটি অনুকূল অনুকূল তৈরির জন্য একটি শালীন সুযোগ আছে?
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

4
হ্যাঁ, আমি অনুমান করি এটি পারে তবে বড় উপাদানগুলির জন্য জিসিসি বলে মনে হয় না। Libstdc ++ এর সাথে ঝাঁকুনি অস্থায়ীটিকে অপ্টিমাইজ করে, তবে কেবল তখনই মনে হয় যে কনস্ট্রাক্টরের কাছে ভেক্টর আকারটি একটি সংকলন-সময় ধ্রুবক হয়, Godbolt.org/z/-2ZDMm দেখুন
আখরোট

1
@ ওয়ালটনের একটি বিশেষ কেস রয়েছে যাতে আমরা std::fillতুচ্ছ প্রকারের জন্য প্রেরণ করি যা এরপরে memcpyস্থানগুলিতে বাইটগুলি বিস্ফোরিত করতে ব্যবহার করে, যা লুপে পৃথক পৃথক অবজেক্ট তৈরির চেয়ে অনেক দ্রুত। আমি বিশ্বাস করি যে libstdc ++ বাস্তবায়ন মেনে চলছে, তবে বিশাল বস্তুর জন্য স্ট্যাকের ওভারফ্লো সৃষ্টি করাই একটি মান বাস্তবায়ন (কিউআই) বাগ is আমি এটি gcc.gnu.org/PR94540 হিসাবে রিপোর্ট করেছি এবং এটি ঠিক করে দেব।
জোনাথন ওয়েকেলি

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

9
huge_type t;

স্পষ্টতই এটি বেশিরভাগ প্ল্যাটফর্মে ক্রাশ হবে ...

আমি "সর্বাধিক" অনুমান নিয়ে বিতর্ক করি। যেহেতু বিশাল বস্তুর স্মৃতি কখনই ব্যবহৃত হয় না, সংকলক এটিকে সম্পূর্ণ উপেক্ষা করতে পারে এবং মেমরিটিকে কখনই বরাদ্দ করতে পারে না যেখানে কোনও ক্র্যাশ হবে না।

প্রশ্নটি এটি কার্যকরভাবে বাস্তবায়ন কিনা।

সি ++ স্ট্যান্ডার্ড স্ট্যাক ব্যবহারকে সীমাবদ্ধ করে না, বা এমনকি স্ট্যাকের অস্তিত্ব স্বীকার করে না। সুতরাং, হ্যাঁ এটি মান অনুসারে। তবে কেউ এটিকে বাস্তবায়নের সমস্যা হিসাবে বিবেচনা করতে পারে।

এর প্রকৃত অর্থ বিশাল আকারের ভেক্টরের ব্যবহার বেশ সীমাবদ্ধ, তাই না?

এটি libstdc ++ এর ক্ষেত্রে দেখা যায়। ক্র্যাশটি libc ++ (ঝনঝন ব্যবহার করে) দিয়ে পুনরুত্পাদন করা হয়নি, সুতরাং মনে হচ্ছে এটি ভাষার সীমাবদ্ধতা নয়, কেবলমাত্র সেই নির্দিষ্ট প্রয়োগের ক্ষেত্রে।


6
"স্ট্যাকের উপচে পড়া সত্ত্বেও অগত্যা ক্রাশ হবে না কারণ বরাদ্দ মেমরিটি প্রোগ্রামের মাধ্যমে কখনও অ্যাক্সেস পায় না" - যদি স্ট্যাকটি এর পরে কোনও উপায়ে ব্যবহার করা হয় (উদাহরণস্বরূপ কোনও ফাংশন ডাকতে), এটি ওভার-কমিটিং প্ল্যাটফর্মগুলিতে ক্রাশ হবে ।
রুসলান

যে প্ল্যাটফর্মের উপর এটি ক্রাশ হয় না (ধরে নেওয়া অবজেক্টটি সফলভাবে বরাদ্দ করা হয়নি) স্ট্যাক ক্ল্যাশের পক্ষে ঝুঁকিপূর্ণ।
ব্যবহারকারী 253751

@ ব্যবহারকারী 253751 এটি ধরে নেওয়া আশাবাদী যে বেশিরভাগ প্ল্যাটফর্ম / প্রোগ্রামগুলি ঝুঁকিপূর্ণ নয়।
এরেরিকা

আমি মনে করি ওভার কমিট কেবল স্তূপের জন্য প্রযোজ্য, স্ট্যাকের জন্য নয়। স্ট্যাকের আকারের উপরে একটি নির্দিষ্ট উপরের আবদ্ধ থাকে।
জোনাথন ওয়াকলি

পছন্দ করেছেন এটি প্রদর্শিত হচ্ছে যে এটি ক্রাশ না হওয়ার কারণ হ'ল সংকলকটি কখনই অব্যবহৃত অবজেক্টটি বরাদ্দ করে না।
এরেরিকা

5

আমি কোনও ভাষার আইনজীবী বা সি ++ মানক বিশেষজ্ঞ নই, তবে সিপ্রেফারেন্স ডটকম বলেছেন:

explicit vector( size_type count, const Allocator& alloc = Allocator() );

টি এর গণনা ডিফল্ট-সন্নিবেশিত উদাহরণ সহ ধারক তৈরি করে No কোনও অনুলিপি তৈরি করা হয় না।

সম্ভবত আমি "ডিফল্ট-সন্নিবেশিত" ভুল বোঝাবুঝি করছি তবে আমি আশা করব:

std::vector<huge_type> v(1);

সমান হতে

std::vector<huge_type> v;
v.emplace_back();

পরবর্তী সংস্করণটি স্ট্যাক অনুলিপি তৈরি করা উচিত নয় তবে ভেক্টরের গতিশীল মেমরিতে সরাসরি একটি বিশাল আকারের নির্মাণ করা উচিত।

আমি প্রামাণিকভাবে বলতে পারছি না যে আপনি যা দেখছেন তা অনুপযুক্ত, তবে এটি অবশ্যই মানসম্পন্ন বাস্তবায়নের থেকে আশা করব না।


4
আমি যেমন প্রশ্নের একটি মন্তব্যে উল্লেখ করেছি যে, libstdc ++ কেবল অনুলিপি নিয়োগের সাথে তুচ্ছ প্রকারের জন্য এই প্রয়োগটি ব্যবহার করে এবং std::allocatorতাই ভেক্টর মেমরিতে সরাসরি andোকানো এবং একটি মধ্যবর্তী অনুলিপি তৈরি করার মধ্যে কোনও পর্যবেক্ষণযোগ্য পার্থক্য থাকতে হবে না।
আখরোট

@ ওয়ালনাট: ঠিক আছে, তবে বিশাল স্ট্যাক বরাদ্দ এবং আরআইপি এবং অনুলিপি এর কার্যকারিতা প্রভাব এখনও এমন জিনিস যা আমি উচ্চমানের বাস্তবায়ন থেকে আশা করবো না।
অ্যাড্রিয়ান ম্যাকার্থি

2
হ্যা আমি রাজি. আমি মনে করি এটি বাস্তবায়নের একটি তদারকি ছিল। আমার বক্তব্যটি কেবল এটি ছিল যে এটি মান সম্মততার ক্ষেত্রে বিবেচ্য নয়।
আখরোট

আইআইআরসি আপনারও অনুলিপি বা চলন প্রয়োজন emplace_backতবে কেবল ভেক্টর তৈরি করার জন্য নয়। যার অর্থ আপনার কাছে থাকতে পারে vector<mutex> v(1)তবে তা নয় vector<mutex> v; v.emplace_back();তবে huge_typeআপনার কাছে এখনও অন্য বরাদ্দ থাকা এবং বরাদ্দকরণের কাজ থাকতে পারে operation উভয়ই অস্থায়ী বস্তু তৈরি করা উচিত নয়।
ডাইপ

1
@IgorR। vector::vector(size_type, Allocator const&)(Cpp17) DefaultInsertable
ডায়প
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.