করণীয় (0) এড়ানোর আরও কিছু ভাল উপায় কী; সি ++ এ হ্যাক?


233

কোড প্রবাহ যখন এইরকম হয়:

if(check())
{
  ...
  ...
  if(check())
  {
    ...
    ...
    if(check())
    {
      ...
      ...
    }
  }
}

উপরের অগোছালো কোড প্রবাহ এড়াতে আমি সাধারণত এই কাজটি দেখেছি:

do {
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
} while(0);

এই কাজের আশপাশ / হ্যাক এড়ানোর জন্য আরও কিছু ভাল উপায় কী কী যাতে এটি একটি উচ্চ-স্তরের (শিল্প স্তরের) কোড হয়ে যায়?

বাক্সের বাইরে থাকা কোনও পরামর্শ স্বাগত!


38
RAII এবং নিক্ষেপ ব্যতিক্রম।
ta.speot.is

135
আমার কাছে, এটি ব্যবহারের জন্য ভাল সময় বলে মনে হচ্ছে goto- তবে আমি নিশ্চিত যে কেউ তাকে পরামর্শ দেওয়ার জন্য আমাকে চিহ্নিত করবে, তাই আমি সেই প্রভাবটির কোনও উত্তর লিখছি না। দীর্ঘায়িত do ... while(0);হওয়া ভুল জিনিস বলে মনে হচ্ছে।
ম্যাটস পিটারসন

42
@ ড্যাসব্লিংকনলাইট: হ্যাঁ, সত্যিই। আপনি যদি ব্যবহার করতে চলেছেন তবে gotoএটি সম্পর্কে সৎ হোন এবং এটি খোলামেলাভাবে করুন, ব্যবহার করে এটি আড়াল করবেন না breakএবংdo ... while
ম্যাটস পিটারসন

44
@ ম্যাটস পিটারসন: এটির উত্তর দিন, আমি আপনার gotoপুনর্বাসন প্রচেষ্টাতে আপনাকে +1 দেব । :)
উইলেক্স

27
@ ta.speot.is: "RAII এবং থ্রো ব্যতিক্রমগুলি"। এটি করে, আপনি ব্যতিক্রমগুলি সহ প্রবাহ নিয়ন্ত্রণ অনুকরণ করবেন। অর্থাত্ ব্যয়বহুল, রক্তপাতের প্রান্তের হার্ডওয়্যারকে হাতুড়ি বা পেপারওয়েট হিসাবে ব্যবহার করার মতো এটি। আপনি এটি করতে পারেন, তবে তা অবশ্যই আমার কাছে খুব খারাপ স্বাদের মতো দেখাচ্ছে।
সিগটর্ম

উত্তর:


309

কোনও সিদ্ধান্তে এই সিদ্ধান্তগুলি বিচ্ছিন্ন করা এবং returnএর পরিবর্তে গুলি ব্যবহার করা গ্রহণযোগ্য অনুশীলন হিসাবে বিবেচিত হয় break। এই সমস্ত চেক ফাংশন হিসাবে বিমূর্ততার একই স্তরের সাথে সামঞ্জস্য করা হলেও এটি বেশ যৌক্তিক পদ্ধতির।

উদাহরণ স্বরূপ:

void foo(...)
{
   if (!condition)
   {
      return;
   }
   ...
   if (!other condition)
   {
      return;
   }
   ...
   if (!another condition)
   {
      return;
   }
   ... 
   if (!yet another condition)
   {
      return;
   }
   ...
   // Some unconditional stuff       
}

22
@ ম্যাটস পিটারসন: "বিচ্ছিন্নভাবে ফাংশন" এর অর্থ একটি নতুন ফাংশনে রিফ্যাক্টরিং যা কেবল পরীক্ষা করে।
এমসাল্টারস

35
+1 টি। এটি একটি ভাল উত্তর। সি ++ ১১-এ, বিচ্ছিন্ন ফাংশনটি ল্যাম্বডা হতে পারে, কারণ এটি স্থানীয় ভেরিয়েবলগুলিও ক্যাপচার করতে পারে, তাই জিনিসগুলি সহজ করে তোলে!
নওয়াজ

4
@ ডেওয়ার্ড: পরিস্থিতির উপর নির্ভর করে এই সমাধানটি গোটোয়ের চেয়ে অনেক বেশি দীর্ঘ এবং কম পঠনযোগ্য হতে পারে। কারণ C ++, দুর্ভাগ্যবশত, স্থানীয় ফাংশন সংজ্ঞাগুলি মঞ্জুরি দেয় না, আপনাকে সেই ফাংশনটি (যার কাছ থেকে আপনি ফিরে আসবেন) অন্য কোথাও সরিয়ে নিতে হবে, যা পাঠযোগ্যতা হ্রাস করে। এটি কয়েক ডজন প্যারামিটারের সাথে শেষ হতে পারে, কারণ কয়েক ডজন পরামিতি থাকা একটি খারাপ জিনিস, আপনি সেগুলি কাঠামোর মধ্যে আবদ্ধ করার সিদ্ধান্ত নেবেন যা নতুন ডেটা টাইপ তৈরি করবে। সাধারণ পরিস্থিতির জন্য খুব বেশি টাইপ করা।
সিগটর্ম

24
@ ড্যামন যদি কিছু থাকে returnতবে পরিষ্কার, কারণ যে কোনও পাঠক তাত্ক্ষণিকভাবে অবগত হন যে এটি সঠিকভাবে কাজ করে এবং এটি কী করে। সঙ্গে gotoআপনি চারপাশে তাকান দেখতে কি এটা জন্য, এবং নিশ্চিত হয়ে নিন যে ভুল হয়েছিল হতে হবে। ছদ্মবেশ হয় সুবিধা।
আর মার্টিনহো ফার্নান্দিস

11
@ সিগটার্ম: কখনও কখনও কোডটি একটি পৃথক ফাংশনে স্থানান্তরিত করা উচিত কেবল প্রতিটি ফাংশনের আকারকে একটি সহজ-কারণে-কারণে-আকারের দিকে নামিয়ে রাখতে। আপনি যদি কোনও ফাংশন কলের জন্য অর্থ প্রদান করতে না চান তবে এটি চিহ্নিত করুন forceinline
বেন ভয়েগট

257

এমন কিছু সময় ব্যবহার করা gotoহয় যখন সত্যিকারের উত্তর হয় - অন্ততপক্ষে যারা ধর্মীয় বিশ্বাসে লালিত হন না তাদের gotoপক্ষে "প্রশ্ন কখনই উত্তর হতে পারে না, প্রশ্ন যাই হোক না কেন" - এবং এটি এই ক্ষেত্রে অন্যতম।

এই কোড এর হ্যাক ব্যবহার করছে do { ... } while(0);একটি ড্রেসিং আপ একমাত্র উদ্দেশ্য জন্য gotoহিসেবে break। আপনি যদি ব্যবহার করতে যাচ্ছেন goto, তবে এটি সম্পর্কে খোলা থাকুন। কোডটি হার্ড করার জন্য এটি পড়ার কোনও অর্থ নেই।

একটি নির্দিষ্ট পরিস্থিতি ঠিক তখনই থাকে যখন আপনার বেশ জটিল শর্ত সহ প্রচুর কোড থাকে:

void func()
{
   setup of lots of stuff
   ...
   if (condition)
   {
      ... 
      ...
      if (!other condition)
      {
          ...
          if (another condition)
          {
              ... 
              if (yet another condition)
              {
                  ...
                  if (...)
                     ... 
              }
          }
      }
  .... 

  }
  finish up. 
}

এটি আসলে এটি পরিষ্কার করে দিতে পারে যে এই জাতীয় জটিল যুক্তি না রেখে কোডটি সঠিক।

