এর মধ্যে পার্থক্য শুরু করা যাক দেখে বনাম কন্টেইনারে উপাদান পরিবর্তন তাদের জায়গায়।
উপাদান পর্যবেক্ষণ
আসুন একটি সহজ উদাহরণ বিবেচনা করুন:
vector<int> v = {1, 3, 5, 7, 9};
for (auto x : v)
cout << x << ' ';
উপরের কোডটিতে উপাদানগুলি int
গুলি প্রিন্ট করে vector
:
1 3 5 7 9
এখন অন্য একটি ক্ষেত্রে বিবেচনা করুন, যাতে ভেক্টর উপাদানগুলি কেবল সাধারণ পূর্ণসংখ্যারই নয়, কাস্টম অনুলিপি নির্মাণকারী সহ আরও জটিল শ্রেণির উদাহরণ etc.
// A sample test class, with custom copy semantics.
class X
{
public:
X()
: m_data(0)
{}
X(int data)
: m_data(data)
{}
~X()
{}
X(const X& other)
: m_data(other.m_data)
{ cout << "X copy ctor.\n"; }
X& operator=(const X& other)
{
m_data = other.m_data;
cout << "X copy assign.\n";
return *this;
}
int Get() const
{
return m_data;
}
private:
int m_data;
};
ostream& operator<<(ostream& os, const X& x)
{
os << x.Get();
return os;
}
যদি আমরা for (auto x : v) {...}
এই নতুন শ্রেণীর সাথে উপরের সিনট্যাক্সটি ব্যবহার করি :
vector<X> v = {1, 3, 5, 7, 9};
cout << "\nElements:\n";
for (auto x : v)
{
cout << x << ' ';
}
আউটপুট যেমন কিছু হয়:
[... copy constructor calls for vector<X> initialization ...]
Elements:
X copy ctor.
1 X copy ctor.
3 X copy ctor.
5 X copy ctor.
7 X copy ctor.
9
এটি আউটপুট থেকে পড়তে পারা যায়, লুপ পুনরাবৃত্তির জন্য পরিসর-ভিত্তিক অনুলিপি কন্সট্রাক্টর কল করা হয়।
এটি হ'ল কারণ আমরা ধারক থেকে উপাদানগুলি মান দ্বারা ক্যাপচার করছি
theauto x
অংশে for (auto x : v)
) ।
এটি অকার্যকর কোড, উদাহরণস্বরূপ, যদি এই উপাদানগুলির উদাহরণ std::string
থাকে তবে মেমরি পরিচালকের কাছে ব্যয়বহুল ট্রিপ সহ হিপ মেমরির বরাদ্দ করা যেতে পারে This পালন একটি কন্টেইনারে উপাদান।
সুতরাং, একটি আরও ভাল বাক্য গঠন উপলব্ধ: রেফারেন্স দ্বারাconst
ক্যাপচার , অর্থাত const auto&
:
vector<X> v = {1, 3, 5, 7, 9};
cout << "\nElements:\n";
for (const auto& x : v)
{
cout << x << ' ';
}
এখন আউটপুট হল:
[... copy constructor calls for vector<X> initialization ...]
Elements:
1 3 5 7 9
কোনও উত্সাহী (এবং সম্ভাব্য ব্যয়বহুল) কপি নির্মাণকারী কল ছাড়াই।
সুতরাং যখন দেখে একটি ধারক (অর্থাত, কেবলমাত্র পাঠ্য অ্যাক্সেস জন্য) উপাদান, নিম্নলিখিত সিনট্যাক্স সহজ জন্য ভালো সস্তা টু কপি ধরনের, মত int
, double
ইত্যাদি .:
for (auto elem : container)
অন্যথায়, অনর্থক (এবং সম্ভাব্য ব্যয়বহুল) অনুলিপি নির্মাণকারী কল এড়াতে সাধারণ ক্ষেত্রেconst
রেফারেন্স দ্বারা ক্যাপচার করা ভাল :
for (const auto& elem : container)
পাত্রে উপাদানগুলি সংশোধন করা হচ্ছে
আমরা যদি পরিসীমা ভিত্তিক ব্যবহার করে একটি
ধারকগুলিতে উপাদানগুলি সংশোধন করতে চাই for
তবে উপরের for (auto elem : container)
এবং for (const auto& elem : container)
বাক্য গঠনগুলি ভুল।
প্রকৃতপক্ষে, পূর্ববর্তী ক্ষেত্রে, মূল উপাদানটির elem
একটি অনুলিপি সংরক্ষণ করে, সুতরাং এটি করা পরিবর্তনগুলি কেবল হারিয়ে যায় এবং ধারকটিতে অবিচ্ছিন্নভাবে সংরক্ষণ করা হয় না, যেমন:
vector<int> v = {1, 3, 5, 7, 9};
for (auto x : v) // <-- capture by value (copy)
x *= 10; // <-- a local temporary copy ("x") is modified,
// *not* the original vector element.
for (auto x : v)
cout << x << ' ';
আউটপুট কেবল প্রাথমিক ক্রম:
1 3 5 7 9
পরিবর্তে, for (const auto& x : v)
কেবল ব্যবহারের একটি প্রচেষ্টা সংকলন করতে ব্যর্থ।
g ++ একটি ত্রুটি বার্তাকে এরকম কিছু দেয়:
TestRangeFor.cpp:138:11: error: assignment of read-only reference 'x'
x *= 10;
^
এই ক্ষেত্রে সঠিক পদ্ধতির const
উল্লেখ ছাড়াই ক্যাপচার করা হয় :
vector<int> v = {1, 3, 5, 7, 9};
for (auto& x : v)
x *= 10;
for (auto x : v)
cout << x << ' ';
আউটপুটটি (আশানুরূপ হিসাবে):
10 30 50 70 90
এই for (auto& elem : container)
বাক্য গঠন আরও জটিল ধরণের জন্য যেমন কাজ করে vector<string>
:
vector<string> v = {"Bob", "Jeff", "Connie"};
// Modify elements in place: use "auto &"
for (auto& x : v)
x = "Hi " + x + "!";
// Output elements (*observing* --> use "const auto&")
for (const auto& x : v)
cout << x << ' ';
আউটপুটটি হ'ল:
Hi Bob! Hi Jeff! Hi Connie!
প্রক্সি পুনরাবৃত্তিকারীদের বিশেষ কেস
ধরা যাক আমাদের একটি আছে vector<bool>
এবং আমরা উপরের সিনট্যাক্সটি ব্যবহার করে এর উপাদানগুলির লজিক্যাল বুলিয়ান রাষ্ট্রটিকে উল্টাতে চাই:
vector<bool> v = {true, false, false, true};
for (auto& x : v)
x = !x;
উপরের কোডটি সংকলন করতে ব্যর্থ।
g ++ এর অনুরূপ একটি ত্রুটি বার্তা আউটপুট করে:
TestRangeFor.cpp:168:20: error: invalid initialization of non-const reference of
type 'std::_Bit_reference&' from an rvalue of type 'std::_Bit_iterator::referen
ce {aka std::_Bit_reference}'
for (auto& x : v)
^
সমস্যা হল std::vector
টেমপ্লেট বিশেষ জন্য bool
একটি বাস্তবায়ন যে সঙ্গে, প্যাকগুলিbool
অপ্টিমাইজ স্থান থেকে গুলি (প্রতিটি বুলিয়ান মান এক বিট, একটি বাইট আট "বুলিয়ান" বিট মধ্যে সংরক্ষিত হয়)।
এর কারণে (যেহেতু এটি কোনও একক রেফারেন্স ফেরানো সম্ভব নয়),
vector<bool>
তথাকথিত "প্রক্সি পুনরুত্থক" প্যাটার্ন ব্যবহার করে। একটি "প্রক্সি পুনরুত্থক" এমন একটি পুনরাবৃত্তি যা পুনঃনির্ধারণ করা হলে একটি সাধারণ ফল দেয় নাbool &
, পরিবর্তে (মান অনুসারে) একটি অস্থায়ী বস্তু দেয় , যা প্রক্সি শ্রেণিতে রূপান্তরযোগ্যbool
। ( এই প্রশ্ন এবং সম্পর্কিত উত্তরগুলিও দেখুন স্ট্যাকওভারফ্লোতেও দেখুন))
এর উপাদানগুলিকে পরিবর্তিত করতে vector<bool>
, নতুন ধরণের সিনট্যাক্স (ব্যবহার auto&&
) অবশ্যই ব্যবহার করা উচিত:
for (auto&& x : v)
x = !x;
নিম্নলিখিত কোডটি সূক্ষ্মভাবে কাজ করে:
vector<bool> v = {true, false, false, true};
// Invert boolean status
for (auto&& x : v) // <-- note use of "auto&&" for proxy iterators
x = !x;
// Print new element values
cout << boolalpha;
for (const auto& x : v)
cout << x << ' ';
এবং ফলাফল:
false true true false
নোট করুন যে for (auto&& elem : container)
বাক্য গঠনটি সাধারণ (নন-প্রক্সি) পুনরাবৃত্তির অন্যান্য ক্ষেত্রেও কাজ করে (উদাহরণস্বরূপ এ vector<int>
বা এ এর জন্য)vector<string>
)।
(পার্শ্ব নোট হিসাবে, for (const auto& elem : container)
প্রক্সি পুনরাবৃত্তকারী ক্ষেত্রেও পূর্বোক্ত "পর্যবেক্ষণ" সিনট্যাক্সগুলি সূক্ষ্মভাবে কাজ করে))
সারসংক্ষেপ
উপরোক্ত আলোচনাটি নিম্নলিখিত নির্দেশিকাগুলিতে সংক্ষিপ্ত করা যেতে পারে:
জন্য নিরীক্ষক উপাদান, নিম্নলিখিত সিনট্যাক্স ব্যবহার করুন:
for (const auto& elem : container) // capture by const reference
যদি বিষয়গুলি অনুলিপি করার জন্য সস্তা হয় (যেমন int
গুলি, double
গুলি ইত্যাদি) তবে কিছুটা সরলীকৃত ফর্ম ব্যবহার করা সম্ভব:
for (auto elem : container) // capture by value
স্থানে থাকা উপাদানগুলিকে সংশোধন করার জন্য , ব্যবহার করুন:
for (auto& elem : container) // capture by (non-const) reference
যদি ধারকটি "প্রক্সি পুনরুক্তি"std::vector<bool>
ব্যবহার করে (যেমন ), তবে ব্যবহার করুন:
for (auto&& elem : container) // capture by &&
অবশ্যই, যদি একটি করতে একটি প্রয়োজন নেই স্থানীয় অনুলিপি ক্যাপচার লুপ শরীর ভিতরে উপাদান, মান ( for (auto elem : container)
) একটি ভাল পছন্দ।
জেনেরিক কোডে অতিরিক্ত নোট
ইন জেনেরিক কোড , যেহেতু আমরা জেনেরিক টাইপ সম্পর্কে অনুমানের করতে পারবেন না T
কপি সস্তা হচ্ছে, এ দেখে মোড এটা সবসময় ব্যবহার করা নিরাপদ for (const auto& elem : container)
।
(এটি সম্ভাব্য ব্যয়বহুল অনর্থক অনুলিপিগুলি ট্রিগার করবে না, সস্তা-টু-কপি প্রকারের int
জন্য এবং প্রক্সি-পুনরায় ব্যবহারকারী পাত্রে যেমন , ঠিক তেমন কাজ করবেstd::vector<bool>
))
তদুপরি, সংশোধন মোডে, আমরা যদি প্রক্সি-পুনরুক্তির ক্ষেত্রে জেনেরিক কোডটি কাজ করতে চাই, তবে সর্বোত্তম বিকল্পটি for (auto&& elem : container)
।
(এই সাধারণ অ প্রক্সি-iterators ব্যবহার করে, মত পাত্রে জন্য শুধু জরিমানা এছাড়াও কাজ করবে std::vector<int>
বা std::vector<string>
।)
সুতরাং, জেনেরিক কোডে , নিম্নলিখিত নির্দেশিকাগুলি সরবরাহ করা যেতে পারে:
জন্য নিরীক্ষক উপাদান, ব্যবহার করুন:
for (const auto& elem : container)
স্থানে থাকা উপাদানগুলিকে সংশোধন করার জন্য , ব্যবহার করুন:
for (auto&& elem : container)