সি ++ তে ভেক্টরের প্রাথমিক ক্ষমতা


92

কি capacity()একটি এর std::vectorযা ডিফল্টভাবে constuctor ব্যবহার করে তৈরি করা হয়? আমি জানি যে size()শূন্য। আমরা কি বলতে পারি যে একটি ডিফল্ট নির্মিত ভেক্টর হিপ মেমরি বরাদ্দ কল করে না?

এইভাবে একটি একক বরাদ্দ ব্যবহার করে একটি স্বেচ্ছাসেবক রিজার্ভ দিয়ে একটি অ্যারে তৈরি করা সম্ভব হবে std::vector<int> iv; iv.reserve(2345);। যাক যে কোনও কারণে, আমি size()2345-এ শুরু করতে চাই না ।

উদাহরণস্বরূপ, লিনাক্সে (g ++ 4.4.5, কার্নেল 2.6.32 amd64)

#include <iostream>
#include <vector>

int main()
{
  using namespace std;
  cout << vector<int>().capacity() << "," << vector<int>(10).capacity() << endl;
  return 0;
}

মুদ্রিত 0,10। এটি কি কোনও নিয়ম, না এটি এসটিএল বিক্রেতার উপর নির্ভরশীল?


7
স্ট্যান্ডার্ড ভেক্টরের প্রাথমিক ক্ষমতা সম্পর্কে কিছু নির্দিষ্ট করে না তবে বেশিরভাগ বাস্তবায়ন 0 ব্যবহার করে।
মিঃ আনুবিস

11
কোনও গ্যারান্টি নেই, তবে আমি কোনও অনুরোধ ছাড়াই মেমরি বরাদ্দকৃত এমন কোনও বাস্তবায়নের গুণমানকে গুরুত্ব সহকারে প্রশ্ন করব।
মাইক সিমুর

4
@ মাইকসিমুর মতবিরোধ সত্যই উচ্চ কার্যকারিতা বাস্তবায়নে একটি ছোট ইনলাইন বাফার থাকতে পারে, সেক্ষেত্রে প্রাথমিক ক্ষমতাকে () সেট করা অর্থপূর্ণ হবে।
অ্যালিস্টায়ার

6
@ অ্যালেস্টায়ার swapসমস্ত পুনরুক্তিকারী এবং রেফারেন্স ব্যবহার করার সময় বৈধ থাকে ( end()গুলি ব্যতীত )। তার মানে একটি ইনলাইন বাফার সম্ভব নয়।
নোটলিস্ট

উত্তর:


74

মানকটি ধারকটির প্রারম্ভিকটি কী capacityহওয়া উচিত তা নির্দিষ্ট করে না , তাই আপনি বাস্তবায়নের উপর নির্ভর করছেন। একটি সাধারণ বাস্তবায়ন ক্ষমতা শূন্য থেকে শুরু করবে, তবে এর কোনও গ্যারান্টি নেই। অন্যদিকে আপনার কৌশলটি এর std::vector<int> iv; iv.reserve(2345);সাথে আটকে থাকার আরও ভাল উপায় নেই ।


4
আমি আপনার শেষ বিবৃতি কিনতে না। আপনি যদি প্রাথমিকভাবে 0 টির ক্ষমতার উপর নির্ভর করতে না পারেন তবে আপনার ভেক্টরকে প্রাথমিক আকারের অনুমতি দেওয়ার জন্য আপনি আপনার প্রোগ্রামটি পুনর্গঠন করতে পারেন। এটি হিপ-মেমরি অনুরোধের অর্ধেক সংখ্যার (2 থেকে 1 অবধি) করবে।
বিটমাস্ক