void func()
{
   setup of lots of stuff
   ...
   if (!condition)
   {
      goto finish;
   }
   ... 
   ...
   if (other condition)
   {
      goto finish;
   }
   ...
   if (!another condition)
   {
      goto finish;
   }
   ... 
   if (!yet another condition)
   {
      goto finish;
   }
   ... 
   .... 
   if (...)
         ...    // No need to use goto here. 
 finish:
   finish up. 
}

সম্পাদনা: পরিষ্কার করার জন্য, আমি কোনওভাবেই gotoসাধারণ সমাধান হিসাবে ব্যবহারের প্রস্তাব দিচ্ছি না । তবে এমন কিছু ক্ষেত্রে রয়েছে যেখানে gotoঅন্যান্য সমাধানের চেয়ে ভাল সমাধান।

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

এখন, যখন আমরা সম্পন্ন করেছি, আমাদের একটি ফাইলে ডেটা সংরক্ষণ করা দরকার।

এবং হ্যাঁ, প্রায়শই অন্যান্য সমাধানগুলি যুক্তিযুক্ত সমাধান সরবরাহ করতে পারে তবে সবসময় নয়।


76
একমত নন। gotoএকটি জায়গা থাকতে পারে, কিন্তু goto cleanupনা। আরএআইআই দিয়ে ক্লিনআপ করা হয়।
এমসাল্টারস

14
@ এসএমএলটাররা: এটি ধরে নিয়েছে যে ক্লিনআপে এমন কিছু জড়িত যা রাইআইআই দিয়ে সমাধান করা যায়। সম্ভবত আমার "ইস্যু ত্রুটি" বা এর পরিবর্তে এমন কিছু বলা উচিত ছিল।
ম্যাটস পিটারসন

25
সুতরাং, এটিকে গুরুত্ব দিয়ে রাখুন, সম্ভবতঃ এর ধর্মীয় বিশ্বাস থেকে তাদের gotoপক্ষে কখনও সঠিক উত্তর হয় না। আমি মন্তব্য ছিল যদি আমি প্রশংসা করব ...
ম্যাট পিটারসন

19
লোকেরা ঘৃণা করে gotoকারণ আপনি এটি ব্যবহার করতে / এটি ব্যবহার করে এমন কোনও প্রোগ্রাম বোঝার জন্য ভাবতে হবে ... অন্যদিকে, মাইক্রোপ্রসেসরগুলি নির্মিত হয়েছে jumpsএবং conditional jumps... সুতরাং সমস্যাটি কিছু লোকের মধ্যে রয়েছে, যুক্তি বা অন্য কিছু নয়।
উলিভি’রার

17
উপযুক্ত ব্যবহারের জন্য +1 goto। RAII হয় না যে ব্যতিক্রম একটি অপব্যবহার হবে, সঠিক সমাধান যদি ত্রুটি বলে আশা করা হয় (ব্যতিক্রমী নয়)।
জো

82

আপনি একটি boolচলক সহ একটি সাধারণ ধারাবাহিকতা প্যাটার্ন ব্যবহার করতে পারেন :

bool goOn;
if ((goOn = check0())) {
    ...
}
if (goOn && (goOn = check1())) {
    ...
}
if (goOn && (goOn = check2())) {
    ...
}
if (goOn && (goOn = check3())) {
    ...
}

checkNরিটার্নের সাথে সাথে মৃত্যুদন্ডের এই শৃঙ্খলা বন্ধ হয়ে যাবে a false। অপারেটরের check...()শর্ট সার্কিটের কারণে আর কোনও কল করা হবে না &&। অধিকন্তু, নিখুঁত কম্পাইলার সেই সেটিং চিনতে স্মার্ট যথেষ্ট goOnথেকে falseএকটি একমুখী রাস্তায়, এবং অনুপস্থিত সন্নিবেশ goto endআপনার জন্য। ফলস্বরূপ, উপরের কোডটির পারফরম্যান্সটি কেবলমাত্র তার পাঠযোগ্যতার জন্য বেদনাদায়ক ঘা ছাড়াই একটি do/ while(0)এর মতো হবে।


30
ifঅবস্থার অভ্যন্তরের অ্যাসাইনমেন্টগুলি খুব সন্দেহজনক দেখাচ্ছে।
মিখাইল

90
@ মিখাইল কেবল একটি প্রশিক্ষণহীন চোখের কাছে।
dasblinkenlight

20
আমি এই কৌশলটি আগে ব্যবহার করেছি এবং এটি সর্বদা আমাকে এলোমেলো করে দিয়েছিল যে আমি কম্পাইলারটিকে দেখেছিলাম যে প্রথম দিকের ব্যর্থতা (জাম্পিং / ব্রেকআপের বিপরীতে) ব্যর্থ হলেও ifকী goOnহয়েছিল তা প্রতিটি বিষয়েই পরীক্ষা করার জন্য কোড তৈরি করতে হবে ... তবে আমি কেবল একটি পরীক্ষা চালিয়েছি এবং ভিএস ২০১২ অন্ততপক্ষে যাইহোক প্রথম মিথ্যা শর্ট সার্কিটের জন্য যথেষ্ট স্মার্ট ছিল। আমি এটি আরও প্রায়শই ব্যবহার করব। নোট: যদি আপনি ব্যবহার goOn &= checkN()তারপর checkN()সবসময় চালানো হবে এমনকি যদি goOnছিল falseশুরুতে if(অর্থাত, যে কি না)।
চিহ্নিত করুন

11
@ নাওয়াজ: আপনার যদি কোনও প্রশিক্ষণপ্রাপ্ত মন যদি কোনও কোড বেস জুড়ে স্বেচ্ছাসেবী পরিবর্তন করে থাকে তবে আপনার কেবলমাত্র ifএস এর ভিতরে থাকা কার্যভারের চেয়ে অনেক বড় সমস্যা রয়েছে ।
ইডেলিক

6
@ সিশার্প কমনীয়তা দর্শকের চোখে তাই! আমি বুঝতে বুঝতে ব্যর্থ হয়েছি যে পৃথিবীতে কীভাবে একটি লুপিং নির্মাণের অপব্যবহারকে একরকম "মার্জিত" হিসাবে ধরা যেতে পারে, তবে সম্ভবত এটিই কেবল আমার।
ডেসব্লিংকনলাইট

38
  1. কোডটি পৃথক ফাংশনে (বা সম্ভবত একাধিক) এ বের করার চেষ্টা করুন। তারপরে চেক ব্যর্থ হলে ফাংশন থেকে ফিরে আসুন।

  2. আশেপাশের কোডটি যদি এটির সাথে খুব জোর করে মিলিত হয় এবং আপনি এই সংযোগটি হ্রাস করার কোনও উপায় খুঁজে না পান তবে এই ব্লকের পরে কোডটি দেখুন। সম্ভবত, এটি ফাংশন দ্বারা ব্যবহৃত কিছু সংস্থান পরিষ্কার করে। একটি RAII অবজেক্ট ব্যবহার করে এই সংস্থানগুলি পরিচালনা করার চেষ্টা করুন ; তারপর প্রতিটি চতুর প্রতিস্থাপন breakসঙ্গে return(অথবা throw, যদি আরো উপযুক্ত থাকবে) এবং আপনার জন্য বস্তুর বিনাশকারী পরিষ্কার আপ যাক।

  3. যদি প্রোগ্রাম প্রবাহটি (অগত্যা) এতটা বিদ্রূপাত্মক হয় যে আপনার সত্যিকারের প্রয়োজন goto, তবে এটি একটি অদ্ভুত ছদ্মবেশ দেওয়ার চেয়ে এটি ব্যবহার করুন।

  4. যদি আপনার কোডিং বিধি থাকে যা অন্ধভাবে নিষিদ্ধ করে goto, এবং আপনি সত্যিই প্রোগ্রাম প্রবাহকে সহজ করতে পারবেন না, তবে আপনাকে সম্ভবত এটি আপনার doহ্যাক দিয়ে ছদ্মবেশ ধারণ করতে হবে ।


