সূচক ভেরিয়েবলের ধরণ নির্বাচন করা


11

আমরা বেশিরভাগ সময়ে ইন্টিজার টাইপ উপস্থাপন করে সূচক ভেরিয়েবল ব্যবহার করি। তবে কিছু পরিস্থিতিতে আমরা বাছাই করতে বাধ্য হই

std::vector<int> vec;
....

for(int i = 0; i < vec.size(); ++i)
....

এটি সংকলক স্বাক্ষরিত / স্বাক্ষরযুক্ত ভেরিয়েবলগুলির মিশ্র ব্যবহারের সতর্কতাটি বাড়িয়ে তুলবে। যদি আমি সূচকটিকে পরিবর্তনশীল হিসাবে তৈরি করি for( size_t i = 0; i < vec.size(); i++ ), (বা একটি unsigned int) এটি সমস্যার সমাধান করবে out

উইন্ডোজের ধরণগুলি ব্যবহার করার ক্ষেত্রে এটি আরও নির্দিষ্ট হয়ে গেলে, বেশিরভাগ উইন্ডোজ এপিআইগুলি ডিডাবর্ড (যা স্বাক্ষরবিহীন দীর্ঘ হিসাবে টাইপডেফ-এড) নিয়ে কাজ করে।

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

DWORD dwCount;
....

for(DWORD i = 0; i < dwCount; ++i)
....

আমি এটি কিছুটা অদ্ভুত বলে মনে করি। উপলব্ধি হ'ল সমস্যা হতে পারে।

আমি সম্মত হই যে সূচিপত্রের ভেরিয়েবলগুলির সাথে পরিসীমা সমস্যা হতে পারে এড়াতে আমাদের একই ধরণের সূচক ভেরিয়েবল ব্যবহার করার কথা are যেমন আমরা যদি ব্যবহার করছি

_int64 i64Count; // 
....

for(_int64 i = 0; i < i64Count; ++i)
....

তবে ডিডাবর্ড, বা স্বাক্ষরবিহীন পূর্ণসংখ্যার ক্ষেত্রে এটি পুনরায় লেখার ক্ষেত্রে কোনও সমস্যা আছে

for(int i = 0; (size_t)i < vec.size(); ++i)

কীভাবে বেশিরভাগ মানুষ একই রকম সমস্যা নিয়ে কাজ করছেন?


4
আপনি সূচকে উপস্থাপন করতে স্বাক্ষরিত পূর্ণসংখ্যা কেন ব্যবহার করবেন? এটি একটি স্ট্রিং সঞ্চয় করতে পূর্ণসংখ্যার ভেক্টর ব্যবহার করার মতো।
আইমন

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

"এটি সংকলক স্বাক্ষরিত / স্বাক্ষরযুক্ত ভেরিয়েবলগুলির মিশ্র ব্যবহারের সতর্কতা বাড়িয়ে তুলবে" " আপনাকে যে দুটি সমস্যার মুখোমুখি হতে হবে তার মধ্যে এটি কেবল একটি । অনেক ক্ষেত্রে ইন std::size_t(বা এমনকি দীর্ঘ) এর চেয়ে উচ্চতর পদ থাকে। যদি ভেক্টরের আকার কখনই অতিক্রম করে std::numeric_limits<int>::max(), আপনি আন্তঃব্যবহার ব্যবহার করে অনুশোচনা করবেন।
অ্যাড্রিয়ান ম্যাকার্থি

উত্তর:


11

ভেক্টরের একটি টাইপিডেফ রয়েছে যা আপনাকে সঠিক টাইপটি ব্যবহারের জন্য বলে:

for(std::vector<int>::size_type i = 0; i < thing.size(); ++i)
{
}

এটি প্রায় সর্বদা আকার_ত হিসাবে সংজ্ঞায়িত হলেও আপনি তার উপর নির্ভর করতে পারবেন না


8
পাঠযোগ্যতার কোনও উন্নতি আসলেই নয়, আইএমএইচও।
ডক ব্রাউন

না, তবে ভেক্টরটিতে কোনও সূচকের জন্য সঠিক প্রকারটি কী তা বলার একমাত্র উপায়, এটি সত্যিই গুরুত্বপূর্ণ নয় ...
জনবি

4
সি ++ এ এই দিনগুলিতে কেবল অটো ব্যবহার করুন
জনবি

6
@ জনবি আপনার পছন্দ মত auto i = 0? এটি কিছুতেই সহায়তা করে না, iহয়ে ওঠে int
জেনিথ