4
@ বিটমাস্ক: ব্যবহারিক হওয়া: আপনি কোনও প্রয়োগের কথা জানেন যেখানে কোনও ভেক্টর ডিফল্ট কনস্ট্রাক্টরে মেমরি বরাদ্দ করে? এটি স্ট্যান্ডার্ড দ্বারা গ্যারান্টিযুক্ত নয়, তবে মাইক সিউমর বিনা প্রয়োজনে বরাদ্দকে ট্রিগার করা বাস্তবায়নের গুণমান সম্পর্কে দুর্গন্ধযুক্ত বলে মনে করেন ।
ডেভিড রদ্রিগেজ - ড্রিবিস

4
@ ডেভিডরডগ্রিজেজ-ড্রিবিয়াস: এটি মূল বিষয় নয়। এর ভিত্তিটি ছিল "আপনি আপনার বর্তমান কৌশলের চেয়ে ভাল করতে পারবেন না, তাই বোকা বাস্তবায়ন হতে পারে কিনা তা ভেবে উদ্বিগ্ন হবেন না "। যদি এই ভিত্তিটি হয় "এরকম কোনও বাস্তবায়ন নেই, তাই বিরক্ত করবেন না" আমি এটি কিনে ফেলতাম। উপসংহারটি সত্য বলে মনে হয় তবে জড়িত কাজ করে না। দুঃখিত, সম্ভবত আমি বাছাই করছি।
বিটমাস্ক

4
@ বিটমাস্ক যদি এমন কোনও বাস্তবায়ন উপস্থিত থাকে যা ডিফল্ট নির্মাণে মেমরি বরাদ্দ করে, আপনি যা বলেছেন তা করলে বরাদ্দ সংখ্যা অর্ধেক হয়ে যায়। তবে vector::reserveপ্রাথমিক আকার উল্লেখ করার মতো নয়। ভেক্টর কনস্ট্রাক্টর যারা প্রাথমিক আকারের মান / অনুলিপি nবস্তুগুলিকে আরম্ভ করে এবং এভাবে লিনিয়ার জটিলতা থাকে। ওটিওএইচ, রিজার্ভকে কল করার অর্থ হ'ল যদি পুনর্বিবেচনা শুরু হয় তবেsize() উপাদানগুলির অনুলিপি / চলন। খালি ভেক্টরে কপি করার কিছুই নেই। সুতরাং বাস্তবায়ন ডিফল্ট নির্মিত ভেক্টরের জন্য মেমরির বরাদ্দ দিলেও পরবর্তীকালে কাঙ্ক্ষিত হতে পারে।
প্রিটোরিয়ান

4
@ বিটমাস্ক, যদি আপনি এই ডিগ্রিতে বরাদ্দ সম্পর্কে উদ্বিগ্ন হন তবে আপনার নির্দিষ্ট স্ট্যান্ডার্ড গ্রন্থাগারের বাস্তবায়নটি দেখে নেওয়া উচিত এবং অনুমানের উপর নির্ভর করা উচিত নয়।
মার্ক মুক্তি পেতে

36

স্ট্যান্ড :: ভেক্টরের স্টোরেজ বাস্তবায়ন উল্লেখযোগ্যভাবে পরিবর্তিত হয় তবে আমি যে সমস্তগুলি 0 থেকে শুরু করেছি।

নিম্নলিখিত কোড:

#include <iostream>
#include <vector>

int main()
{
  using namespace std;

  vector<int> normal;
  cout << normal.capacity() << endl;

  for (unsigned int loop = 0; loop != 10; ++loop)
  {
      normal.push_back(1);
      cout << normal.capacity() << endl;
  }

  cin.get();
  return 0;
}

নিম্নলিখিত আউটপুট দেয়:

0
1
2
4
4
8
8
8
8
16
16

জিসিসি 5.1 এর অধীনে এবং:

0
1
2
3
4
6
6
9
9
9
13

এমএসভিসি 2013 এর অধীনে।


4
এটি @ অ্যান্ড্রু
ভ্যালেন্টিন মার্সিয়ের