4
আমি নম্রভাবে জমা দিতে পারি যে RAII, কার্যকর হলেও এটি কোনও রূপালী বুলেট নয়। যখন আপনি নিজেকে রূপান্তর-গীত-টু-আরআইআইআই ক্লাস লিখতে চলেছেন যার অন্য কোনও ব্যবহার নেই, আমি অবশ্যই মনে করি যে ইতিমধ্যে উল্লিখিত "গোটো-এন্ড-দ্য দ্য ওয়ার্ল্ড" মূর্খ লোকদের ব্যবহার করে আপনি আরও ভাল পরিবেশিত হবেন।
idoby

1
@ বুসি_ওয়াইট: সত্যই, আরআইআই সব সমাধান করতে পারে না; সে কারণেই আমার উত্তরটি দ্বিতীয় দফার সাথে থেমে নেই, তবে এটি gotoযদি আরও ভাল বিকল্প হয় তবে আপনি পরামর্শ দিতে চলেছেন ।
মাইক সিমুর

3
আমি সম্মত, তবে আমি মনে করি গোটো-আরআইআই রূপান্তর ক্লাসগুলি লিখতে এটি একটি খারাপ ধারণা এবং আমি মনে করি এটি স্পষ্টভাবে বলা উচিত।
idoby

@ আইডোবি একটি আরএআইআই টেম্পলেট ক্লাস লেখার বিষয়ে , এবং একটি ল্যাম্বডায় আপনার যা প্রয়োজন একক ব্যবহারের ক্লিনআপ দিয়ে তা ইনস্ট্যান্ট করার
কালেথ

@ ক্যালথ আমার কাছে মনে হচ্ছে আপনি কি সিটি / ডেক্টর পুনর্নির্মাণ করছেন?
অহংকার

37

TLDR : RAII , লেনদেনজনিত কোড (শুধুমাত্র সেট ফলাফল বা রিটার্ন কাপড় যখন এটি আগে থেকেই নির্ণয় করা হয়) এবং ব্যতিক্রম।

দীর্ঘ উত্তর:

ইন সি , কোড এই ধরনের জন্য শ্রেষ্ঠ অনুশীলন একটি করে প্রস্থান / পরিষ্করণ / যোগ হয় অন্যান্য কোডে লেবেল, যেখানে স্থানীয় সম্পদের পরিষ্করণ ঘটে একটি ত্রুটি কোডের (যদি থাকে) ফিরিয়ে দেওয়া হয়। এটি সর্বোত্তম অনুশীলন কারণ এটি প্রাথমিকভাবে কোডটি বিভক্তকরণ, গণনা, প্রতিশ্রুতিবদ্ধ এবং ফিরে আসার জন্য আলাদা করে দেয়:

error_code_type c_to_refactor(result_type *r)
{
    error_code_type result = error_ok; //error_code_type/error_ok defd. elsewhere
    some_resource r1, r2; // , ...;
    if(error_ok != (result = computation1(&r1))) // Allocates local resources
        goto cleanup;
    if(error_ok != (result = computation2(&r2))) // Allocates local resources
        goto cleanup;
    // ...

    // Commit code: all operations succeeded
    *r = computed_value_n;
cleanup:
    free_resource1(r1);
    free_resource2(r2);
    return result;
}

