Verkürzung von sprintf() und throw Exception

CSANecromancer

Erfahrenes Mitglied
Hi Leute,

in meinem derzeitigen Projekt habe ich eine Utilityklasse mit verschiedenen Grafikfunktionen. In jeder Funktion findet vor der Verarbeitung eine ausführliche Parameterprüfung statt.

Beispielsweise gegeben ist:

Im Header:
Code:
#define GFX "TGraphicsControl"
#define GFX_GRAYSCALE "GrayScale(): "
#define GFX_GRAYSCALE_ERR003 "%s Empty source bitmap referenced.\nWidth: %d, Height: %d"

Im Source:
Code:
m_strError[256];
strcpy(m_strError, GFX);
strcay(m_strError, GFX_GRAYSCALE);

if ((p_bmSource->Width == 0) || (p_bmSource->Height == 0))
{
  sprintf(m_strErrorBuffer, 
          GFX_GRAYSCALE_ERR003, 
          m_strError, 
          p_bmSource->Width, 
          p_bmSource->Height);

  throw (EGraphicsException(m_pParent, m_strErrorBuffer));
}
wobei p_bmSource ein Pointer auf ein Bitmapobjekt ist und EGraphicsException eine selbst definierte Exceptionklasse.

(Das verwendete Rahmenwerk ist die VCL von Borland, was aber mit der eigentlichen Frage nach meinem Erachten nicht unbedingt etwas zu tun hat.)

Mein Problem ist jetzt folgendes:
Ich habe im Source ziemlich viele solcher Prüfungen. Und mich stört ein wenig, daß ich zu jeder Prüfung nach dem if() vier Zeilen brauche (geschw. Klammer auf, sprintf(), throw, geschw. Klammer zu). Mir wäre es sehr lieb, wenn ich den throw der Exception auf eine einzige Zeile verkürzen könnte.
Blöderweise muß ich die Fehlermeldungen manuell aufbauen und kann nicht einfach auf die reinen Exceptionmeldungen zurückgreifen. Ich muß also meinen Fehlerstring, der passende Platzhalter (%d, %s) beinhaltet, irgendwie (z.B. mit sprintf() ) zusammenbauen und dann an den throw weiterreichen.
Wenn sprintf() den fertig gebauten String als Rückgabewert zurückreichen würde (im Stile von char* sprintf(...) ), dann wäre das ja kein Problem.

Fällt jemandem eine Möglichkeit ein, wie ich auf einen Rutsch meinen Fehlerstring zusammenbauen und an den throw weiterreichen kann?
 
Hi.

Du könntest den Seqenzoperator verwenden:
C++:
throw EGraphicsException(m_pParent, (sprintf(m_strErrorBuffer, 
GFX_GRAYSCALE_ERR003, 
          m_strError, 
          p_bmSource->Width, 
          p_bmSource->Height), m_strErrorBuffer));
Ob das jetzt natürlich übersichtlicher ist...

Gruß
 
Zuletzt bearbeitet:
Ich habe es gerade in verschiedenen Varianten ausprobiert, klappt leider nicht.
Die aufbereitete Fehlermeldung soll ja in m_strErrorBuffer stehen und das geschieht mit dem von dir geposteten Konstrukt leider nicht.

Also ich habe den Fall so konstruiert:

Hauptprogramm:
Code:
  m_GFX->GrayScale(NULL, imCheck->Picture->Bitmap, gfGray);
Da die Source Bitmap leer ist (NULL) kann die Funktion natürlich nicht durchlaufen, der Fehler muß entsprechend abgefangen werden. Das m_GFX ist dabei das Objekt mit den ganzen Funktionen mit den Parameterprüfungen.

Im m_GFX sieht es dann so aus:
Code:
  // Ist überhaupt eine Bitmap übergeben worden?
  if(!p_bmSource)
  {
    sprintf(m_strErrorBuffer, POSGFX_GRAYSCALE_ERR001, m_strError);
    throw (EPOSGraphicsException(m_pParent, m_strErrorBuffer));
  }
