Frage

Ich möchte einen Stringstream ableiten, damit ich den Operator << zum Erstellen einer Nachricht verwenden kann, die dann geworfen wird. Die API würde aussehen wie:

error("some text") << " more text " << 42 << std::endl;

Dies sollte a machen

throw "some text more text 42"

Ich habe also eine Fehlerbuf (Erben von StreamBuf) gemacht, die die "Überlauf" -Methode überlastet und dann einen Ostream (& ERRORBUF) erstellt. Ich frage mich, ob ich stattdessen nicht von Basic_oStringstream oder so etwas erben sollte ...

War es hilfreich?

Lösung

Ich werde hier wieder mein Lieblings -Makro ausstellen:

#define ATHROW( msg )                                               \
{                                                                   \
    std::ostringstream os;                                          \
    os << msg;                                                      \
    throw ALib::Exception( os.str(), __LINE__, __FILE__ );          \
}                                                                   \

In Benutzung:

ATHROW( "Invalid value: " << x << " should be " << 42 );

Der Ausnahmetyp stammt aus meiner eigenen Bibliothek, aber ich denke, Sie haben die Idee. Dies ist viel einfacher, als Ihre eigene Stream -Klasse abzuleiten, und vermeidet viele böse Komplikationen mit OP << ().

Andere Tipps

Sie könnten es wahrscheinlich einfacher machen, wenn Sie so etwas wie:

class error_builder
{
public:
    error_builder(const std::string& pMsg = "")
    {
        mMsg << pMsg;
    }

    ~error_builder(void)
    {
        throw std::runtime_error(mMsg.str());
    }

    template <typename T>
    error_builder& operator<<(const T& pX)
    {
        mMsg << pX;

        return *this;
    }

private:
    std::stringstream mMsg;    
};


error_builder("some text") << " more text " << 42 << std::endl;

Beachten Sie, dass Sie keine Saiten wie Sie werfen sollten, daher habe ich verwendet std::runtime_error. Alle Ausnahmen sollten abgeleitet werden std::exception, die runtime_error Auf diese Weise können alle sinnvollen Ausnahmen mit const erfasst werden std::exception&.

Dies funktioniert, weil der vorübergehende bis zum Ende des vollen Ausdrucks lebt.

Einige Betreiber fehlen bei Gmans Lösung.

class error {
   public:
   explicit error(const std::string& m = "") :
          msg(m, std::ios_base::out | std::ios_base::ate)
   {}

   ~error() {
      if(!std::uncaught_exception()) {
         throw std::runtime_error(msg.str());
      }
   }

   template<typename T>
   error& operator<<(const T& t) {
      msg << t;
      return *this;
   }

   error& operator<<(std::ostream& (*t)(std::ostream&)) {
      msg << t;
      return *this;
   }
   error& operator<<(std::ios& (*t)(std::ios&)) {
      msg << t;
      return *this;
   }
   error& operator<<(std::ios_base& (*t)(std::ios_base&)) {
      msg << t;
      return *this;
   }
   private:
   std::ostringstream msg;
};

Normalerweise erstelle ich nur meine eigenen Ausnahmeklassen. Sie müssen nur außer Kraft setzen what() und kann so viele Konstruktoren liefern, wie Sie möchten. Um die Fehlermeldung aufzubauen, verwenden Sie einfach Vasprintf (falls verfügbar) oder std :: ostringstream wie oben.

Hier ist ein Beispiel:

class CustomException : public std::exception {
private:
    const std::string message;
public:
    CustomException(const std::string &format, ...) {
        va_list args;
        va_start(args, format);
        char *formatted = 0;
        int len = vasprintf(&formatted, format.c_str(), args);
        if (len != -1) {
            message = std::string(formatted);
            free(formatted);
        } else {
            message = format;
        }
        va_end(args);
    }
    const char *what() const {
        return message.c_str();
    }
};

Wenn Sie kein Vasprintf haben, können Sie auch vsnprintf mit einem Puffer auf dem Stapel verwenden ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top