কেন স্ট্যান্ডার্ড ইটারেটর রেঞ্জগুলি [শুরু, শেষ] এর পরিবর্তে [শুরু, শেষ) হয়?


204

কেন স্ট্যান্ডার্ডটি end()প্রকৃত প্রান্তের পরিবর্তে শেষের মতো হিসাবে সংজ্ঞায়িত হয়?


19
আমি অনুমান করছি "কারণ এটি যা বলে স্ট্যান্ডার্ড" এটি কাটবে না, তাইনা? :)
লুচিয়ান গ্রিগোর

39
@ লুচিয়ানগ্রিগোর: অবশ্যই না। এটি (পিছনে থাকা লোকদের) মানদের প্রতি আমাদের শ্রদ্ধা নষ্ট করবে। আমাদের প্রত্যাশা করা উচিত যে স্ট্যান্ডার্ড দ্বারা করা পছন্দগুলির একটি কারণ আছে ।
কেরেক এসবি

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

8
"শেষ এক" উত্পন্ন করার একমাত্র উপায় থাকার কারণে এটি প্রায়শই সস্তা হয় না কারণ এটি আসল হতে হয়। "আপনি ক্লিফের শেষের দিকে পড়ে গিয়েছিলেন" উত্পন্ন করা সর্বদা সস্তা, অনেকগুলি সম্ভাব্য উপস্থাপনা এটি করবে। (অকার্যকর *) "আহহ্হ্হহ" ভাল করবে।
হ্যানস প্যাস্যান্ট

6
আমি প্রশ্নের তারিখের দিকে তাকিয়েছিলাম এবং সেখানে এক সেকেন্ডের জন্য আমি ভেবেছিলাম আপনি মজা করছেন।
আসফ

উত্তর:


286

সহজেই সর্বোত্তম যুক্তি হ'ল ডিজকস্ট্রা নিজে তৈরি করেছিলেন :

  • আপনি সীমাটির আকারটি একটি সাধারণ পার্থক্য সমাপ্ত হতে চান  -  শুরু করুন ;

  • নিম্ন সীমা সহ আরও "প্রাকৃতিক" যখন সিক্যুয়েন্সগুলি শূন্যগুলিতে অবনমিত হয়, এবং বিকল্পটি ( নিম্ন সীমাটি বাদ দিয়ে) একটি "এক-পূর্ব-শুরু" সেন্ডিনেল মানটির অস্তিত্ব প্রয়োজন।

আপনি এখনও একের চেয়ে শূন্যে কেন গণনা শুরু করলেন তা আপনাকে ন্যায়সঙ্গত করতে হবে, তবে এটি আপনার প্রশ্নের অংশ ছিল না।

[শুরু, শেষ) কনভেনশনের পিছনে বুদ্ধি সময় এবং আবার সময় দেয় যখন আপনার কোনও ধরণের অ্যালগরিদম থাকে যা একাধিক নেস্টেড বা পুনরাবৃত্তিযুক্ত কলগুলির সাথে পরিসীমা ভিত্তিক নির্মাণগুলিতে ডিল করে, যা প্রাকৃতিকভাবে শৃঙ্খলাবদ্ধ। বিপরীতে, দ্বিগুণ-বদ্ধ পরিসীমা ব্যবহার করে অফ-বাই-ওড এবং চূড়ান্ত অপ্রীতিকর এবং শোরগোলের কোড আসতে পারে। উদাহরণস্বরূপ, একটি পার্টিশন বিবেচনা করুন [ n 0 , n 1 ) [ n 1 , n 2 ) [ n 2 , n 3 )। আর একটি উদাহরণ স্ট্যান্ডার্ড পুনরাবৃত্তি লুপ for (it = begin; it != end; ++it), যা end - beginবার চালায় । উভয় প্রান্তটি অন্তর্ভুক্ত থাকলে সংশ্লিষ্ট কোডটি খুব কম পঠনযোগ্য হবে - এবং কীভাবে খালি রেঞ্জগুলি পরিচালনা করবেন তা কল্পনা করুন।

