এটি দুর্দান্ত অনুশীলন।
লুপের ভিতরে ভেরিয়েবল তৈরি করে, আপনি নিশ্চিত করেন যে তাদের সুযোগটি লুপের অভ্যন্তরে সীমাবদ্ধ। এটি লুপের বাইরে রেফারেন্স করা বা কল করা যায় না।
এই পথে:
যদি ভেরিয়েবলের নামটি কিছুটা "জেনেরিক" হয় (যেমন "আই") হয় তবে আপনার কোডের পরে কোথাও এটি একই নামের অন্য ভেরিয়েবলের সাথে মিশ্রিত করার কোনও ঝুঁকি নেই (জিসিসিতে -Wshadow
সতর্কতা নির্দেশ ব্যবহার করে প্রশমিতও করা যেতে পারে )
সংকলক জানে যে ভেরিয়েবল স্কোপটি লুপের মধ্যেই সীমাবদ্ধ থাকে এবং ভেরিয়েবলটি অন্য কোথাও ভুল করে রেফারেন্স করা হলে সঠিক ত্রুটি বার্তা জারি করবে।
সর্বশেষে তবে সর্বনিম্ন নয়, কিছু উত্সর্গীকৃত অপ্টিমাইজেশন সংকলক (আরও গুরুত্বপূর্ণভাবে বরাদ্দ রেজিস্টার) দ্বারা আরও দক্ষতার সাথে সম্পাদন করতে পারে, কারণ এটি জানে যে লুপের বাইরে চলকটি ব্যবহার করা যায় না। উদাহরণস্বরূপ, পরে পুনরায় ব্যবহারের জন্য ফলাফল সংরক্ষণ করার দরকার নেই।
সংক্ষেপে, আপনি এটি করা ঠিক।
তবে নোট করুন যে ভেরিয়েবলের প্রতিটি লুপের মধ্যে তার মান ধরে রাখার কথা নয় । এই ক্ষেত্রে, আপনার এটি প্রতিবারই শুরু করার প্রয়োজন হতে পারে। আপনি লুপকে ঘিরে আরও একটি বৃহত ব্লক তৈরি করতে পারেন, যার একমাত্র উদ্দেশ্য ভেরিয়েবলগুলি ঘোষণা করা যা তাদের মানটি একটি লুপ থেকে অন্য লুপ ধরে রাখতে হবে। এটি সাধারণত লুপ কাউন্টার নিজেই অন্তর্ভুক্ত।
{
int i, retainValue;
for (i=0; i<N; i++)
{
int tmpValue;
/* tmpValue is uninitialized */
/* retainValue still has its previous value from previous loop */
/* Do some stuff here */
}
/* Here, retainValue is still valid; tmpValue no longer */
}
# 2 প্রশ্নের জন্য: ফাংশনটি ডাকা হলে একবার ভেরিয়েবল বরাদ্দ করা হয়। আসলে, বরাদ্দের দৃষ্টিকোণ থেকে, এটি (প্রায়) ফাংশনের শুরুতে ভেরিয়েবল ঘোষণার মতোই। পার্থক্যটি কেবলমাত্র সুযোগ: ভেরিয়েবলটি লুপের বাইরে ব্যবহার করা যায় না। এমনকি এটি সম্ভব হতে পারে যে ভেরিয়েবল বরাদ্দ করা হয়নি, কেবল কিছু ফ্রি স্লট পুনরায় ব্যবহার করুন (অন্যান্য ভেরিয়েবল থেকে যার স্কোপ শেষ হয়েছে)।
সীমাবদ্ধ এবং আরও সুনির্দিষ্ট সুযোগ নিয়ে আরও সঠিক অপ্টিমাইজেশন আসে। তবে আরও গুরুত্বপূর্ণ বিষয়, কোডের অন্যান্য অংশগুলি পড়ার সময় চিন্তা করা আপনার কম কোড (যেমন ভেরিয়েবল) সহ আপনার কোডটিকে আরও সুরক্ষিত করে।
এটি কোনও if(){...}
ব্লকের বাইরেও সত্য । সাধারণত, পরিবর্তে:
int result;
(...)
result = f1();
if (result) then { (...) }
(...)
result = f2();
if (result) then { (...) }
এটি লিখতে নিরাপদ:
(...)
{
int const result = f1();
if (result) then { (...) }
}
(...)
{
int const result = f2();
if (result) then { (...) }
}
পার্থক্যটি সামান্য মনে হতে পারে, বিশেষত এরকম একটি ছোট উদাহরণের ক্ষেত্রে। কিন্তু একটি বৃহত্তর কোড বেস উপর, এটা সাহায্য করবে: এখন কিছু পরিবহন কোন ঝুঁকি result
থেকে মান f1()
থেকে f2()
ব্লক। প্রত্যেকে result
কঠোরভাবে তার নিজস্ব ক্ষেত্রের মধ্যে সীমাবদ্ধ, এর ভূমিকাটিকে আরও নির্ভুল করে তোলে। একটি পর্যালোচক দৃষ্টিকোণ থেকে, এটি অনেক সুন্দর, যেহেতু চিন্তাভাবনা এবং ট্র্যাক করার জন্য তার কাছে দীর্ঘ পরিসীমা রাষ্ট্রীয় ভেরিয়েবল রয়েছে ।
এমনকি সংকলকটি আরও ভালভাবে সহায়তা করবে: ধরে নিচ্ছি ভবিষ্যতে কোডের কিছু ভ্রান্ত পরিবর্তনের পরে, result
সঠিকভাবে শুরু করা হয়নি f2()
। দ্বিতীয় সংস্করণটি সহজেই কাজ করতে অস্বীকার করবে, সংকলনের সময় একটি পরিষ্কার ত্রুটি বার্তাটি জানিয়েছে (রান টাইমের চেয়ে ভাল উপায়)। প্রথম সংস্করণে কোনও কিছু পাওয়া যাবে না f1()
, ফলাফলটির জন্য বিভ্রান্ত হয়ে দ্বিতীয়বারের ফলাফলটি সহজভাবে পরীক্ষা করা হবে f2()
।
পরিপূরক তথ্য
ওপেন-সোর্স সরঞ্জাম CppCheck (সি / সি ++ কোডের জন্য একটি স্ট্যাটিক বিশ্লেষণ সরঞ্জাম) ভেরিয়েবলের অনুকূল সুযোগ সম্পর্কে কিছু দুর্দান্ত ইঙ্গিত সরবরাহ করে।
বরাদ্দের বিষয়ে মন্তব্যের জবাবে: উপরের নিয়মটি সিটিতে সত্য, তবে কিছু সি ++ শ্রেণির জন্য নাও হতে পারে।
স্ট্যান্ডার্ড ধরণের এবং কাঠামোর জন্য, ভেরিয়েবলের আকার সংকলন সময়ে জানা যায়। সি তে "কনস্ট্রাকশন" বলে কোনও জিনিস নেই, সুতরাং ভেরিয়েবলের জন্য স্থানটি কেবল স্ট্যাকের মধ্যে বরাদ্দ করা হবে (কোনও প্রারম্ভিককরণ ছাড়াই), যখন ফাংশনটি বলা হয়। লুপের অভ্যন্তরে ভেরিয়েবল ঘোষণার সময় একটি "শূন্য" ব্যয় হয়।
তবে সি ++ ক্লাসের জন্য এই কনস্ট্রাক্টর জিনিসটি রয়েছে যা সম্পর্কে আমি খুব কম জানি। আমার ধারণা, বরাদ্দ সম্ভবত সমস্যা হতে পারে না, যেহেতু সংকলক একই স্থানটি পুনরায় ব্যবহার করার জন্য যথেষ্ট চালাক হবে, তবে প্রতিটি লুপের পুনরাবৃত্তিতে প্রাথমিককরণের সম্ভাবনা রয়েছে।