Werfen einer Exception angebracht?

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Werfen einer Exception angebracht?

Beitrag von Dirty Oerti » Mi Jan 16, 2013 6:06 pm

Mal eine Meinungsfrage:

Ich habe einen einfachen Stack in C++ implementiert.

Wie würdet ihr die pop() bzw. top() Methode implementieren, speziell den Fall, wenn eine der Methoden aufgerufen wird obwohl der Stack leer ist?

Code: Alles auswählen

class Stack
{
  private:
  protected:
    int * const _begin;
    int * const _end;
    int * _current;
  public:
    Stack(unsigned int size);
    ~Stack();

    void push(int value);
    int pop();

    bool empty() const;
    int top() const;

    int const * begin() const;
    int const * end() const;
};

Code: Alles auswählen

#include "stack.hpp"

Stack::Stack(unsigned int size = 10)
  :
  _begin(new int[size]),
  _end(_begin + size - 1),
  _current(_begin - 1)
{}

Stack::~Stack()
{
  delete [] _begin;
}

void Stack::push(int value)
{
  if (_current < _end)
  {
    _current++;
    *_current = value;
  }
}

int Stack::pop()
{
  int value = 0;
  if (_current >= _begin)
  {
    value = *_current;
    _current--;
  }
  return value;
}

bool Stack::empty() const
{
  return (_current < _begin);
}

int Stack::top() const
{
  int value = 0;
  if (_current >= _begin)
  {
    value = *_current;
  }
  return value;
}

int const * Stack::begin() const
{
  return _begin;
}

int const * Stack::end() const
{
  return _end;
}
Wie ihr seht, gebe ich in diesem Fall einfach 0 zurück, da ich davon ausgehe, dass über die empty() - Methode ja abgefragt werden kann, ob noch was auf dem Stack ist.

Laut einer anderen Meinung wäre hier jedoch das Werfen einer Exception (also bei top und pop) besser.

Was meint ihr?

LG
Daniel
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3123
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Werfen einer Exception angebracht?

Beitrag von cloidnerux » Mi Jan 16, 2013 7:01 pm

Was meint ihr?
Kniffliges Problem.
Zum eine ist es schon sinnvoll den Nutzer darauf hinzuweisen, dass da auf dem Stack nichts mehr ist, indem halt eine Exception geworfen wird, damit man nicht mit Fehlerhaften Daten weiter rechnet.
Auf der anderen Seite ist das so eine tolle Sache, die niemand abfragen würde womit das Programm dann hin und wieder crasht.

Mit 0 zurück geben ist so eine Sache. Bei Pointer würde es dem Nutzer eine Aussage geben, dass hier etwas nichts stimmt, bei ints kann es sich auch um nen regulären Wert handeln und man popt evt sehr viel mehr vom Stack als egt drauf ist.
Ich wäre im Moment für die Exception.
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Werfen einer Exception angebracht?

Beitrag von Xin » Mi Jan 16, 2013 9:03 pm

Code: Alles auswählen

bool Stack::pop( int & value )
{
  if (_current >= _begin)
  {
    value = *_current;
    _current--;
    return true;
  }
  return false;
}
top entsprechend.

Dass ein Stack leer ist, ist keine Ausnahme, sondern der Regelfall, wenn nix mehr drauf ist...
Kurz: Ich bin absolut gegen eine Exception. Du musst auf 0 abfragen, was ein valider Wert sein kann; ich frage auf true und false abfragen und im Falle von true mit der Information arbeiten.

Bei Deiner pop-Variante initialisierst Du value mit 0. Wenn Du ein Ergebnis hast, überschreibst Du es. Wieso hast Du es dann initialisiert?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Werfen einer Exception angebracht?

Beitrag von fat-lobyte » Mi Jan 16, 2013 10:02 pm

Xin hat geschrieben:

Code: Alles auswählen

bool Stack::pop( int & value )
{
  if (_current >= _begin)
  {
    value = *_current;
    _current--;
    return true;
  }
  return false;
}
top entsprechend.

Ich wäre für eine Exception, weil ich solche Referenz/Zeiger+Rückgabewert-Konstrukte gar nicht mag.
Erstens kann man Rückgabewerte genausogut ignorieren wie Exceptions, der Unterschied ist halt, dass es nicht raucht und kracht, sondern nur ganz leise irgendwo ein Flag auf False gesetzt wird, dafür gibts dann irgendwo anders im Programm nen Segmentation fault.

Wenn du eine Referenz übergibst, dann ist der Zustand des referenzierten Objekts bei leerem Stack nach dem Aufruf undefiniert. Das kann dir bei "int" vielleicht egal sein, wenn du allerdings komplexere Objekte mit Konstruktoren reinsteckst, wird das ein Problem.
Man sollte Stets "in der Luft hängende" Objekte und undefinierte Objekte vermeiden.

Wenn du den Wert als Rückgabewert zurückgibst, ist erstens die Syntax ziemlich eindeutig ("gib mir ein int", "hier hast du es"), zweitens gibts da keine zweideutigkeiten wenn eine Exception knallt: es *gibt* den Rückgabewert einfach nicht, und der Nutzer ist gezwungen sich etwas für diesen Fall zu überlegen.