পরিশেষে, আমরা একটি দুর্দান্ত যুক্তিও করতে পারি কেন গণনা শূন্য থেকে শুরু হওয়া উচিত: আমরা সবেমাত্র প্রতিষ্ঠিত রেঞ্জগুলির অর্ধ-খোলা কনভেনশন সহ, যদি আপনাকে এন এন উপাদানগুলির একটি পরিসর দেওয়া হয় (কোন অ্যারের সদস্যদের গণনা করতে বলুন), তবে 0 হ'ল প্রাকৃতিক "সূচনা" যাতে আপনি কোনও বিশ্রী অফসেট বা সংশোধন না করে [0, N ) হিসাবে পরিসরটি লিখতে পারেন ।

সংক্ষেপে: সত্য যে আমরা 1পরিসর ভিত্তিক অ্যালগরিদমগুলিতে কোথাও সংখ্যাটি দেখতে পাই না , এটি [শুরু, শেষ) সম্মেলনের প্রত্যক্ষ ফলাফল এবং প্রেরণা।


2
N এর আকারের অ্যারে ধরে লুপের পুনরাবৃত্তির জন্য সাধারণ সি হ'ল "(i = 0; i <N; i ++) a [i] = 0;"। এখন, আপনি এটি পুনরাবৃত্তকারীদের সাথে সরাসরি প্রকাশ করতে পারবেন না - অনেক লোক <অর্থবহ তৈরি করার চেষ্টা করে সময় নষ্ট করে। তবে এটি "প্রায় (i = 0; i! = N; i ++) বলা প্রায় সমানই স্পষ্ট is" 0 টি শুরু করার জন্য ম্যাপিং এবং এন শেষ হতে তাই সুবিধাজনক।
ক্রেজি গ্লিউ

3
@ ক্রজিগ্লিউ: আমি আমার লুপের উদাহরণটি ইচ্ছাকৃতভাবে রাখিনি। আপনি মনে করেন beginএবং endযেমন intমান গুলি 0এবং Nযথাক্রমে, এটা পুরোপুরি ফিট। যুক্তিযুক্তভাবে, এটি এমন !=শর্ত যা প্রচলিত than ষধের চেয়ে প্রাকৃতিক <, তবে আমরা আরও সাধারণ সংগ্রহ সম্পর্কে চিন্তা না করা অবধি এটি কখনই আবিষ্কার করতে পারি নি।
কেরেক এসবি 20

4
@ কেরেকএসবি: আমি সম্মত হই যে "যতক্ষণ না আমরা আরও সাধারণ সংগ্রহের বিষয়ে চিন্তা শুরু করি" আমরা কখনই এটি আবিষ্কার করি নি [[= = আরও ভাল]] " স্টিপানোভ যে সমস্ত বিষয়গুলির জন্য ক্রেডিট প্রাপ্য সেগুলির মধ্যে আইএমএইচও - এসটিএলের আগে এই জাতীয় টেম্পলেট লাইব্রেরি লেখার চেষ্টা করেছিলেন এমন ব্যক্তি হিসাবে কথা বলা। তবে, আমি "! =" আরও প্রাকৃতিক হওয়া সম্পর্কে তর্ক করব - বা বরং, আমি তর্ক করব যে! = সম্ভবত বাগগুলি প্রবর্তন করেছে, এটি <ধরাতে পারে। (I = 0; i! = 100; i + = 3) ... এর জন্য চিন্তা করুন ...
ক্রেজি গ্লিউ

@ ক্রজিগ্লিউ: আপনার শেষ পয়েন্টটি কিছুটা অফ-টপিকের, যেহেতু OP 0, 3, 6, ..., 99 the ক্রমটি ওপি যে রূপের বিষয়ে জিজ্ঞাসা করেছিল তা নয়। আপনি যদি এটি ++এমনটি হতে চান তবে আপনার উচিত একটি বিস্ময়কর পুনরুদ্ধার টেম্পলেট step_by<3>, যা এরপরে মূলত বিজ্ঞাপনীকৃত শব্দার্থবিজ্ঞান লেখা উচিত।
কেরেক এসবি

@ ক্রজিগ্লিউ এমনকি <এক সময় কোনও বাগ লুকিয়ে রাখলেও, এটি যাইহোক একটি বাগ । যদি কেউ ব্যবহার করে !=তার ব্যবহার করা হয় <, তবে এটি একটি বাগ। যাইহোক, ত্রুটির সেই রাজা ইউনিট পরীক্ষা বা দৃ or়তার সাথে সন্ধান করা সহজ।
ফিল 1970

80