ভাল আপনি কার্যত সর্বত্র খুঁজে পাবেন যে গতির উদ্দেশ্যে প্রস্তাবনাটি প্রায়শই কেবল একটি ভেক্টর ব্যবহার করা হয়, তাই আপনি যদি অল্প ডেটার সাথে যুক্ত এমন কোনও কিছু করেন ...
অ্যান্ড্রু

@ অ্যান্ড্রু কি তাদের এটি শুরু করা উচিত ছিল? যদি প্রোগ্রামার ডিফল্টর চেয়ে বেশি রিজার্ভ করতে চায় তবে কিছু বরাদ্দ করা ঠিক সেই সময়টি বরাদ্দ করা এবং সেই মেমোরিটিকে অপসারণ করা। যদি আপনি ধরে নিচ্ছেন যে তাদের 1 দিয়ে শুরু করা উচিত, তবে যে কেউ যেভাবে যাইহোক 1 বরাদ্দ করার সাথে সাথে এটি বরাদ্দ হয়ে যাবে।
পুডল

@ পুডল আপনি মুখের মূল্যে না নেওয়ার পরিবর্তে লাইনগুলির মধ্যে পড়ছেন। এটি যে কৌতুকপূর্ণ নয় সে ক্লুটি হ'ল "স্মার্ট" শব্দটি, সাথে সাথে আমার দ্বিতীয় মন্তব্যটি স্পার্স ডেটা উল্লেখ করে।
অ্যান্ড্রু

@ অ্যান্ড্রু ওহ ভাল, আপনি যথেষ্ট পরিমাণে স্বস্তি পেয়েছিলেন তারা এটিকে ০.০৫ এ শুরু করেছিলেন কেন এমনকি এটি নিয়ে মজা করার মতো মন্তব্য কেন?
পুডল

7

যতদূর আমি স্ট্যান্ডার্ডটি বুঝতে পেরেছি (যদিও আমি আসলে কোনও রেফারেন্সের নাম দিতে পারি না), ধারক তাত্পর্য এবং মেমরির বরাদ্দটি ভাল কারণে ইচ্ছাকৃতভাবে decoupled হয়েছে। তার জন্য আপনার স্বতন্ত্র, পৃথক কলগুলির জন্য

  • constructor পাত্রে নিজে তৈরি করতে
  • reserve() কমপক্ষে (!) প্রদত্ত কয়েকটি সংখ্যক অবজেক্টের জন্য উপযুক্ত বৃহত মেমরি ব্লক বরাদ্দ করতে

এবং এটি অনেক অর্থবোধ করে। এর জন্য বিদ্যমান থাকার একমাত্র অধিকার reserve()হ'ল ভেক্টর বাড়ানোর সময় আপনাকে সম্ভবত ব্যয়বহুল পুনর্নির্দেশগুলির চারপাশে কোড করার সুযোগ দেওয়া। দরকারী হওয়ার জন্য আপনাকে কী পরিমাণ জিনিস সংরক্ষণ করতে হবে তা জানতে হবে বা কমপক্ষে একটি শিক্ষিত অনুমান করতে সক্ষম হতে হবে। এটি যদি আপনাকে দেওয়া না হয় তবে আরও ভাল থেকে দূরে থাকুনreserve() যেহেতু আপনি কেবল নষ্ট মেমরির জন্য পুনঃস্থাপন পরিবর্তন করবেন।