সি, অধিকাংশ codebases এ, if(error_ok != ...এবং gotoকোড সাধারণত কিছু সুবিধা ম্যাক্রো (পিছনে লুকানো হয় RET(computation_result), ENSURE_SUCCESS(computation_result, return_code)ইত্যাদি)।

সি ++ উপর অতিরিক্ত সরঞ্জামগুলি অফার সি :

  • ক্লিনআপ ব্লক কার্যকারিতা আরআইআইআই হিসাবে প্রয়োগ করা যেতে পারে, এর অর্থ আপনার আর পুরো cleanupব্লকের প্রয়োজন নেই এবং প্রারম্ভিক রিটার্নের বিবৃতি যুক্ত করতে ক্লায়েন্ট কোড সক্ষম করতে হবে।

  • আপনি যখনই চালিয়ে যেতে না পারেন তখনই ছুঁড়ে ফেলুন, সমস্তকে if(error_ok != ...সরাসরি-ফরোয়ার্ড কলগুলিতে রূপান্তর করে ।

সমতুল্য সি ++ কোড:

result_type cpp_code()
{
    raii_resource1 r1 = computation1();
    raii_resource2 r2 = computation2();
    // ...
    return computed_value_n;
}

এটি সর্বোত্তম অনুশীলন কারণ:

  • এটি সুস্পষ্ট (এটি, ত্রুটি পরিচালনার সময় স্পষ্ট না হলেও অ্যালগরিদমের মূল প্রবাহটি হ'ল)

  • এটি ক্লায়েন্ট কোড লিখতে সহজ

  • এটি ন্যূনতম

  • এটা সহজ

  • এটিতে কোনও পুনরাবৃত্ত কোড কোড নেই

  • এটি কোনও ম্যাক্রো ব্যবহার করে না

  • এটি অদ্ভুত do { ... } while(0)নির্মাণ ব্যবহার করে না

  • এটি সর্বনিম্ন প্রচেষ্টা সহ পুনরায় ব্যবহারযোগ্য (এটি যদি আমি কলটি অন্য computation2();কোনও ফাংশনে অনুলিপি করতে চাই, তবে আমাকে do { ... } while(0)নতুন কোডে কোনও যোগ করার বিষয়টি নিশ্চিত করতে হবে না, #defineগোটো রেপার ম্যাক্রো এবং একটি ক্লিনআপ লেবেলও নয়) আর কিছু).


+1 টি। এটিই আমি ব্যবহার করতে চেষ্টা করি, আরআইআইআই বা অন্য কিছু ব্যবহার করে। shared_ptrএকটি কাস্টম মোছার সাথে অনেক কিছুই করতে পারে। সি ++ 11 এ ল্যাম্বডাস দিয়ে আরও সহজ।
ম্যাক

সত্য, তবে আপনি যদি পয়েন্টার নয় এমন জিনিসগুলির জন্য শেয়ারড_পিটার ব্যবহার করে শেষ করেন তবে কমপক্ষে এটি টাইপডেফ -বিবেচনা করুন: namespace xyz { typedef shared_ptr<some_handle> shared_handle; shared_handle make_shared_handle(a, b, c); };এই ক্ষেত্রে ( make_handleনির্মাণে সঠিক মুছে ফেলার ধরণটি সেট করার সাথে ), টাইপের নামটি আর বোঝায় না যে এটি পয়েন্টার হিসাবে রয়েছে ।
utnapistim

21

আমি সম্পূর্ণতার জন্য একটি উত্তর যুক্ত করছি। অন্যান্য বেশ কয়েকটি উত্তর উল্লেখ করেছে যে বৃহত শর্তের ব্লকটি আলাদা ফাংশনে বিভক্ত হতে পারে। তবে যেমনটি বেশ কয়েকবার উল্লেখ করা হয়েছিল তা হ'ল এই পদ্ধতিটি শর্তাধীন কোডটি মূল প্রসঙ্গে থেকে পৃথক করে। এটি একটি কারণ যা ল্যাম্বডাসকে সি ++ 11 এ ভাষাতে যুক্ত করা হয়েছিল। ল্যাম্বডাস ব্যবহারের জন্য অন্যরা পরামর্শ দিয়েছিল তবে কোনও স্পষ্ট নমুনা সরবরাহ করা হয়নি। আমি এই উত্তরে একটি রেখেছি। আমাকে যে আঘাত করে তা হ'ল এটি do { } while(0)অনেক দিক থেকে পদ্ধতির সাথে খুব মিল বলে মনে হচ্ছে - এবং এর অর্থ সম্ভবত এটি এখনও gotoছদ্মবেশে আছে ...

earlier operations
...
[&]()->void {

    if (!check()) return;
    ...
    ...
    if (!check()) return;
    ...
    ...
    if (!check()) return;
    ...
    ...
}();
later operations

7
আমার কাছে এই হ্যাক করণার চেয়ে খারাপ দেখাচ্ছে ... হ্যাক করার সময়।
মাইকেল

18

অবশ্যই না উত্তর, কিন্তু কোন উত্তর (সম্পূর্ণতার স্বার্থে)

পরিবর্তে :

do {
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
} while(0);

আপনি লিখতে পারেন:

switch (0) {
case 0:
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
}

এটি এখনও ছদ্মবেশে একটি গোটো , তবে কমপক্ষে এটি আর লুপ নয়। আপনি খুব সাবধানে চেক করতে কিছু নয় থাকবে না যার মানে অবিরত ব্লক লুকিয়ে কোথাও।

নির্মাণটিও যথেষ্ট সহজ যা আপনি আশা করতে পারেন যে সংকলকটি এটিকে দূরে সরিয়ে ফেলবে।

@ জামেসডলিনের পরামর্শ অনুসারে আপনি এমনকি এটি কোনও ম্যাক্রোর মতো আড়াল করতেও পারেন

#define BLOC switch(0) case 0:

এবং এটি ব্যবহার করুন

BLOC {
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
}

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


2
ওহ, চালাক এমনকি আপনি এটিকে ম্যাক্রোর মতো করে আড়াল করতে define BLOCK switch (0) case 0:এবং এটির মতো ব্যবহার করতে পারেন BLOCK { ... break; }
জেমসডলিন

@ জামেডলিন: এটি আমার আগে কখনও ঘটেনি যে এটি কার্যকর হতে পারে আপনি একটি স্যুইচের খোলার ব্র্যাকেটের আগে একটি মামলা রেখেছিলেন। তবে এটি প্রকৃতপক্ষে সি দ্বারা অনুমোদিত এবং এক্ষেত্রে এটি একটি দুর্দান্ত ম্যাক্রো লেখার পক্ষে সহজ।
ক্রিস

15

আমি অযৌক্তিকভাবে ম্যাটসের উত্তর বিয়োগের অনুরূপ একটি পদ্ধতির প্রস্তাব করব goto। ফাংশনটিতে কেবল শর্তযুক্ত যুক্তি রাখুন। যে কোনও কোড যা সর্বদা চলে তা কলারের মধ্যে ফাংশনটি আহ্বানের আগে বা পরে যাওয়া উচিত:

void main()
{
    //do stuff always
    func();
    //do other stuff always
}

void func()
{
    if (!condition)
        return;
    ...
    if (!other condition)
        return;
    ...
    if (!another condition)
        return;
    ... 
    if (!yet another condition)
        return;
    ...
}

3
মাঝামাঝি সময়ে আপনাকে যদি অন্য কোনও সংস্থান অর্জন করতে হয় তবে আপনাকে অন্য funcএকটি ফাংশন (আপনার নিদর্শন অনুযায়ী) ফ্যাক্টর আউট করতে হবে। এই সমস্ত বিচ্ছিন্ন ফাংশনগুলিতে যদি একই ডেটার প্রয়োজন হয় তবে আপনি কেবল একই স্ট্যাক যুক্তিগুলি বারবার অনুলিপি করে শেষ করতে পারেন, বা আপনার আর্গুমেন্টগুলি গাদাতে বরাদ্দ করার এবং চারপাশে একটি পয়েন্টার পাস করার সিদ্ধান্ত নেবেন, ভাষার বৈশিষ্ট্যের সবচেয়ে বেসিকটি উপকার না করে ( ফাংশন যুক্তি)। সংক্ষেপে, আমি এই সমাধানটিকে সবচেয়ে খারাপ অবস্থার জন্য স্কেল করে বিশ্বাস করি না যেখানে নতুন সংস্থানগুলি সাফ করার পরে প্রতিটি শর্ত পরীক্ষা করা হয়। নোট লাম্বদাস সম্পর্কে মন্তব্য নোট যদিও।
tne

2
ওপি মাঝখানে তার কোড ব্লক সংস্থানগুলি অর্জন করার বিষয়ে কিছু বলেছিল মনে নেই তবে আমি এটি একটি বাস্তব প্রয়োজন হিসাবে গ্রহণ করি। সেক্ষেত্রে যে কোনও জায়গায় স্ট্যাকের উপর রিসোর্স ঘোষণা করা func()এবং এর ধ্বংসকারীকে নিখরচায় সংস্থানগুলি পরিচালনা করার অনুমতি দেওয়ার ক্ষেত্রে কী ভুল ? যদি বাহ্যিক কোনও কিছু func()একই সংস্থানটিতে অ্যাক্সেসের প্রয়োজন হয় তবে এটি func()কোনও উপযুক্ত সংস্থান পরিচালক দ্বারা কল করার আগে গাদাতে ঘোষণা করা উচিত ।
ড্যান বেচার্ড

12

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


11

কার্যকর করার সময় যদি আপনার স্থানীয় ভেরিয়েবলগুলি প্রবর্তনের প্রয়োজন না হয় তবে আপনি প্রায়শই এটি সমতল করতে পারেন:

if (check()) {
  doStuff();
}  
if (stillOk()) {
  doMoreStuff();
}
if (amIStillReallyOk()) {
  doEvenMore();
}

// edit 
doThingsAtEndAndReportErrorStatus()

2
তবে তারপরে প্রতিটি শর্তে পূর্ববর্তীটি অন্তর্ভুক্ত করতে হবে, যা কেবল কুৎসিতই নয়, পারফরম্যান্সের জন্যও সম্ভবত খারাপ। আমরা "ঠিক আছে না" তত তাড়াতাড়ি এই চেকগুলি এবং ক্লিনআপের উপরে ঝাঁপিয়ে পড়া আরও ভাল।
tne

এটি সত্য, তবে এই পদ্ধতির সুবিধাগুলি যদি এমন কিছু আছে যা শেষে করা উচিত যাতে আপনি তাড়াতাড়ি ফিরে আসতে চান না (সম্পাদনা দেখুন)। যদি আপনি শর্তে ডুলিসের বুল ব্যবহারের পদ্ধতির সাথে একত্রিত হন, তবে যদি এটি খুব শক্ত লুপ না হয় তবে পারফরম্যান্স হিট উপেক্ষিত হবে।
the_mandrill

10

ড্যাসব্লিংক্লাইটলাইটের উত্তরের মতো, তবে ifকোনও কোড পর্যালোচক দ্বারা "স্থির" হয়ে যেতে পারে তার ভিতরে থাকা কার্যনির্বাহীকরণ এড়ানো :

bool goOn = check0();
if (goOn) {
    ...
    goOn = check1();
}
if (goOn) {
    ...
    goOn = check2();
}
if (goOn) {
    ...
}

...

আমি এই প্যাটার্নটি ব্যবহার করি যখন পরবর্তী পদক্ষেপের আগে কোনও পদক্ষেপের ফলাফলগুলি পরীক্ষা করা দরকার, যা এমন পরিস্থিতি থেকে পৃথক যেখানে সমস্ত চেক একটি বড় if( check1() && check2()...ধরণের প্যাটার্নের সাথে সামনে করা যেতে পারে ।


নোট করুন যে চেক 1 () সত্যিই পারফর্মস্টেপ 1 () হতে পারে যা পদক্ষেপের একটি ফলাফল কোড দেয়। এটি আপনার প্রক্রিয়া প্রবাহের জটিলতা কমিয়ে দেবে।
ডেনিস স্কিডমোর

10

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

#include <iostream>
#include <stdexcept>   // For exception, runtime_error, out_of_range

int main () {
    try {
        if (!condition)
            throw std::runtime_error("nope.");
        ...
        if (!other condition)
            throw std::runtime_error("nope again.");
        ...
        if (!another condition)
            throw std::runtime_error("told you.");
        ...
        if (!yet another condition)
            throw std::runtime_error("OK, just forget it...");
    }
    catch (std::runtime_error &e) {
        std::cout << e.what() << std::endl;
    }
    catch (...) {
        std::cout << "Caught an unknown exception\n";
    }
    return 0;
}

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

3
আমি বলতে চাইছি, এটি সম্পর্কে কুঁচকানো হবে না, তবে আপনি উল্লেখ করেছেন সেই স্ট্রস্ট্রপ আর্টিকেলে যান এবং "আমার কী ব্যতিক্রমগুলি ব্যবহার করা উচিত নয়?" সন্ধান করুন? অধ্যায়. অন্যান্য জিনিসের মধ্যে তিনি বলেছেন: "বিশেষত, থ্রোকটি কোনও ফাংশন (প্রত্যাবর্তনের অনুরূপ) থেকে কোনও মূল্য ফেরত দেওয়ার বিকল্প উপায় নয় so এটি করা ধীর হবে এবং বেশিরভাগ সি ++ প্রোগ্রামার কেবলমাত্র ত্রুটির জন্য ব্যবহৃত ব্যতিক্রমগুলি সেল করতে ব্যবহৃত হবে তা বিভ্রান্ত করবে will হ্যান্ডলিং। একইভাবে, নিক্ষেপ করা আউট থেকে বেরিয়ে আসার ভাল উপায় নয় throw "
ক্রেগ

3
@ ক্রেইগ আপনি যা নির্দেশ করেছেন তার সবই সঠিক, তবে আপনি ধরে check()নিচ্ছেন যে কোনও শর্ত ব্যর্থ হওয়ার পরে নমুনা প্রোগ্রামটি চালিয়ে যেতে পারে, এবং সত্যই এটি আপনার অনুমান, নমুনার কোনও প্রসঙ্গ নেই। ধরে নিই যে প্রোগ্রামটি চালিয়ে যেতে পারছে না, ব্যাতিক্রম ব্যবহার করেই যাওয়ার উপায়।
কার্টুচো

2
ঠিক আছে, সত্য যদি এটি আসলে প্রসঙ্গ হয়। তবে, অনুমানগুলি সম্পর্কে মজার বিষয় ... ;-)
ক্রেগ

10

আমার do{...}while(0)জন্য ভাল। আপনি যদি এটি দেখতে না চান তবে আপনি do{...}while(0)তাদের জন্য বিকল্প কীওয়ার্ড সংজ্ঞায়িত করতে পারেন।

উদাহরণ:

//--------SomeUtilities.hpp---------
#define BEGIN_TEST do{
#define END_TEST }while(0);

//--------SomeSourceFile.cpp--------
BEGIN_TEST
   if(!condition1) break;
   if(!condition2) break;
   if(!condition3) break;
   if(!condition4) break;
   if(!condition5) break;

   //processing code here

END_TEST

আমি মনে করি যে সংকলকটি বাইনারি সংস্করণে অযাচিত while(0)অবস্থা সরিয়ে ফেলবে do{...}while(0)এবং বিরতিগুলিকে নিঃশর্ত জাম্পে রূপান্তর করবে। নিশ্চিত হয়ে আপনি এটি অ্যাসেম্বলি ভাষার সংস্করণ পরীক্ষা করতে পারেন।

ব্যবহারে gotoক্লিনার কোডও তৈরি হয় এবং এটি শর্ত-তারপরে জাম্প যুক্তির সাথে সোজা। আপনি নিম্নলিখিতটি করতে পারেন:

{
   if(!condition1) goto end_blahblah;
   if(!condition2) goto end_blahblah;
   if(!condition3) goto end_blahblah;
   if(!condition4) goto end_blahblah;
   if(!condition5) goto end_blahblah;

   //processing code here

 }end_blah_blah:;  //use appropriate label here to describe...
                   //  ...the whole code inside the block.

নোটটি বন্ধ হওয়ার পরে স্থাপন করা আছে তা নোট করুন }। এটি হ'ল এটির সম্ভাব্য সমস্যাটি gotoহ'ল দুর্ঘটনাক্রমে একটি কোড স্থাপন করা হচ্ছে কারণ আপনি লেবেলটি দেখেন নি। এটি এখন do{...}while(0)কন্ডিশন কোডবিহীন।

এই কোডটি ক্লিনার এবং আরও বোধগম্য করতে, আপনি এটি করতে পারেন:

//--------SomeUtilities.hpp---------
#define BEGIN_TEST {
#define END_TEST(_test_label_) }_test_label_:;
#define FAILED(_test_label_) goto _test_label_

//--------SomeSourceFile.cpp--------
BEGIN_TEST
   if(!condition1) FAILED(NormalizeData);
   if(!condition2) FAILED(NormalizeData);
   if(!condition3) FAILED(NormalizeData);
   if(!condition4) FAILED(NormalizeData);
   if(!condition5) FAILED(NormalizeData);

END_TEST(NormalizeData)

এটির সাহায্যে আপনি নেস্টেড ব্লকগুলি করতে পারেন এবং আপনি যেখানে প্রস্থান করতে / জাম্প আউট করতে চান তা নির্দিষ্ট করতে পারেন।

//--------SomeUtilities.hpp---------
#define BEGIN_TEST {
#define END_TEST(_test_label_) }_test_label_:;
#define FAILED(_test_label_) goto _test_label_

//--------SomeSourceFile.cpp--------
BEGIN_TEST
   if(!condition1) FAILED(NormalizeData);
   if(!condition2) FAILED(NormalizeData);

   BEGIN_TEST
      if(!conditionAA) FAILED(DecryptBlah);
      if(!conditionBB) FAILED(NormalizeData);   //Jump out to the outmost block
      if(!conditionCC) FAILED(DecryptBlah);

      // --We can now decrypt and do other stuffs.

   END_TEST(DecryptBlah)

   if(!condition3) FAILED(NormalizeData);
   if(!condition4) FAILED(NormalizeData);

   // --other code here

   BEGIN_TEST
      if(!conditionA) FAILED(TrimSpaces);
      if(!conditionB) FAILED(TrimSpaces);
      if(!conditionC) FAILED(NormalizeData);   //Jump out to the outmost block
      if(!conditionD) FAILED(TrimSpaces);

      // --We can now trim completely or do other stuffs.

   END_TEST(TrimSpaces)

   // --Other code here...

   if(!condition5) FAILED(NormalizeData);

   //Ok, we got here. We can now process what we need to process.

END_TEST(NormalizeData)

স্প্যাগেটি কোড এর ত্রুটি নয় goto, এটি প্রোগ্রামারের দোষ। আপনি এখনও ব্যবহার না করে স্প্যাগেটি কোড উত্পাদন করতে পারেন goto


10
আমি gotoএক মিলিয়ন বার প্রিপ্রসেসর ব্যবহার করে ভাষার বাক্য গঠনকে প্রসারিত করার মাধ্যমে বেছে নেব ।
খ্রিস্টান

2
"এই কোডটি পরিষ্কার এবং আরও বোধগম্য করতে আপনি [LOADS_OF_WEIRD_MACROS ব্যবহার করতে পারেন]" : গণনা করেন না।
আন্ডারস্কোর_

8

এটি কার্যকরী প্রোগ্রামিং দৃষ্টিকোণ থেকে একটি সুপরিচিত এবং সলভিত সমস্যা - সম্ভবত মোনাড।

আমি নীচে প্রাপ্ত মন্তব্যের প্রতিক্রিয়া হিসাবে আমি আমার পরিচিতিটি এখানে সম্পাদনা করেছি: আপনি বিভিন্ন জায়গায় সি ++ মনড বাস্তবায়ন সম্পর্কে সম্পূর্ণ বিশদ জানতে পারেন যা রোটারের পরামর্শ অনুসারে আপনাকে অর্জন করতে দেবে। মোনাডগুলি কুঁচকে উঠতে কিছুটা সময় লাগে তাই পরিবর্তে আমি এখানে একটি দ্রুত "দরিদ্র-মনুষ্য" মনাদ-জাতীয় প্রক্রিয়াটির পরামর্শ দিতে যাচ্ছি যার জন্য আপনার প্রয়োজন বিকাশ :: thanচ্ছিক ছাড়া আর কিছুই জানতে হবে না।

আপনার গণনার পদক্ষেপগুলি নীচে সেট আপ করুন:

boost::optional<EnabledContext> enabled(boost::optional<Context> context);
boost::optional<EnergisedContext> energised(boost::optional<EnabledContext> context);

প্রতিটি গণনামূলক পদক্ষেপ স্পষ্টতই ফেরতের মতো কিছু করতে পারে boost::noneযদি এটি দেওয়া alচ্ছিকটি খালি থাকে। উদাহরণস্বরূপ:

struct Context { std::string coordinates_filename; /* ... */ };

struct EnabledContext { int x; int y; int z; /* ... */ };

boost::optional<EnabledContext> enabled(boost::optional<Context> c) {
   if (!c) return boost::none; // this line becomes implicit if going the whole hog with monads
   if (!exists((*c).coordinates_filename)) return boost::none; // return none when any error is encountered.
   EnabledContext ec;
   std::ifstream file_in((*c).coordinates_filename.c_str());
   file_in >> ec.x >> ec.y >> ec.z;
   return boost::optional<EnabledContext>(ec); // All ok. Return non-empty value.
}

তারপরে তাদের একসাথে চেইন করুন:

Context context("planet_surface.txt", ...); // Close over all needed bits and pieces

boost::optional<EnergisedContext> result(energised(enabled(context)));
if (result) { // A single level "if" statement
    // do work on *result
} else {
    // error
}

এ সম্পর্কে দুর্দান্ত বিষয়টি হ'ল আপনি প্রতিটি গণনামূলক পদক্ষেপের জন্য পরিষ্কারভাবে সংজ্ঞায়িত ইউনিট পরীক্ষা লিখতে পারেন। অনুরোধটি সরল ইংরাজির মতো পড়ে (সাধারণত কার্যকরী শৈলীর ক্ষেত্রে এটি হয়)।

আপনি যদি অপরিবর্তনীয়তা সম্পর্কে চিন্তা না করেন এবং প্রতিবার একই জিনিসটি ফিরে আসা আরও সুবিধাজনক তবে আপনি শেয়ারড_পিটার বা এই জাতীয় ব্যবহার করে কিছুটা ভিন্নতা নিয়ে আসতে পারেন।


3
এই কোডটিতে পূর্ববর্তী ফাংশনটির ব্যর্থতা পরিচালনা করতে প্রতিটি স্বতন্ত্র ক্রিয়াকলাপকে বাধ্য করার এক অনাকাঙ্ক্ষিত সম্পত্তি রয়েছে, সুতরাং সঠিকভাবে মোনাড আইডিয়মটি ব্যবহার না করা (যেখানে এক্ষেত্রে ব্যর্থতার ক্ষেত্রে মোনাডিক প্রভাবগুলি স্পষ্টভাবে পরিচালিত হবে বলে মনে করা হয়)। এটি করার জন্য আপনার optional<EnabledContext> enabled(Context); optional<EnergisedContext> energised(EnabledContext);পরিবর্তে ফাংশন অ্যাপ্লিকেশন না করে monadic রচনাটি ('বাইন্ড') ব্যবহার করতে হবে।
Rotsor

ধন্যবাদ। আপনি সঠিক - এটি সঠিকভাবে এটি করার উপায়। আমি আমার উত্তরে খুব বেশি লিখতে চাইনি যে এটি ব্যাখ্যা করতে (অতএব "গরিব-মানস" শব্দটি যা বোঝানোর জন্য বোঝানো হয়েছিল আমি এখানে পুরো ছড়িয়ে যাচ্ছি না)।
বেনেডিক্ট

7

যদি বিবৃতিগুলি একটি অতিরিক্ত ক্রিয়ায় একটি সংখ্যা বা এনাম ফলাফল উপস্থাপন করে তবে কীভাবে?

int ConditionCode (void) {
   if (condition1)
      return 1;
   if (condition2)
      return 2;
   ...
   return 0;
}


void MyFunc (void) {
   switch (ConditionCode ()) {
      case 1:
         ...
         break;

      case 2:
         ...
         break;

      ...

      default:
         ...
         break;
   }
}

এটি সম্ভব হলে দুর্দান্ত, তবে এখানে জিজ্ঞাসিত প্রশ্নের তুলনায় খুব কম সাধারণ। প্রতিটি শর্ত শেষ ডিবাঞ্চিং পরীক্ষার পরে কার্যকর করা কোডের উপর নির্ভর করে।
খ্রিস্ট

এখানে সমস্যা হ'ল আপনি আলাদা কারণ এবং ফলাফল। অর্থাৎ আপনি পৃথক কোড যা একই শর্ত সংখ্যাটিকে বোঝায় এবং এটি আরও বাগের উত্স হতে পারে।
রিগা

@ ক্রিসস: ভাল, কন্ডিশনকোড () ফাংশনটি এটি যত্ন নিতে সামঞ্জস্য করা যেতে পারে। এই ফাংশনটির মূল বিষয়টি হ'ল আপনি চূড়ান্ত শর্ত গণনা করা মাত্রই পরিষ্কার ছাড়ার জন্য রিটার্ন <রিসাল্ট> ব্যবহার করতে পারেন; এবং এটিই এখানে কাঠামোগত স্পষ্টতা সরবরাহ করছে।
karx11erx

@ রিগা: ইমো এগুলি সম্পূর্ণ একাডেমিক আপত্তি। আমি প্রতিটি নতুন সংস্করণে আরও জটিল, ক্রিপ্টিক এবং অপঠনযোগ্য হয়ে উঠতে সি ++ পেয়েছি। টার্গেট ফাংশনটিকে আরও পড়ার যোগ্য করে তোলার জন্য একটি সুগঠিত পদ্ধতিতে জটিল অবস্থার মূল্যায়নের জন্য একটি ছোট সহায়ক সহায়ক ফাংশনে আমি কোনও সমস্যা দেখতে পাচ্ছি না।
karx11erx

1
@ karx11erx আমার আপত্তিগুলি ব্যবহারিক এবং আমার অভিজ্ঞতার ভিত্তিতে। এই প্যাটার্নটি সি ++ 11 বা যে কোনও ভাষাতেই সম্পর্কিত নয় bad আপনার যদি ভাষা নির্মাণের ক্ষেত্রে অসুবিধা হয় যা আপনাকে ভাল আর্কিটেকচার লিখতে দেয় যা কোনও ভাষা সমস্যা নয়।
রিগা

5

এরকম কিছু সম্ভবত

#define EVER ;;

for(EVER)
{
    if(!check()) break;
}

বা ব্যতিক্রম ব্যবহার করুন

try
{
    for(;;)
        if(!check()) throw 1;
}
catch()
{
}

ব্যতিক্রম ব্যবহার করে আপনি ডেটাও পাস করতে পারেন।


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

5
এবং যখন আপনি ম্যাক্রোগুলি নামকরণ করেন, আপনার সেগুলি ম্যাক্রোর মতো হওয়া উচিত (অর্থাত্, সমস্ত বড় ক্ষেত্রে)। অন্যথায় যে কেউ ভেরিয়েবল / ফাংশন / প্রকার / ইত্যাদি নামকরণ করে। নামকরণ করা everহবে অত্যন্ত অসন্তুষ্ট ...
জেমসডলিন

5

আমি বিশেষভাবে ব্যবহার breakবা returnএ জাতীয় ক্ষেত্রে আসছি না । সাধারণত যখন আমরা এইরকম পরিস্থিতির মুখোমুখি হই তবে এটি সাধারণত তুলনামূলক দীর্ঘ পদ্ধতি।

যদি আমাদের একাধিক বহির্গমন পয়েন্ট থাকে, তবে আমরা যখন নির্দিষ্ট যুক্তিটি কার্যকর করতে পারি তা জানতে চাইলে এটি অসুবিধা হতে পারে: সাধারণত আমরা কেবল সেই যুক্তির টুকরোটি আবদ্ধ করে অবরুদ্ধ ব্লকগুলিতে চলতে থাকি, এবং সেইগুলি আবদ্ধ ব্লকের মানদণ্ডটি আমাদের জানায় যে অবস্থা:

উদাহরণ স্বরূপ,

if (conditionA) {
    ....
    if (conditionB) {
        ....
        if (conditionC) {
            myLogic();
        }
    }
}

বদ্ধ ব্লকগুলি দেখে, এটি খুঁজে পাওয়া সহজ যে myLogic()কেবল যখন conditionA and conditionB and conditionCসত্য হয়।

প্রথমদিকে রিটার্ন পাওয়া গেলে এটি অনেক কম দৃশ্যমান হয়:

if (conditionA) {
    ....
    if (!conditionB) {
        return;
    }
    if (!conditionD) {
        return;
    }
    if (conditionC) {
        myLogic();
    }
}

myLogic()অবস্থাটি সনাক্ত করার জন্য আমরা এখন আর এখান থেকে নেভিগেট করতে পারি না enc

আমি ব্যবহার করেছি বিভিন্ন workaround আছে। তাদের মধ্যে একটি এখানে:

if (conditionA) {
    isA = true;
    ....
}

if (isA && conditionB) {
    isB = true;
    ...
}

if (isB && conditionC) {
    isC = true;
    myLogic();
}

(অবশ্যই সকলকে প্রতিস্থাপনের জন্য একই পরিবর্তনশীলটি ব্যবহার করা স্বাগত isA isB isC

এই জাতীয় দৃষ্টিভঙ্গি কমপক্ষে কোডের পাঠককে দেয়, myLogic()যখন এটি কার্যকর করা হয় isB && conditionC। পাঠককে একটি ইঙ্গিত দেওয়া হয় যে তার আরও তদন্ত করা দরকার যেটি আইজিকে সত্য হতে পারে।


3
typedef bool (*Checker)();

Checker * checkers[]={
 &checker0,&checker1,.....,&checkerN,NULL
};

bool checker1(){
  if(condition){
    .....
    .....
    return true;
  }
  return false;
}

bool checker2(){
  if(condition){
    .....
    .....
    return true;
  }
  return false;
}

......

void doCheck(){
  Checker ** checker = checkers;
  while( *checker && (*checker)())
    checker++;
}

কীভাবে?


যদি অপ্রচলিত হয়, ঠিক return condition;, অন্যথায় আমি মনে করি এটি ভালভাবে রক্ষণাবেক্ষণযোগ্য।
স্পেসট্রিকার

2

ব্যর্থতাটি কোথায় রয়েছে তার উপর নির্ভর করে আপনার যদি বিভিন্ন পরিষ্কারকরণ পদক্ষেপের প্রয়োজন হয় তবে অন্য একটি ধরণ কার্যকর:

    private ResultCode DoEverything()
    {
        ResultCode processResult = ResultCode.FAILURE;
        if (DoStep1() != ResultCode.SUCCESSFUL)
        {
            Step1FailureCleanup();
        }
        else if (DoStep2() != ResultCode.SUCCESSFUL)
        {
            Step2FailureCleanup();
            processResult = ResultCode.SPECIFIC_FAILURE;
        }
        else if (DoStep3() != ResultCode.SUCCESSFUL)
        {
            Step3FailureCleanup();
        }
        ...
        else
        {
            processResult = ResultCode.SUCCESSFUL;
        }
        return processResult;
    }

2

আমি কোনও সি ++ প্রোগ্রামার নই , সুতরাং আমি এখানে কোনও কোড লিখব না, তবে এখনও অবধি কোনও বস্তু কেন্দ্রিক সমাধানের কথা উল্লেখ করেনি। সুতরাং এখানে আমার অনুমান:

একটি জেনেরিক ইন্টারফেস রয়েছে যা একটি একক শর্তকে মূল্যায়নের জন্য একটি পদ্ধতি সরবরাহ করে। এখন আপনি প্রশ্নে পদযুক্ত আপনার বস্তুতে সেই শর্তগুলির বাস্তবায়নের একটি তালিকা ব্যবহার করতে পারেন। আপনি তালিকার উপরে পুনরাবৃত্তি করুন এবং প্রতিটি শর্তটি মূল্যায়ন করুন, সম্ভবত কোনও ব্যর্থ হলে খুব তাড়াতাড়ি ব্রেকআপ হয়ে যায়।

ভাল কথা হ'ল এই জাতীয় নকশাটি খোলার / বদ্ধ নীতিটির সাথে খুব ভাল লেগে যায় কারণ আপনি প্রশ্নে থাকা পদ্ধতিযুক্ত অবজেক্টটি শুরু করার সময় সহজেই নতুন শর্ত যুক্ত করতে পারেন। আপনি শর্তের বিবরণ ফিরিয়ে আনার শর্ত মূল্যায়নের জন্য পদ্ধতির সাথে ইন্টারফেসে একটি দ্বিতীয় পদ্ধতিও যুক্ত করতে পারেন। এটি স্ব-ডকুমেন্টিং সিস্টেমগুলির জন্য ব্যবহার করা যেতে পারে।

নেতিবাচক দিকটি হ'ল আরও কিছু ওভারহেড জড়িত কারণ আরও বেশি বস্তুর ব্যবহার এবং তালিকার উপরে পুনরাবৃত্তি ঘটে।


আপনি একটি ভিন্ন ভাষায় উদাহরণ যোগ করতে পারেন? আমি মনে করি এই প্রশ্নটি অনেক ভাষায় প্রযোজ্য যদিও এটি বিশেষত সি ++ সম্পর্কে জিজ্ঞাসা করা হয়েছিল।
ডেনিস স্কিডমোর

1

এইভাবেই আমি এটি করি।

void func() {
  if (!check()) return;
  ...
  ...

  if (!check()) return;
  ...
  ...

  if (!check()) return;
  ...
  ...
}

1

প্রথমত, gotoC ++ এর জন্য কেন ভাল সমাধান নয় তা দেখানোর একটি সংক্ষিপ্ত উদাহরণ :

struct Bar {
    Bar();
};

extern bool check();

void foo()
{
    if (!check())
       goto out;

    Bar x;

    out:
}

এটি কোনও অবজেক্ট ফাইলে সংকলন করার চেষ্টা করুন এবং দেখুন কী ঘটে। তারপরে সমতুল্য do+ break+ চেষ্টা করুন while(0)

এটা ছিল একদিকে। মূল বিষয়টি অনুসরণ করে।

কোড যারা সামান্য অংশ প্রায়ই প্রয়োজন কিছু পরিষ্করণ ধরনের পুরো ফাংশন ব্যর্থ করা উচিত নয়। আংশিক-সমাপ্ত গণনাটি আপনি "আনওয়াইন্ড" করার কারণে এই পরিষ্কারগুলি সাধারণত খণ্ডগুলি থেকে বিপরীত ক্রমে ঘটতে চায় ।

এই শব্দার্থকগুলি পাওয়ার জন্য একটি বিকল্প হ'ল রাইআইআই ; @ utnapistim এর উত্তর দেখুন। সি ++ গ্যারান্টি দেয় যে স্বয়ংক্রিয় ধ্বংসকারীরা নির্মাণকারীদের বিপরীত ক্রমে চালিত হয়, যা স্বাভাবিকভাবে একটি "অযাচিত" সরবরাহ করে।

তবে এর জন্য প্রচুর RAII ক্লাস প্রয়োজন। কখনও কখনও একটি সহজ বিকল্প কেবল স্ট্যাক ব্যবহার করা হয়:

bool calc1()
{
    if (!check())
        return false;

    // ... Do stuff1 here ...

    if (!calc2()) {
        // ... Undo stuff1 here ...
        return false;
    }

    return true;
}

bool calc2()
{
    if (!check())
        return false;

    // ... Do stuff2 here ...

    if (!calc3()) {
        // ... Undo stuff2 here ...
        return false;
    }

    return true;
}

... ইত্যাদি। এটি নিরীক্ষণ করা সহজ, যেহেতু এটি "কর" কোডের পাশে "পূর্বাবস্থায়" কোড রাখে। সহজ নিরীক্ষণ ভাল। এটি নিয়ন্ত্রণ প্রবাহকে খুব স্পষ্ট করে তোলে। এটি সি এর জন্যও কার্যকর প্যাটার্ন।

calcপ্রচুর আর্গুমেন্ট গ্রহণের জন্য এটি ফাংশনগুলির প্রয়োজন হতে পারে, তবে আপনার ক্লাস / স্ট্রাক্টগুলিতে ভাল সংহতি থাকলে সাধারণত সমস্যা হয় না। (এটি, একসাথে সম্পর্কিত স্টাফগুলি একক বস্তুতে বাস করে, তাই এই ফাংশনগুলি অল্প সংখ্যক অবজেক্টের জন্য পয়েন্টার বা রেফারেন্স নিতে পারে এবং এখনও প্রচুর দরকারী কাজ করতে পারে))


ক্লিনআপ পাথের নিরীক্ষণ করা খুব সহজ, তবে সোনার পথটি সনাক্ত করা এত সহজ নয়। তবে সামগ্রিকভাবে, আমি মনে করি এর মতো কিছু একটি ধারাবাহিক পরিচ্ছন্নতার ধরণকে উত্সাহ দেয়।
ডেনিস স্কিডমোর

0

যদি আপনার কোডটিতে if..else if..else বিবৃতিগুলির একটি দীর্ঘ ব্লক থাকে তবে আপনি Functorsবা এর সাহায্যে পুরো ব্লকটি আবার লিখতে পারেন function pointers। এটি সর্বদা সঠিক সমাধান নাও হতে পারে তবে প্রায়শই হয়।

http://www.cprogramming.com/tutorial/functors-function-objects-in-c++.html


নীতিগতভাবে এটি সম্ভব (এবং খারাপ নয়) তবে সুস্পষ্ট ফাংশন অবজেক্টস বা-পয়েন্টার সহ এটি কোড প্রবাহকে খুব বেশি দৃ .়তার সাথে ব্যাহত করে। এটি সমতুল্য লম্বাডাস বা সাধারণ নামযুক্ত ফাংশনগুলির ব্যবহার ভাল অনুশীলন, দক্ষ এবং ভালভাবে পড়া যায়।
বামে চূড়ান্ত

0

আমি এখানে উপস্থাপন করা বিভিন্ন উত্তর সংখ্যা দ্বারা অবাক। তবে, শেষ অবধি আমাকে যে কোডটি পরিবর্তন করতে হবে (যেমন এই do-while(0)হ্যাক বা অন্য কিছু সরিয়ে ফেলতে হবে ), আমি এখানে বর্ণিত উত্তরগুলির থেকে আলাদা কিছু করেছি এবং কেন কেউ এ কথা ভাবেনি তা নিয়ে আমি বিভ্রান্ত হয়ে পড়েছি। আমি যা করেছি তা এখানে:

প্রাথমিক কোড:

do {

    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
} while(0);

finishingUpStuff.

এখন:

finish(params)
{
  ...
  ...
}

if(!check()){
    finish(params);    
    return;
}
...
...
if(!check()){
    finish(params);    
    return;
}
...
...
if(!check()){
    finish(params);    
    return;
}
...
...

সুতরাং, এখানে কী করা হয়েছে তা হ'ল ফিনিশিং স্টাফগুলি কোনও ফাংশনে আলাদা করা হয়েছে এবং জিনিসগুলি হঠাৎ এত সহজ এবং পরিষ্কার হয়ে গেছে!

আমি ভেবেছিলাম এই সমাধানটি উল্লেখযোগ্য, সুতরাং এটি এখানে সরবরাহ করুন।


0

এটি একটি ifবিবৃতিতে একীভূত করুন :

if(
    condition
    && other_condition
    && another_condition
    && yet_another_condition
    && ...
) {
        if (final_cond){
            //Do stuff
        } else {
            //Do other stuff
        }
}

এটি জাভা-র মতো ভাষায় ব্যবহৃত প্যাটার্নটি যেখানে গোটো কীওয়ার্ড সরানো হয়েছিল।


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

@ জেরেমিফ্রিজার প্রকৃতপক্ষে, আপনি আসলে মধ্যে-মধ্যে-স্টাফ পৃথক বুলিয়ান ফাংশন হিসাবে করতে পারেন যা সর্বদা হিসাবে মূল্যায়ন করে true। শর্ট সার্কিট মূল্যায়ন গ্যারান্টি দেয় যে আপনি কখনও কখনও এমন স্টাফের মধ্যে চলবেন না যার জন্য সমস্ত পূর্বশর্ত পরীক্ষাগুলি পাস করেনি।
এজেম্যানসফিল্ড

@ এজেম্যান্সফিল্ড হ্যাঁ, এটিই আমি আমার দ্বিতীয় বাক্যে উল্লেখ করছি ... তবে আমি নিশ্চিত নই যে এটি করা কোডের মানের উন্নতি হবে।
জেরেমি ফ্রাইজনার

@ জেরেমিফ্রিজার কিছুই শর্ত লিখতে বাধা দেয় না (/*do other stuff*/, /*next condition*/), আপনি এটি সুন্দরভাবে ফরম্যাটও করতে পারেন। লোকেরা এটি পছন্দ করবে এমন আশা করবেন না। তবে সত্যই, এটি কেবল এটি দেখানোর জন্য যায় যে জাভা যে gotoবিবৃতিটি পর্যালোচনা করেছিলেন তা ভুল ছিল ...
সিমেস্টার - মনিকা পুনরুদ্ধার করুন

@ জেরেমিফ্রিজার আমি অনুমান করছিলাম যে এগুলি বুলিয়ান। যদি প্রতিটি শর্তের ভিতরে ফাংশনগুলি পরিচালনা করা হয় তবে এটি পরিচালনা করার চেয়ে আরও ভাল উপায়।
টাইজয়েড

0

যদি সমস্ত ত্রুটির জন্য একই ত্রুটি হ্যান্ডলারটি ব্যবহার করা হয় এবং প্রতিটি পদক্ষেপ সাফল্যের ইঙ্গিত দেয় এমন একটি বিল দেয়:

if(
    DoSomething() &&
    DoSomethingElse() &&
    DoAThirdThing() )
{
    // do good condition action
}
else
{
    // handle error
}

(টাইজয়েডের জবাবের মতো, তবে শর্তগুলি ক্রিয়া হয়, এবং && প্রথম ক্রিয়াকলাপের পরে অতিরিক্ত ক্রিয়াগুলি ঘটতে বাধা দেয়))


0

পতাকাঙ্কিত পদ্ধতিটির উত্তর কেন দেওয়া হয়নি তা এটি যুগ যুগ ধরে ব্যবহৃত হয়।

//you can use something like this (pseudocode)
long var = 0;
if(condition)  flag a bit in var
if(condition)  flag another bit in var
if(condition)  flag another bit in var
............
if(var == certain number) {
Do the required task
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.