1
পাঠযোগ্যতা উন্নত করা যেতে পারে, সঙ্গে using index_t = std::vector<int>::size_type;
টবি স্পিড

4
std::vector<int> vec;

for(int i = 0; i < vec.size(); ++i)

এর জন্য একটি পুনরুক্তি ব্যবহার করুন, forলুপ নয়।

অন্যদের জন্য, যতদিন পরিবর্তনশীল টাইপ একই আকারের হয়, static_castঠিক সূক্ষ্ম কাজ করা উচিত (অর্থাত DWORDকরার int16_t)


2
for (std::vector<int>::iterator i = vec.begin(); i != vec.end(); ++i)লিখতে ব্যথা is থাকা for (auto i = vec.begin();...অনেক বেশি পাঠযোগ্য able অবশ্যই, foreachসি ++ 11 এও রয়েছে।
ডেভিড থর্নলে

3

আপনি বর্ণিত কেসটি আমি সি ++ এও অপছন্দ করি of তবে আমি তা ব্যবহার করে বাঁচতে শিখেছি

for( size_t i = 0; i < vec.size(); i++ )

অথবা

for( int i = 0; i < (int)vec.size(); i++ )

(অবশ্যই, পরে যখন কেবল কিছুটা ওভারফ্লো হওয়ার ঝুঁকি থাকে না)।


3

স্বাক্ষরিত এবং স্বাক্ষরযুক্তের মধ্যে তুলনা সম্পর্কে এটি আপনাকে সতর্ক করার কারণ হ'ল স্বাক্ষরিত মানটি স্বাক্ষরিততে রূপান্তরিত হবে, যা আপনার প্রত্যাশা মতো নাও হতে পারে।

আপনার উদাহরণে (তুলনা intকরা size_t), intসুস্পষ্টভাবে রূপান্তরিত হবে size_t(যদি না intকোনওরকমের চেয়ে আরও বড় পরিসর থাকে size_t)। সুতরাং, যদি এটি intনেতিবাচক হয় তবে এটি মোড়কের কারণে তুলনামূলকভাবে তুলনা করা মানের চেয়ে বেশি হবে। আপনার সূচকটি কখনও নেতিবাচক না থাকলে এটি কোনও সমস্যা হবে না তবে আপনি এখনও সেই সতর্কতা পাবেন।

পরিবর্তে, একটি স্বাক্ষরবিহীন টাইপ (যেমন হিসাবে ব্যবহার unsigned int, size_t, অথবা, জন বি বিশেষ পরামর্শ দেওয়া হচ্ছে , std::vector<int>::size_typeআপনার সূচক পরিবর্তনশীল জন্য):

for(unsigned int i = 0; i < vec.size(); i++)

গণনা করার সময় সতর্ক থাকুন, যদিও:

for(unsigned int i = vec.size()-1; i >= 0; i--) // don't do this!

উপরেরগুলি কাজ করবে না কারণ স্বাক্ষরবিহীন থাকা i >= 0অবস্থায় সর্বদা সত্য i। পরিবর্তে, গণনা করা লুপগুলির জন্য " তীর অপারেটর " ব্যবহার করুন:

for (unsigned int i = vec.size(); i-- > 0; )
    vec[i] = ...;

অন্যান্য উত্তরগুলি নির্দেশ করে, আপনি সাধারণত একটিকে ট্র্যাভার করতে একটি পুনরুক্তি ব্যবহার করতে চান vector। এখানে সি ++ 11 বাক্য গঠন রয়েছে:

for (auto i = vec.begin(); i != vec.end(); ++i)

1
এটি এখনও এই ঝুঁকিটি চালায় যে unsigned intআকার ধারণের পক্ষে যথেষ্ট বড় নয়।
অ্যাড্রিয়ান ম্যাকার্থি

2

সি ++ 11 এর জন্য একটি নতুন বিকল্প, আপনি নীচের মতো জিনিসগুলি করতে পারেন

for(decltype(vec.size()) i = 0; i < vec.size(); ++i) {...}

এবং

for(decltype(dWord) i = 0; i < dWord; ++i) {...}

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

int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)

তবুও, autoযখনই আপনি iকিছু বুদ্ধিমান মান (যেমন vec.begin()) তে সেট করেন তখন আপনার ব্যবহার করা উচিত, যখন আপনি decltypeশূন্যের মতো ধ্রুবক স্থাপন করছেন তখন কাজ করে যেখানে অটো কেবল এটি সমাধান করবে intকারণ 0 একটি সাধারণ পূর্ণসংখ্যার আক্ষরিক।

