Pregunta

Soy un estudiante en mi primera clase de programación C ++, y estoy trabajando en un proyecto en el que tenemos que crear varias clases de excepción personalizada, y luego en uno de los controladores de eventos, utilice un bloque try/catch para manejar adecuadamente .

Mi pregunta es: ¿Cómo puedo coger mi varios excepciones personalizadas en mi bloque try/catch? GetMessage() es un método personalizado en mis clases de excepción que devuelve la explicación como una excepción std::string. A continuación he incluido todo el código relevante de mi proyecto.

Gracias por su ayuda!

try / catch


    // This is in one of my event handlers, newEnd is a wxTextCtrl
try {
    first.ValidateData();
    newEndT = first.ComputeEndTime();
    *newEnd << newEndT;
}
catch (// don't know what do to here) {
    wxMessageBox(_(e.GetMessage()), 
                 _("Something Went Wrong!"),
                 wxOK | wxICON_INFORMATION, this);;
}

ValidateData () Método


void Time::ValidateData()
{
    int startHours, startMins, endHours, endMins;

    startHours = startTime / MINUTES_TO_HOURS;
    startMins = startTime % MINUTES_TO_HOURS;
    endHours = endTime / MINUTES_TO_HOURS;
    endMins = endTime % MINUTES_TO_HOURS;

    if (!(startHours <= HOURS_MAX && startHours >= HOURS_MIN))
        throw new HourOutOfRangeException("Beginning Time Hour Out of Range!");
    if (!(endHours <= HOURS_MAX && endHours >= HOURS_MIN))
        throw new HourOutOfRangeException("Ending Time Hour Out of Range!");
    if (!(startMins <= MINUTE_MAX && startMins >= MINUTE_MIN))
        throw new MinuteOutOfRangeException("Starting Time Minute Out of    Range!");
    if (!(endMins <= MINUTE_MAX && endMins >= MINUTE_MIN))
        throw new MinuteOutOfRangeException("Ending Time Minute Out of Range!");
    if(!(timeDifference <= P_MAX && timeDifference >= P_MIN))
        throw new PercentageOutOfRangeException("Percentage Change Out of Range!");
    if (!(startTime < endTime))
        throw new StartEndException("Start Time Cannot Be Less Than End Time!");
}

Sólo una de mis clases de excepción personalizados, los demás tienen la misma estructura que éste


class HourOutOfRangeException
{
public:
        // param constructor
        // initializes message to passed paramater
        // preconditions - param will be a string
        // postconditions - message will be initialized
        // params a string
        // no return type
        HourOutOfRangeException(string pMessage) : message(pMessage) {}
        // GetMessage is getter for var message
        // params none
        // preconditions - none
        // postconditions - none
        // returns string
        string GetMessage() { return message; }
        // destructor
        ~HourOutOfRangeException() {}
private:
        string message;
};
¿Fue útil?

Solución

Si tiene varios tipos de excepción, y suponiendo que hay una jerarquía de excepciones (y todos los derivados públicamente de alguna subclase de std::exception,) comenzar desde la más específica y continuar más general:

try
{
    // throws something
}
catch ( const MostSpecificException& e )
{
    // handle custom exception
}
catch ( const LessSpecificException& e )
{
    // handle custom exception
}
catch ( const std::exception& e )
{
    // standard exceptions
}
catch ( ... )
{
    // everything else
}

Por otro lado, si usted está interesado sólo en el mensaje de error - throw misma excepción, dicen std::runtime_error con diferentes mensajes y, a continuación, catch que:

try
{
    // code throws some subclass of std::exception
}
catch ( const std::exception& e )
{
    std::cerr << "ERROR: " << e.what() << std::endl;
}

Asimismo, recuerda -. Tiro por el valor, la captura por la referencia [const]

Otros consejos

Se debe crear una clase de excepción base y tener todas sus excepciones específicas se deben a que:

class BaseException { };
class HourOutOfRangeException : public BaseException { };
class MinuteOutOfRangeException : public BaseException { };

A continuación, puede coger todos ellos en un solo bloque catch:

catch (const BaseException& e) { }

Si usted quiere ser capaz de GetMessage llamada, tendrá que o bien:

  • lugar que la lógica en BaseException, o
  • Hacer GetMessage una función miembro virtual en BaseException y anular en cada una de las clases de excepción derivados.

También podría considerar tener sus excepciones derivan de una de las excepciones de la biblioteca estándar, como std::runtime_error y utilizar la función miembro what() idiomática en lugar de GetMessage().

