অন্যরা যেমন বলেছে, সমস্যাটি goto
নিজেই নয়; সমস্যা কীভাবে লোকেরা ব্যবহার করে goto
এবং কীভাবে এটি কোড বোঝা ও বজায় রাখা আরও শক্ত করে তুলতে পারে তা নিয়েই সমস্যা।
নিম্নলিখিত কোড স্নিপেট অনুমান:
i = 4;
label: printf( "%d\n", i );
কি মান জন্য মুদ্রিত হয় i
? এটি কখন ছাপা হয়? যতক্ষণ না আপনি নিজের ফাংশনটির প্রতিটি উদাহরণের জন্য অ্যাকাউন্ট করেন goto label
, আপনি জানতে পারবেন না। সেই লেবেল সহজ উপস্থিতি ধ্বংস সহজ পরিদর্শন দ্বারা ডিবাগ কোড আপনার ক্ষমতা। এক বা দুটি শাখা সহ ছোট ফাংশনগুলির জন্য, খুব বেশি সমস্যা নয়। ছোট-ছোট ফাংশনের জন্য ...
'90 এর দশকের গোড়ার দিকে ফিরে আসার পথে আমাদের কাছে সি কোডের একটি গাদা দেওয়া হয়েছিল যা 3 ডি গ্রাফিকাল ডিসপ্লে চালিত করে এবং এটিকে দ্রুত চালিত করতে বলে। এটি কোডের প্রায় 5000 লাইন ছিল তবে এটি সমস্তই ছিল main
এবং লেখক goto
উভয় দিকেই প্রায় 15 বা এর বেশি শাখা ব্যবহার করেছিলেন। এটি দিয়ে শুরু করা খারাপ কোড ছিল , তবে তাদের উপস্থিতি goto
এটিকে আরও খারাপ করে তুলেছে। নিয়ন্ত্রণ প্রবাহ ধাঁধাতে আমার সহকর্মীকে প্রায় 2 সপ্তাহ সময় লেগেছে। আরও ভাল, সেগুলির goto
ফলাফলের ফলে কোডটি নিজের সাথে এত দৃ with়ভাবে মিলিত হয়েছিল যে আমরা কিছু ভঙ্গ না করে কোনও পরিবর্তন করতে পারি না ।
আমরা স্তর 1 অপ্টিমাইজেশনের সাথে সংকলনের চেষ্টা করেছি, এবং সংকলকটি সমস্ত উপলব্ধ র্যাম, তারপরে সমস্ত উপলভ্য অদলবদল খেয়ে goto
ফেলেছে এবং তারপরে সিস্টেমটিকে আতঙ্কিত করেছে (যার সম্ভবত তাদের নিজস্ব কোনও সম্পর্ক ছিল না , তবে আমি সেই উপাখ্যানটি বাইরে ফেলে দিতে চাই)।
শেষ পর্যন্ত, আমরা গ্রাহককে দুটি বিকল্প দিয়েছিলাম - আসুন আমরা স্ক্র্যাচ থেকে পুরো জিনিসটি আবার লিখি, বা দ্রুত হার্ডওয়্যার কিনি।
তারা দ্রুত হার্ডওয়্যার কিনেছিল।
ব্যবহারের জন্য বোডের নিয়ম goto
:
- কেবল শাখা এগিয়ে;
- বাইপাস নিয়ন্ত্রণ কাঠামো (অর্থাত, একটি শরীরের মধ্যে শাখায় বিভক্ত না না
if
বা for
বা while
বিবৃতি);
goto
নিয়ন্ত্রণ কাঠামোর জায়গায় ব্যবহার করবেন না
সেখানে যখােন হয় goto
হয় সঠিক উত্তর, কিন্তু তারা বিরল (ক গভীরভাবে নেস্টেড লুপ খুঁজে ভঙ্গ সম্পর্কে একমাত্র জায়গা আমি এটা ব্যবহার চাই যায়)।
সম্পাদনা
এই শেষ বিবৃতিটি প্রসারিত করে, এখানে কয়েকটি বৈধ ব্যবহারের ক্ষেত্রে একটি goto
। ধরুন আমাদের নিম্নলিখিত ফাংশন রয়েছে:
T ***myalloc( size_t N, size_t M, size_t P )
{
size_t i, j, k;
T ***arr = malloc( sizeof *arr * N );
for ( i = 0; i < N; i ++ )
{
arr[i] = malloc( sizeof *arr[i] * M );
for ( j = 0; j < M; j++ )
{
arr[i][j] = malloc( sizeof *arr[i][j] * P );
for ( k = 0; k < P; k++ )
arr[i][j][k] = initial_value();
}
}
return arr;
}
এখন, আমাদের একটি সমস্যা আছে - যদি malloc
মাঝপথে কোনও কল কল ব্যর্থ হয়? সম্ভবত এটির মতো ঘটনাটি, আমরা আংশিক বরাদ্দকৃত অ্যারেটি ফিরিয়ে দিতে চাই না, বা ত্রুটিযুক্তভাবে আমরা কেবল ফাংশন থেকে জামিন দিতে চাই না; আমরা আমাদের পরে পরিষ্কার করতে এবং কোনও আংশিক বরাদ্দ মেমরি অপসারণ করতে চাই। যে ভাষায় একটি খারাপ বরাদ্দ ব্যতিক্রম ছুঁড়ে, এটি মোটামুটি সোজা - আপনি ইতিমধ্যে যা বরাদ্দ করা হয়েছে তা খালি করার জন্য কেবল ব্যতিক্রম হ্যান্ডলারটি লিখুন।
সি তে, আপনার কাঠামোগত ব্যতিক্রম হ্যান্ডলিং নেই; আপনাকে প্রতিটি malloc
কলের রিটার্ন মানটি পরীক্ষা করতে হবে এবং যথাযথ পদক্ষেপ নিতে হবে।
T ***myalloc( size_t N, size_t M, size_t P )
{
size_t i, j, k;
T ***arr = malloc( sizeof *arr * N );
if ( arr )
{
for ( i = 0; i < N; i ++ )
{
if ( !(arr[i] = malloc( sizeof *arr[i] * M )) )
goto cleanup_1;
for ( j = 0; j < M; j++ )
{
if ( !(arr[i][j] = malloc( sizeof *arr[i][j] * P )) )
goto cleanup_2;
for ( k = 0; k < P; k++ )
arr[i][j][k] = initial_value();
}
}
}
goto done;
cleanup_2:
// We failed while allocating arr[i][j]; clean up the previously allocated arr[i][j]
while ( j-- )
free( arr[i][j] );
free( arr[i] );
// fall through
cleanup_1:
// We failed while allocating arr[i]; free up all previously allocated arr[i][j]
while ( i-- )
{
for ( j = 0; j < M; j++ )
free( arr[i][j] );
free( arr[i] );
}
free( arr );
arr = NULL;
done:
return arr;
}
আমরা কি ব্যবহার না করে এটি করতে পারি goto
? অবশ্যই আমরা এটি করতে পারি - এটির জন্য কেবলমাত্র অতিরিক্ত অতিরিক্ত হিসাবরক্ষণের প্রয়োজন (এবং বাস্তবে, আমি যে পথটি গ্রহণ করব)। তবে, আপনি যদি এমন জায়গাগুলি সন্ধান করছেন যেখানে একটি অবিলম্বে ব্যবহার করা খারাপ অভ্যাস বা ডিজাইনের লক্ষণ goto
নয়, তবে কয়েকটিতে এটি একটি।