Die EPOSGraphicsException ist dabei ein einfache Exception, die einen Sender (im Code m_pParent) und einen char* (m_strErrorBuffer) übergeben bekommt. Damit habe ich einerseits ein Exceptionobjekt, das mir mitteilt, wo genau der Fehler auftrat und einen String, der mir ganz genau sagt, was schief gegangen ist.

Wenn ich das hier benutze:
Code:
throw EGraphicsException(m_pParent, (sprintf(m_strErrorBuffer,
GFX_GRAYSCALE_ERR003,
          m_strError,
          p_bmSource->Width,
          p_bmSource->Height), m_strErrorBuffer);
dann kann ich zwar die Exception werfen, aber m_strErrorBuffer ist nicht belegt. Ich bekomme lediglich das Parent-Objekt in die Exception und einen leeren String.

Aber evtl. hast du mich gerade auf eine Idee gebracht...
 
Danke, aber ich habe es jetzt anders gelöst und irgendwie finde ich die Lösung auch nicht gerade hässlich:
Code:
// Enthält die Übergabebitmap Daten?
if ((p_bmSource->Width == 0) || (p_bmSource->Height == 0))
  ThrowException(POSGFX_GRAYSCALE_ERR003, p_bmSource->Width, p_bmSource->Height);

Ich habe mal meine gesamten Fehlermeldungen geprüft und die hatten alle das Schema String, [int], [int]. Da bot sich natürlich eine Funktion mit Vorgabeparametern an. Da mir die Performance im Exceptionfall auch gestohlen bleiben kann ;) , kann ich den Fehlerstring einfach in einer Funktion zusammenbasteln und dann eine passende Exception werfen.

Frag nicht wieso, aber deine Erwähnung des Sequenzoperators hat mich irgendwie auf die Idee gebracht.
 
Hallo,

falls du die Exception-Klasse verändert kannst/darfst, könntest du auch einen neuen Konstruktor definieren. Dieser nimmt dann einen Formatstring und eine variable Anzahl von weiteren Parametern entgegen und baut sich die Fehlermeldung mittels sprintf dann selbst zusammen. Dieses Muster könntest du natürlich auch auf deine Hilfsfunktion ThrowException anwenden, falls du mehr Flexibilität benötigst.

Grüße, Matthias
 
Hallo,
falls du die Exception-Klasse verändert kannst/darfst
Ist gegeben.

könntest du auch einen neuen Konstruktor definieren. Dieser nimmt dann einen Formatstring und eine variable Anzahl von weiteren Parametern entgegen und baut sich die Fehlermeldung mittels sprintf dann selbst zusammen.
Das hatte ich probiert, aber nach ca. 3,5 Jahren Delphi und C++-Pause war ich zu doof/nicht fit genug, das für meinen Geschmack schnell genug hinzukriegen. Hier im Forum nerven wollte ich nicht. Und bislang klappt alles in einem guten Zeitrahmen, der Source ist sehr viel übersichtlicher geworden und ich habe keine Speicherlecks oder unbehandelte Exceptions, von daher: Alles im grünen Bereich. :)

Dieses Muster könntest du natürlich auch auf deine Hilfsfunktion ThrowException anwenden, falls du mehr Flexibilität benötigst
Bislang komme ich noch mit dem starren Schema String, [int], [int] gut zurecht und ich hoffe, daß ich keine variable Parameterliste brauche, da ich die noch nicht richtig hinbekomme. Wenn es soweit ist, dann werde ich wohl sowieso den Exception-Klassenkonstruktor abändern.
 
Hier im Forum nerven wollte ich nicht.
Zu spät ;-] (Und vielleicht auch für später auf dieses Thema stoßende Benutzer ganz interessant.)

C++:
#include <cstdarg>

void TGraphicsControl::ThrowError(const char* format, ...) {
  va_list args;
  va_start(args, format);
  vsprintf(m_strErrorBuffer, format, args);
  va_end(args);
  throw EGraphicsException(m_pParent, m_strErrorBuffer);
}

Grüße, Matthias
 
Zurück