9 Stimmen

Single-Entry/Single-Exit-Regel

Ich habe irgendwo eine Regel dazu gelesen:

Befolgen Sie die Regel des einmaligen Zutritts und des einmaligen Austritts. Schreiben Sie niemals mehrere Return-Anweisungen in dieselbe Funktion.

Stimmt diese Aussage? Wenn ja, könnten Sie bitte genauer erläutern, warum wir diese Regel befolgen sollten?

25voto

David Hammen Punkte 31452

Ist das wahr?

So steht es in der Vorschrift, und zwar dort, wo sie angewendet und durchgesetzt wird. Ist es eine gute Regel? Ich wehre mich mit Händen und Füßen gegen ihre Annahme. Ich halte sie für eine dumme Regel. Schlimmer als dumm: Es ist eine schädliche Regel für C++.

Ich stimme dem ersten Teil der Regel, "einmalige Eingabe", zu. Die Fortran entry Anweisung verursacht viel mehr Probleme als sie löst. Dieser erste Teil der Regel gilt nicht für C oder C++ aus dem einfachen Grund, dass keine der beiden Sprachen einen Mechanismus für mehrere Einstiegspunkte bietet. "Ein einzelner Einstieg ist in C und C++ ein No-op.

Wie steht es also mit der "einmaligen Ausreise"? Eine vorzeitige Rückkehr verursacht nicht unbedingt Probleme. Probleme entstehen, wenn die zugewiesenen Ressourcen vor der Rückkehr nicht bearbeitet werden. Die richtige Regel lautet: "Räumt euren Mist auf", oder lasst keine Ressourcen liegen, die nicht genutzt werden. Single Exit löst dieses Problem nicht, weil es nichts über das Aufräumen aussagt.

In C geht die Single Entry / Single Exit-Regel in der Regel Hand in Hand mit der Zulassung (und sogar Förderung) der Verwendung von goto für die Fehlerbehandlung. Ich sehe den Platz für goto wie es für die Fehlerbehandlung im Linux-Kernel-Code verwendet wird. Aber nicht in C++. Aus diesem Grund habe ich geschrieben, dass Single Entry / Single Exit in C++ schädlich ist. Diese Regel entmutigt die Verwendung von RAII und ausnahmesicherer Programmierung und ermutigt die Verwendung von goto .

12voto

SingerOfTheFall Punkte 28940

Nein, das ist keine Regel, und manchmal ist es sogar schwierig/unmöglich zu erreichen. Ein Code mit einem Eintritts- und einem Austrittspunkt ist jedoch leichter zu verstehen und zu beheben. Vergleichen Sie dies:

int foo()
{
    if(something)
        return 0;
    //100 lines of code
    if(something)
        return 11;
    //100 lines of code
    if(something)
        return -1;
    //100 lines of code
    return 0;
}

und dies:

int foo()
{
    int errorCode = 0;
    if(something)
        errorCode = 1;
    //100 lines of code
    if(something)
        errorCode = 11;
    //100 lines of code
    if(something)
        errorCode = -1;
    //100 lines of code
    return errorCode;
}

Jetzt gibt es nur noch einen Exit-Point, und (auch unter Berücksichtigung des Variablennamens) ist es viel einfacher zu verstehen, was die Funktion tut. Sie können auch einen Haltepunkt auf den letzten Rücksprung setzen und wissen, dass dies der Punkt ist, an dem die Funktion endet, und dass Sie ihn definitiv treffen werden.

6voto

Gorpik Punkte 10610

Diese Regel mag in C gelten, kann aber in C++ aufgrund von Ausnahmen als veraltet betrachtet werden. Sobald Ihre Funktion eine Ausnahme auslöst oder eine Funktion aufruft, die eine Ausnahme auslösen kann, haben Sie einen zusätzlichen Exit-Point:

int f()
{
  //...
  g(); // g() may throw: you have an exit point here
  //...
  throw exc; // another possible exit point
  //...
  return returnValue; // Nice try, but you have additional exit points
}

Dies kommt zu dem in anderen Antworten gemachten Punkt hinzu: Diese Regel soll den Code übersichtlicher machen, aber es ist leicht, Beispiele zu finden, bei denen dies nicht zutrifft. Viel besser:

if (condition)
  return a;
if (condition2)
  return b;
if (condition3)
  return c;

// Insert all your code for the general case

als:

int returnValue;    
if (!condition) {
  if (!condition2) {
    if (!condition3) {
      // Insert your code here
    }
    else {
      returnValue = c;
    }
    returnValue = b;  // Where am I now?
  }
  returnValue = a;
}
return returnValue;

Und dann gibt es noch den Fall, dass Sie den Rückgabewert in einer switch :

switch (a)
{
  case 1: return 10;
  case 2: return 20;
  case 3: return 40;
  default: return 50;
}

statt:

int returnValue;
switch (a)
{
  case 1: returnValue = 10; break;
  case 2: returnValue = 20; break;
  case 3: returnValue = 40; break;
  default: returnValue = 50; break;
}
return returnValue; // Where is the clarity gained?

1voto

Choufler Punkte 460

Außerdem könnten mehrere Ausgänge ein Leistungsproblem darstellen: Wenn der Prozessor den aktuellen Befehl ausführt, verarbeitet er im gleichen Takt mehrere nächste Befehle und führt einige Operationen mit ihnen aus. Wenn Ihr Code also mehrere Exits hat, wie hier:

if (condition)
  return a;
DoSomething();
if (condition2)
  return b;

und die erste Bedingung erfüllt ist, wird die Extraktion von DoSomething() Befehl nutzlos sein wird. Eigentlich, mit Zweigvorhersage kann es immer noch gut sein, aber trotzdem ist es besser, diese Sache im Auge zu behalten.

0voto

Lajos Arpad Punkte 53001

Sie können Ihren Rückgabewert in einer Variablen speichern, wenn Sie dies erreichen wollen, aber es ist nicht wahr. Sie können ohne Probleme mehrere Rückgaben in derselben Funktion haben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X