আসলে, পুনরুক্তিকারীর সংশ্লিষ্ট কাপড় অনেকটা হঠাৎ যদি আপনি iterators প্রতি নির্দেশ না বিবেচনা অনেক বেশি জ্ঞান করে তোলে ক্রম উপাদান কিন্তু মাঝে এটি পরবর্তী উপাদান অধিকার অ্যাক্সেস dereferencing সঙ্গে। তারপরে "এক অতীত প্রান্ত" পুনরুক্তিকারী হঠাৎ করে তাত্ক্ষণিকভাবে তাৎপর্য দেয়:

   +---+---+---+---+
   | A | B | C | D |
   +---+---+---+---+
   ^               ^
   |               |
 begin            end

স্পষ্টতই beginসিকোয়েন্সের শুরুতে নির্দেশ করে এবং endএকই ক্রমের শেষ দিকে নির্দেশ করে। ডিফেরেন্সিং beginউপাদানটি অ্যাক্সেস করে Aএবং ডেরেফারেন্সিং এর endকোনও অর্থ হয় না কারণ এর সাথে কোনও উপাদান নেই right এছাড়াও, iমাঝখানে একটি পুনরাবৃত্তি যুক্ত করে দেয়

   +---+---+---+---+
   | A | B | C | D |
   +---+---+---+---+
   ^       ^       ^
   |       |       |
 begin     i      end

এবং আপনি অবিলম্বে দেখতে যে থেকে উপাদানগুলি পরিসীমা beginথেকে iউপাদানগুলি রয়েছে Aএবং Bথেকে উপাদানগুলি পরিসীমা যখন iথেকে endউপাদানগুলি রয়েছে Cএবং D। ডেরেফারেন্সিং iউপাদানটিকে ডান দেয়, এটি দ্বিতীয় অনুক্রমের প্রথম উপাদান।

এমনকি বিপরীত পুনরাবৃত্তকারীদের জন্য "অফ-বাই-ওয়ান" হঠাৎ করে সেইভাবে সুস্পষ্ট হয়ে ওঠে: সেই ক্রমটিকে বিপরীত করে দেয়:

   +---+---+---+---+
   | D | C | B | A |
   +---+---+---+---+
   ^       ^       ^
   |       |       |
rbegin     ri     rend
 (end)    (i)   (begin)

আমি নীচে বন্ধনীতে সংশ্লিষ্ট অ-বিপরীত (বেস) পুনরাবৃত্তিগুলি লিখেছি। আপনি দেখুন, বিপরীত পুনরুক্তিযুক্ত i(যা আমি নাম দিয়েছি ri) এখনও উপাদান Bএবং এর মধ্যে পয়েন্ট করে C। তবে ক্রমটি উল্টে যাওয়ার কারণে এখন উপাদানটি Bএর ডানদিকে রয়েছে।


2
এটি আইএমএইচওই সেরা উত্তর, যদিও আমি মনে করি যদি এটির সংখ্যাগুলি নির্দেশ করে এবং উপাদানগুলি সংখ্যার (সিনট্যাক্স foo[i]) অবধি অবস্থানের পরে আইটেমটির জন্য একটি সংক্ষিপ্ত বিবরণ হয় তবে এটি আরও ভাল চিত্রিত হতে পারে i। এটি সম্পর্কে ভাবতে ভাবতে আমি অবাক হয়েছি যে "ভাষার পরে আইটেমের পরে" এবং "আইটেমের ঠিক আগে" আইটেমের জন্য আলাদা অপারেটর ব্যবহার করা কোনও ভাষার পক্ষে কার্যকর হতে পারে, যেহেতু প্রচুর অ্যালগরিদম সংলগ্ন আইটেমের জোড়া নিয়ে কাজ করে এবং বলে " আই "এর উভয় পাশের আইটেমগুলি" আইটেমের আই এবং আই +1 "এর চেয়ে পরিষ্কার হতে পারে।
সুপারক্যাট

@ সুপের্যাট: সংখ্যাগুলি পুনরাবৃত্তকারী অবস্থান / সূচকগুলি নির্দেশ করার কথা ছিল না, তবে উপাদানগুলিকে নিজেরাই নির্দেশ করবে। আমি আরও পরিষ্কার করার জন্য সংখ্যার সাথে চিঠিগুলি প্রতিস্থাপন করব। প্রকৃতপক্ষে, প্রদত্ত সংখ্যাগুলির সাথে, begin[0](একটি এলোমেলো অ্যাক্সেস পুনরুদ্ধারকারী ধরে নেওয়া) উপাদানটি অ্যাক্সেস করতে পারে 1, যেহেতু 0আমার উদাহরণ ক্রমের কোনও উপাদান নেই ।
celtschk