Derivar todas sus excepciones de un BaseException clase base común que tiene un método GetMessage() virtual.

A continuación, catch(const BaseException& e).

He tenido un problema similar en la actualidad, pero resultó que no necesitaba mi solución para resolver mi problema. Honestamente, no podía pensar en casos reales de uso (tala?), Y no he encontrado mucho uso para él en mi código.

De todos modos, este es un enfoque con listas de tipo (requiere C ++ 11). Creo que la ventaja de este enfoque es que no hay necesidad de tener una clase base común para excepciones personalizadas (excepto para std :: excepción, tal vez?). En otras palabras, no es intrusiva a su jerarquía de excepciones.

Puede haber algunos errores sutiles que no soy consciente de.

#include <type_traits>
#include <exception>

/// Helper class to handle multiple specific exception types
/// in cases when inheritance based approach would catch exceptions
/// that are not meant to be caught.
///
/// If the body of exception handling code is the same
/// for several exceptions,
/// these exceptions can be joined into one catch.
///
/// Only message data of the caught exception is provided.
///
/// @tparam T  Exception types.
/// @tparam Ts  At least one more exception type is required.
template <class T, class... Ts>
class MultiCatch;

/// Terminal case that holds the message.
/// ``void`` needs to be given as terminal explicitly.
template <>
class MultiCatch<void> {
 protected:
  explicit MultiCatch(const char* err_msg) : msg(err_msg) {}
  const char* msg;
};

template <class T, class... Ts>
class MultiCatch : public MultiCatch<Ts...> {
  static_assert(std::is_base_of<std::exception, T>::value, "Not an exception");

 public:
  using MultiCatch<Ts...>::MultiCatch;

  /// Implicit conversion from the guest exception.
  MultiCatch(const T& error) : MultiCatch<Ts...>(error.what()) {}  // NOLINT

  /// @returns The message of the original exception.
  const char* what() const noexcept {
    return MultiCatch<void>::msg;
  }
};

/// To avoid explicit ``void`` in the type list.
template <class... Ts>
using OneOf = MultiCatch<Ts..., void>;

/// Contrived example.
void foo() {
  try {
    bar();  // May throw three or more sibling or unrelated exceptions.
  } catch (const OneOf<IOError, OutOfMemory>& err) {
    log() << "External failure: " << err.what();

    throw;  // Throw the original exception.
  }
}

Cuando las plantillas no pueden, macros de salvar el día. La solución se toma de Boost . Todo se reduce a 7 líneas de código.

/// @file multicatch.hpp
#include <boost/preprocessor/variadic/to_list.hpp>
#include <boost/preprocessor/list/for_each.hpp>

/// Callers must define CATCH_BODY(err) to handle the error,
/// they can redefine the CATCH itself, but it is not as convenient. 
#define CATCH(R, _, T) \
  catch (T & err) {    \
    CATCH_BODY(err)    \
  }
/// Generates catches for multiple exception types
/// with the same error handling body.
#define MULTICATCH(...) \
  BOOST_PP_LIST_FOR_EACH(CATCH, _, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__))
// end of file multicatch.hpp

/// @file app.cc
#include "multicatch.hpp"

// Contrived example.
/// Supply the error handling logic.
#define CATCH_BODY(err)                        \
  log() << "External failure: " << err.what(); \
  throw;

void foo() {
  try {
    bar();  // May throw three or more sibling or unrelated exceptions.
  }
  MULTICATCH(IOError, OutOfMemory)
}

#undef CATCH_BODY

Me encuentro con el mismo problema y esto es lo que terminé con:

  std::shared_ptr<MappedImage> MappedImage::get(const std::string & image_dir,
                                                const std::string & name,
                                                const Packet::Checksum & checksum) {
    try {
      return std::shared_ptr<MappedImage>(images_.at(checksum));
    } catch (std::out_of_range) {
    } catch (std::bad_weak_ptr) {
    }
    std::shared_ptr<MappedImage> img =
      std::make_shared<MappedImage>(image_dir, name, checksum);
    images_[checksum_] = img;
    return img;
  }

En mi caso la función devuelve cuando no recibe una excepción. Así que en realidad no tienen que ver nada dentro de la captura, pero puedo hacer el trabajo fuera de la prueba.

#include <iostream> void test(int x)` { try{ if(x==1) throw (1); else if(x==2) throw (2.0); } catch(int a) { cout<<"It's Integer"; } catch(double b) { cout<<"it's Double"; } } int main(){ cout<<" x=1"; test(1); cout<<"X=2"; test(2.0); return 0; }`
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top