সত্যি কথা বলতে, আমি autoলুপ ইনক্রিমেন্টারগুলির সাথে তুলনা করা মানটি দেখার জন্য টাইপ- সংকল্পটি বাড়ানোর জন্য একটি সংকলক প্রক্রিয়া দেখতে চাই ।


1

আমি অন্তর্ভুক্ত হিসাবে একটি কাস্ট ব্যবহার করি for (int i = 0; i < (int)v.size(); ++i)। হ্যাঁ, এটি কুরুচিপূর্ণ। আমি এটি স্ট্যান্ডার্ড লাইব্রেরির বোকা নকশার জন্য দোষ দিচ্ছি যেখানে তারা মাপের প্রতিনিধিত্ব করতে স্বাক্ষরবিহীন পূর্ণসংখ্যা ব্যবহার করার সিদ্ধান্ত নিয়েছে। (যাতে .. কি? পরিধিটি এক বিট বাড়িয়ে দিতে হবে?)


1
কোন পরিস্থিতিতে নেতিবাচক কিছু সংগ্রহের আকারটি অর্থবহ হবে? বিভিন্ন সংগ্রহের আকারের জন্য স্বাক্ষরযুক্ত ইন্টিজার ব্যবহার করা আমার কাছে বোধগম্য পছন্দ মতো মনে হয়। শেষ আমি পরীক্ষা করেছিলাম, একটি স্ট্রিংয়ের দৈর্ঘ্য নেওয়ার কারণে খুব কমই নেতিবাচক ফলাফল ফিরে আসে ...
সিভিএন

1
কোন পরিস্থিতিতে যেমন if(v.size()-1 > 0) { ... }খালি পাত্রে সত্য ফিরে আসার মতো সাধারণ পরীক্ষার জন্য এটি অর্থবহ হবে ? সমস্যাটি হ'ল মাপগুলিও প্রায়শই অঙ্কগুলিতে ব্যবহৃত হয়, এসএসপি। সূচক-ভিত্তিক পাত্রে, যা স্বাক্ষরবিহীন থাকায় সমস্যা জিজ্ঞাসা করছে। মূলত, 1) বিটওয়াইজ ম্যানিপুলেশন ব্যতীত অন্য যে কোনও কিছুর জন্য স্বাক্ষরবিহীন প্রকারগুলি ব্যবহার করা বা 2) মডিউলার গাণিতিক সমস্যার জন্য ডাকে।
zvrba

2
ভাল যুক্তি. যদিও আমি সত্যিই আপনার নির্দিষ্ট উদাহরণটির বিন্দুটি দেখতে পাচ্ছি না (সম্ভবত আমি কেবল এটি লিখব if(v.size() > 1) { ... }যেহেতু এটি অভিপ্রায়টি আরও স্পষ্ট করে তোলে, এবং একটি অতিরিক্ত বোনাস হিসাবে স্বাক্ষরিত / স্বাক্ষরযুক্ত ইস্যুটি বাতিল হয়ে যায়), আমি কিছু নির্দিষ্ট ক্ষেত্রে কীভাবে দেখছি স্বাক্ষর দরকারী হতে পারে। আমি সংশোধন করেছি.
একটি সিভিএন

1
@ মিশেল: আমি সম্মত হলাম এটি একটি নিখুঁত উদাহরণ ছিল। তবুও, আমি প্রায়শই নেস্টেড লুপগুলি সহ অ্যালগরিদমগুলি লিখি: (i = 0; i <v.size () - 1; ++ i) এর জন্য (j = i + 1; j <v.size (); ++ জে) .. যদি ভি খালি থাকে তবে বাইরের লুপটি (আকার_ টি) -1 বার চালায়। সুতরাং আমাকে একটি স্বাক্ষরিত ধরণের লুপের আগে v.empty () পরীক্ষা করতে হবে বা v.size () নিক্ষেপ করতে হবে, যার উভয়ই আমি ব্যক্তিগতভাবে কুৎসিত কাজ বলে মনে করি। আমি কাস্টটিকে এটি কম এলওসি হিসাবে বেছে নেব, ভুলের জন্য যদি () গুলি => কম সংখ্যক সম্ভাবনা কম হয় no (এছাড়াও, দ্বিতীয় পরিপূরক হিসাবে, রূপান্তর ওভারফ্লো একটি নেতিবাচক সংখ্যা প্রদান করে, যাতে লুপটি কার্যকর হয় না))
zvrba

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