"সূচনা" না দিয়ে "শুরু" শব্দটি কেন ব্যবহৃত হয়? সর্বোপরি, "শুরু" একটি ক্রিয়াপদ।
ব্যবহারকারী1741137

@ ব্যবহারকারী1741137 আমি মনে করি "শুরু" বলতে "সূচনা" (যা এখন বোঝা যায়) এর সংক্ষেপণ হিসাবে বোঝানো হয়েছে। "শুরু" খুব দীর্ঘ হওয়া, "শুরু" খুব সুন্দর লাগছে। "স্টার্ট" ক্রিয়াপদ "স্টার্ট" এর সাথে সাংঘর্ষিক হবে (উদাহরণস্বরূপ যখন start()নির্দিষ্ট শ্রেণীর কোনও প্রক্রিয়া শুরু করার জন্য আপনাকে যখন আপনার ক্লাসে কোনও ক্রিয়াকলাপটি নির্ধারণ করতে হয় বা যাই হোক না কেন, এটি যদি ইতিমধ্যে বিদ্যমান কোনওের সাথে দ্বন্দ্ব হয় তবে তা বিরক্তিকর হবে)।
ফারিয়ানোর

74

কেন স্ট্যান্ডার্ডটি end()প্রকৃত প্রান্তের পরিবর্তে শেষের মতো হিসাবে সংজ্ঞায়িত হয়?

কারণ:

  1. এটি খালি রেঞ্জের জন্য বিশেষ পরিচালনা পরিচালনা এড়িয়ে চলে। খালি ব্যাপ্তির জন্য, begin()সমান end()এবং
  2. এটি লুপগুলির জন্য শেষ মাপদণ্ডকে সহজ করে তোলে যা উপাদানগুলির উপর পুনরাবৃত্তি করে: লুপগুলি কেবল যতক্ষণ end()না পৌঁছে যায় ততক্ষণ চালিয়ে যায় ।

64

কারণ তখন

size() == end() - begin()   // For iterators for whom subtraction is valid

এবং আপনার মতো বিশ্রী জিনিসগুলি করতে হবে না

// Never mind that this is INVALID for input iterators...
bool empty() { return begin() == end() + 1; }

এবং আপনি দুর্ঘটনাক্রমে ভুল কোড পছন্দ করবেন না

bool empty() { return begin() == end() - 1; }    // a typo from the first version
                                                 // of this post
                                                 // (see, it really is confusing)

bool empty() { return end() - begin() == -1; }   // Signed/unsigned mismatch
// Plus the fact that subtracting is also invalid for many iterators

এছাড়াও: কোনও বৈধ উপাদানকে নির্দেশ করলে কী find()ফিরে আসবে end()?
আপনি কি সত্যিই অন্য একজন সদস্য হিসাবে পরিচিত চান invalid()যা একজন অবৈধ পুনরাবৃত্তিকে ফেরত দেয় ?!
দুটি পুনরুক্তিকারী ইতিমধ্যে যথেষ্ট বেদনাদায়ক ...

ওহ, এবং দেখতে এই সংশ্লিষ্ট পোস্টে


এছাড়াও:

যদি endশেষ উপাদানটির আগে ছিল, তবে আপনি কীভাবে আসবেন insert()?!


2
এটি একটি উচ্চ আন্ডাররেটেড উত্তর। উদাহরণগুলি সংক্ষিপ্ত এবং সোজাসুজি বক্তব্য, এবং "এছাড়াও" গুলি অন্য কারও দ্বারা বলা হয়নি এবং এটি এমন এক ধরণের জিনিস যা পশ্চাদপসরণে খুব সুস্পষ্ট বলে মনে হয় তবে আমাকে প্রকাশের মতো আঘাত করে।
আন্ডারস্কোর_

@ মাউন্ডসর_ডি: ধন্যবাদ !! :)
user541686