সুতরাং সব একত্রিত:

  • মান ইচ্ছাকৃতভাবে না কোনও কনস্ট্রাক্টর নির্দিষ্ট যা আপনাকে নির্দিষ্ট সংখ্যক অবজেক্টের জন্য মেমরি ব্লক বরাদ্দ দেওয়ার অনুমতি দেয় (যা হুডের নীচে একটি নির্দিষ্ট নির্দিষ্ট কিছু নির্দিষ্টকরণ বরাদ্দ করার চেয়ে কমপক্ষে আরও আকাঙ্ক্ষিত হবে)।
  • বরাদ্দ অন্তর্ভুক্ত করা উচিত নয়। সুতরাং, একটি ব্লককে পূর্বনির্ধারণ করতে আপনাকে পৃথক কল করতে হবেreserve() হবে এবং এটি একই স্থানে নির্মাণের প্রয়োজন হবে না (অবশ্যই পরে থাকার দরকার ছিল, পরে আপনি প্রয়োজনীয় আকার সম্পর্কে অবগত হওয়ার পরে)
  • সুতরাং যদি কোনও ভেক্টর সর্বদা বাস্তবায়িত সংজ্ঞায়িত আকারের একটি মেমরি ব্লককে পূর্বনির্ধারণ করে রাখে তবে এটি এর উদ্দেশ্যযুক্ত কাজটি বানচাল করে reserve()দেবে, তাই না?
  • যদি এসটিএল প্রাকৃতিকভাবে কোনও ভেক্টরের উদ্দিষ্ট উদ্দেশ্য এবং প্রত্যাশিত আকারটি না জানতে পারে তবে কোনও ব্লকটি প্রাক-প্রচারের কী সুবিধা হবে? পাল্টা-উত্পাদনশীল না হলে এটি অযৌক্তিক হবে।
  • পরিবর্তে যথাযথ সমাধানটি হ'ল প্রথমটির সাথে নির্দিষ্ট ব্লকটি বরাদ্দকরণ এবং বাস্তবায়ন করা push_back() - যদি ইতিমধ্যে স্পষ্টভাবে আগে বরাদ্দ না দেওয়া হয়reserve()
  • প্রয়োজনীয় পুনঃনির্ধারণের ক্ষেত্রে ব্লকের আকারের বৃদ্ধি এছাড়াও নির্দিষ্টকরণ বাস্তবায়ন। ভেক্টর বাস্তবায়নগুলি আমি আকারের তাত্পর্যপূর্ণ বৃদ্ধি দিয়ে শুরু করে জানি তবে বিপুল পরিমাণ স্মৃতি অপচয় করতে বা এমনকি এটির ব্লোয়িং এড়ানোর জন্য বর্ধিত হারকে একটি নির্দিষ্ট সর্বোচ্চে ক্যাপচার করবে।

বরাদ্দকারী কন্সট্রাক্টর দ্বারা বিরক্ত না হলে এই সমস্তগুলি সম্পূর্ণ অপারেশন এবং সুবিধার জন্য আসে। আপনার কাছে সাধারণ পরিস্থিতিগুলির জন্য যুক্তিসঙ্গত ডিফল্ট রয়েছে যা reserve()(এবং shrink_to_fit()) দ্বারা চাহিদা অনুসারে ওভাররাইড করা যেতে পারে । সুতরাং, এমনকি যদি স্ট্যান্ডার্ডটি স্পষ্টভাবে বর্ণিত না হয় তবে আমি নিশ্চিতভাবেই ধরে নিচ্ছি যে একটি সদ্য নির্মিত ভেক্টর প্রাকলোকট করে না বর্তমান সমস্ত বাস্তবায়নগুলির জন্য এটি একটি নিরাপদ বাজি।


4

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

বিশেষত যদি _ITERATOR_DEBUG_LEVEL! = 0 হয় তবে ভেক্টর পুনরুক্তি পরীক্ষার জন্য সহায়তা করার জন্য কিছু জায়গা বরাদ্দ করবে।

https://docs.microsoft.com/en-gb/cpp/standard-library/iterator-debug-level

আমি এই সামান্য বিরক্তিকর পেলাম যেহেতু আমি তখন কাস্টম বরাদ্দকারী ব্যবহার করছিলাম এবং অতিরিক্ত বরাদ্দ আশা করছিলাম না।


আকর্ষণীয়, তারা ভঙ্গ noexcept-গ্যারান্টী (সি + 17, আগের জন্য অন্তত?): En.cppreference.com/w/cpp/container/vector/vector
Deduplicator

4