Hier noch eine alternative Variante für dich:
Was du hier hast ist eigentlich ein "pop_front()", also "lese das erste Objekt und lösche dieses dann aus dem Stack". Der Stack von STL verzichtet auf eine solche Methode, und gibt zwei verschiedene Funktionen:

Code: Alles auswählen

value_type& top()
welche dir eine Lesbare referenz auf das oberste Objekt zurückgibt ohne dieses zu entfernen und

Code: Alles auswählen

void pop()
, das dir erlaubt das oberste Element zu entfernen.
Haters gonna hate, potatoes gonna potate.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Werfen einer Exception angebracht?

Beitrag von Dirty Oerti » Do Jan 17, 2013 1:37 am

cloidnerux hat geschrieben:Auf der anderen Seite ist das so eine tolle Sache, die niemand abfragen würde womit das Programm dann hin und wieder crasht.
Ja, das sehe ich auch so. Ich würde es hier eben für sinnvoller halten, den Benutzer (des stack Codes) darauf hinzuweisen, dass im Falle eines leeren Stacks der Wert 0 zurückgegeben wird, vor Abnehmen eines Wertes also geprüft werden muss, ob sich noch Werte auf dem Stack befinden.

Meist wird so eine Struktur ja eh in ähnlicher Form wie folgendes benutzt:

Code: Alles auswählen

while(!myStack.empty())
{
  int value = myStack.pop();
  someCrazyFunction(value);
}
Xin hat geschrieben:Kurz: Ich bin absolut gegen eine Exception.
Ich prinzipiell eben auch. Ich sehe nicht den Sinn, hier eine Exception zu bemühen. Es mag zwar ein ganz interessantes Sprachmittel sein, aber in diesem Zusammenhang finde ich das übertrieben.
Bei der Implementierungen blieben mir da dann eigentlich nur zwei Möglichkeiten:

Entweder ich werfe einen primitiven Datentyp und spezifiziere genau, welcher Wert was bedeutet.
Oder ich schreibe eigens dafür eine Klassenhierarchie. Also z.B. StackException -> EmptyStackException oder wie auch immer.

Ich sehe auch das Problem, dass der Code des "Nutzers" meist nicht Exception-Safe ist:

Code: Alles auswählen

int * myBuffer = new int[400];
size_t iterator = 0;
while (someReallyCrazyCondition())
{
  myBuffer[iterator++] = myStack.pop();
  // More awesome magic
}
int result = moreCrazyThings(myBuffer);
delete [] myBuffer;
return result;
Nach Allem was ich weiß führt eine Exception hier dazu, dass ich ein hübsches MemoryLeak erhalte, weil myBuffer nicht freigegeben wird. Dazu bräuchte ich dann wieder Guard-Klassen und so weiter ...
Xin hat geschrieben:ich frage auf true und false
Das kann ich leider nicht, die Definition der Methode ist vorgegeben. Ansonsten fände ich die Methode aus technischer Sicht am besten, aber schön würde ich es nicht finden, weil:
fat-lobyte hat geschrieben:[...] Syntax ziemlich eindeutig ("gib mir ein int", "hier hast du es")
fat-lobyte hat geschrieben: Der Stack von STL verzichtet auf eine solche Methode, und gibt zwei verschiedene Funktionen:
Und wie arbeitet pop in diesem Fall? Mit einer Exception?
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Yoghurt
Beiträge: 79
Registriert: Fr Nov 16, 2012 8:01 am
Wohnort: Niederbayern

Re: Werfen einer Exception angebracht?

Beitrag von Yoghurt » Do Jan 17, 2013 8:25 am

Also hierfür eine Exception zu werfen empfinde ich wie mit Kanonen auf Spatzen zu schießen.
Ich wüsste jetzt aber auch nicht wie du sonst eine vernünftige Fehleranzeige hinbekommen könntest, da du ja die Signatur nicht verändern darfst. Also in dem Fall wo du pop() und top() in einer Funktion haben willst.
Was ist zum Beispiel, wenn du 0 auf deinen Stack schreiben willst?
Dirty Oerti hat geschrieben:[quote="Dirty Oerti"fat-lobyte"]
Der Stack von STL verzichtet auf eine solche Methode, und gibt zwei verschiedene Funktionen:
Und wie arbeitet pop in diesem Fall? Mit einer Exception?[/quote]
Ich denke ja, weil pop() hier den Rückgabewert void hat.
Da dein pop() aber sowieso einen int zurückgibt, könntest du hier die Fehleranzeige mit Fehlercodes machen. :)

Bei top() hast du dann allerdings wieder das gleiche Problem, dass du entweder eine Exception werfen musst oder ein definierter int-Wert angibt, dass dein Stack leer ist. Diesen Wert kannst du dann aber auch nicht auf dem Stack speichern.
"Theory is when you know something, but it doesn't work.
Practice is when something works, but you don't know why.
Programmers combine theory and practice: Nothing works and they don't know why."

Antworten