বিটিডব্লিউ, ক্ষেত্রে যদি আমি উত্সাহ না দেওয়ার জন্য ভণ্ডামির মতো মনে হয়, কারণ আমি ইতিমধ্যে জুলাই ২০১ 2016 সালে ফিরে এসেছি!
আন্ডারস্কোর_

@ মাউন্ডস_ডি: হাহাহা আমি খেয়ালও করিনি, তবে ধন্যবাদ! :)
user541686

22

অর্ধ-বদ্ধ রেঞ্জগুলির পুনরাবৃত্তি আইডিয়াম [begin(), end())মূলত প্লেইন অ্যারেগুলির জন্য পয়েন্টার গাণিতিকের উপর ভিত্তি করে। অপারেশনের সেই মোডে আপনার ফাংশনগুলি হবে যা একটি অ্যারে এবং একটি আকার পেরিয়ে গেছে।

void func(int* array, size_t size)

অর্ধ-বদ্ধ রেঞ্জগুলিতে রূপান্তর করা [begin, end)খুব সহজ যখন আপনার কাছে সেই তথ্য থাকে:

int* begin;
int* end = array + size;

for (int* it = begin; it < end; ++it) { ... }

সম্পূর্ণ-বদ্ধ রেঞ্জগুলির সাথে কাজ করা, এটি আরও শক্ত:

int* begin;
int* end = array + size - 1;

for (int* it = begin; it <= end; ++it) { ... }

যেহেতু অ্যারেগুলিতে নির্দেশকগুলি সি ++ এ পুনরাবৃত্ত হয় (এবং সিনট্যাক্স এটির অনুমতি দেওয়ার জন্য ডিজাইন করা হয়েছিল), কল করার std::find(array, array + size, some_value)চেয়ে এটি কল করা আরও সহজ std::find(array, array + size - 1, some_value)


এছাড়াও, আপনি যদি অর্ধ-বন্ধ রেঞ্জগুলির সাথে কাজ করেন তবে আপনি !=অপারেটরটি শেষ শর্তটি পরীক্ষা করতে পারবেন, কারণ (যদি আপনার অপারেটরগুলি সঠিকভাবে সংজ্ঞায়িত করা হয়) তবে <বোঝা যায় !=

for (int* it = begin; it != end; ++ it) { ... }

তবে সম্পূর্ণরূপে বন্ধ রেঞ্জগুলির সাথে এটি করার সহজ উপায় নেই। তোমার সাথে আটকে আছি করছি <=

একমাত্র ধরণের পুনরাবৃত্তি যা সি ++ এ সমর্থন করে <এবং >ক্রিয়াকলাপগুলি এলোমেলো-অ্যাক্সেস পুনরুক্তি হয়। যদি আপনাকে <=সি ++ তে প্রতিটি পুনরুক্তি ক্লাসের জন্য অপারেটর লিখতে হয় , আপনাকে আপনার সমস্ত পুনরুক্তিদাতা সম্পূর্ণরূপে তুলনামূলক করে তুলতে হবে এবং আপনি কম সক্ষম পুনরাবৃত্তকারী তৈরি করতে (যেমন দ্বিদ্বিদী পুনরুদ্ধারকারী std::listবা ইনপুট পুনরাবৃত্তকারী) তৈরি করার জন্য আপনার পছন্দ কম ছিল কাজ যে iostreams) যদি সি ++ সম্পূর্ণ বদ্ধ রেঞ্জ ব্যবহৃত।


8

সঙ্গে end()শেষ অতীত ইশারা এক, এটা লুপ জন্য একটি সঙ্গে একটি সংগ্রহ পুনরুক্তি করতে সহজ:

for (iterator it = collection.begin(); it != collection.end(); it++)
{
    DoStuff(*it);
}

end()শেষ উপাদানটির দিকে ইঙ্গিত করার সাথে সাথে একটি লুপ আরও জটিল হবে:

iterator it = collection.begin();
while (!collection.empty())
{
    DoStuff(*it);

    if (it == collection.end())
        break;

    it++;
}

0
  1. যদি একটি ধারক খালি থাকে begin() == end(),।
  2. সি ++ প্রোগ্রামাররা লুপ অবস্থাতে (এর চেয়ে কম) !=পরিবর্তে ব্যবহার করার প্রবণতা রাখে <, সুতরাং end()পজিশনের সমাপ্তি একটি অবস্থানের দিকে ইশারা করা সুবিধাজনক।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.