এটি একটি পুরানো প্রশ্ন, এবং এখানে সমস্ত উত্তর সঠিকভাবে স্ট্যান্ডার্ডের দৃষ্টিভঙ্গি এবং যেভাবে আপনি বহনযোগ্য পদ্ধতিতে প্রাথমিক সামর্থ্যটি ব্যবহার করে ব্যবহার করতে পারবেন তা ব্যাখ্যা করেছে std::vector::reserve;

যাইহোক, আমি ব্যাখ্যা করব যে কোনও এসটিএল বাস্তবায়নের জন্য কোনও std::vector<T>বস্তু নির্মাণের পরে মেমরি বরাদ্দ করা কেন তা বিবেচ্য নয় ;

  1. std::vector<T> অসম্পূর্ণ প্রকারের;

    সি ++ 17 এর আগে , ইনস্ট্যান্টেশনের সময়ে std::vector<T>যদি সংজ্ঞাটি Tএখনও অজানা থাকে তবে এটি নির্মাণ করা অপরিজ্ঞাত আচরণ ছিল । তবে, এই বাধাটি C ++ 17 এ শিথিল করা হয়েছিল

    কোনও জিনিসের জন্য দক্ষতার সাথে মেমরির বরাদ্দ করতে আপনাকে তার আকারটি জানতে হবে। সি ++ 17 এবং এর বাইরে, আপনার ক্লায়েন্টের এমন কেস থাকতে পারে যেখানে আপনার std::vector<T>ক্লাসের আকার জানেন না T। টাইপ সম্পূর্ণতার উপর নির্ভর করে মেমরি বরাদ্দ বৈশিষ্ট্যগুলি কী বোঝায়?

  2. Unwanted Memory allocations

    অনেকগুলি, অনেকগুলি, অনেক সময় আপনার সফ্টওয়্যারটিতে একটি গ্রাফের মডেল প্রয়োজন। (একটি গাছ একটি গ্রাফ); আপনি সম্ভবত এটির মতো মডেল করতে যাচ্ছেন:

    class Node {
        ....
        std::vector<Node> children; //or std::vector< *some pointer type* > children;
        ....
     };
    

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

    এটি কেবল একটি উদাহরণ, আরও বেশি কিছু ভাবতে নির্দ্বিধায় ...


2

স্ট্যান্ডার্ড সামর্থ্যের জন্য প্রাথমিক মান নির্দিষ্ট করে না তবে এসটিএল কনটেইনার স্বয়ংক্রিয়ভাবে আপনি যতটা ডেটা রাখেন তত পরিমাণে বাড়ানোর জন্য বৃদ্ধি পায়, আপনি যদি সর্বোচ্চ আকার অতিক্রম না করেন (তবে জানার জন্য ম্যাক্স_সাইজ সদস্য ফাংশনটি ব্যবহার করুন)। ভেক্টর এবং স্ট্রিংয়ের জন্য, যখনই আরও স্থানের প্রয়োজন হয় তখন রিলোক দ্বারা বৃদ্ধি পরিচালনা করা হয়। মনে করুন আপনি ভেক্টর হোল্ডিং মান 1-1000 তৈরি করতে চান। রিজার্ভ ব্যবহার না করে, কোডটি সাধারণত নিম্নলিখিত লুপের সময় 2 এবং 18 এর মধ্যে পুনঃনির্ধারণের ফলাফল দেয়:

vector<int> v;
for ( int i = 1; i <= 1000; i++) v.push_back(i);

রিজার্ভ ব্যবহারের জন্য কোডটি সংশোধন করার ফলে লুপের সময় 0 টি বরাদ্দ হতে পারে:

vector<int> v;
v.reserve(1000);

for ( int i = 1; i <= 1000; i++) v.push_back(i);

মোটামুটিভাবে বলতে গেলে, ভেক্টর এবং স্ট্রিং ক্যাপাসিটিগুলি প্রতিবার 1.5 থেকে 2 এর মধ্যে একটি ফ্যাক্টর দ্বারা বৃদ্ধি পায়।

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