2010-07-01 10 views
20

Estoy usando códigos de error para manejar errores en mi proyecto de C++. El problema es cómo devolver los códigos de error de una función que se supone que devuelve alguna variable/objeto.Cuál es el enfoque correcto para devolver códigos de error en C++

Considera:

long val = myobject.doSomething(); 

Aquí, myObject es un objeto de alguna clase. Si doSomething function encuentra alguna condición de error, ¿cómo debería notificar a la persona que llama (sin usar excepciones)?

soluciones posibles:

  1. tiene un miembro de datos (por ejemplo err_) en la clase que se puede comprobar por la persona que llama. Pero sería inseguro en una aplicación multihilo compartir el mismo objeto y llamar a la misma función.
  2. Usa alguna variable de error global, de nuevo el mismo problema en un entorno de subprocesos múltiples.

¿Cómo puedo notificar a la persona que llama acerca de alguna condición de error?

+0

Relacionado: [Error de resultado y código de la convención C++ int foo (...)] (http://stackoverflow.com/questions/1882047/convention-result-and-code-error-c-int-foo) –

+9

Usted ' Acabo de descubrir el motivo # 1 para las excepciones, por cierto. ¿Pero por qué también está rechazando la otra solución común para informar errores, que es devolver un código de error y usar parámetros externos para los resultados de las funciones? – MSalters

+0

@MSalters No estoy usando el otro enfoque que mencionaste porque parte del código ya está hecho y eso se agregaría a la inconsistencia en el estilo – Jeet

Respuesta

4

Puede pasar la variable como referencia y devolver el código de error en ella.

+2

La práctica más común es pasar la bruja variable obtendrá el resultado por referencia y devolverá el código de error. – adf88

+2

Esa es una práctica común pero desagradable. La expresión esperada es mucho mejor. –

3

Es común devolver un código de devolución/error y poner a disposición una propiedad o miembro con los resultados.

int retCode = myobject.doSomething(); 
if (retCode < 0){ //Or whatever you error convention is 
    //Do error handling 
}else{ 
    long val = myobject.result; 
} 

También es común que pasar en un puntero que se establece en el valor de retorno, y devolver el código de retorno/error. (Ver HrQueryAllRows).

long val = INIT_VAL; 
int retCode = myObject.doSomething(&val); 

if (retCode < 0){ 
    //Do error handling 
}else{ 
    //Do something with val... 
} 
2

Devuelve un identificador de error. Haga que un administrador de errores guarde los códigos de error y la información adicional (por ejemplo, ERROR_INVALID_PARAMETER y pares de nombre-valor como ParameterName="pszFileName"). Se puede acceder a esta información usando el mango. La persona que llama puede verificar el identificador de error contra NO_ERROR_HANDLE. Si es verdadero, no ocurrió ningún error. La persona que llama puede aumentar la información de error y pasar el controlador a la pila. El administrador de errores puede ser uno para el proceso o uno para cada hilo.

2

Tiene tres opciones:

crear una clase que contiene el valor de retorno y un posible código de error.

Use algo como boost :: optional para el valor de retorno, que permite respuestas no válidas.

Pasa una referencia a una variable y devuelve cualquier posible código de error dentro de esa.

2

La práctica más común es devolver el código de error

long result; 
int error = some_obj.SomeMethod(&result); 

o devolver un valor que indica que hubo un error:

long result = some_obj.SomeMethod(); 
if (result < 0) error = some_obj.GetError(); 
+1

El método 'GetError()' realmente limita su capacidad para escribir código simultáneo de calidad (está guardando el estado de una llamada a método en su objeto). – weberc2

28

Hacer una plantilla llamada, por ejemplo, Maybe que parametrizada por su tipo de valor de retorno.Cada vez que regresa un valor, lo envuelve en esta plantilla como esta:

Maybe<long> result = object.somemethod(); 

La plantilla Maybe tendría una forma de ser instanciado con un código de error (probablemente un método estático):

return Maybe<long>::error(code); 

Pero normalmente se acaba de ser devuelto con el valor:

Maybe<long> retval; 
retval = 15; 
return retval; 

(que tendría que, por supuesto, anular los constructores apropiados, operadores de asignación, etc.)

En el lado del cliente, llama a un método para verificar el error.

Maybe<long> result = object.somemethod(); 
if (result.is_error) 
{ 
    ... handle the error ... 
} 
else 
{ 
    ... use the result ... 
} 

vez que había necesidad de los operadores adecuados, definidos a utilizar Maybe<long> dondequiera que haya un long requerido.

Esto suena como un montón de trabajo, pero realmente el trabajo se hace una vez en la fabricación de una buena, Maybe plantilla a prueba de balas. También tendrá que hacer algunos ajustes de rendimiento para evitar gastos generales desagradables. Si desea hacerlo más flexible, puede parametrizarlo tanto en el tipo de valor devuelto como en el tipo de error. (Esto es solo un pequeño aumento en la complejidad.)

+6

+1 - Esto es bastante elegante. Puede ampliarlo bien agregando un operador de conversión a 'bool' para que pueda escribir' if (result) 'en vez de' if (! Result.is_error) 'y agregue una excepción al acceder al resultado si el resultado es un error . Sé que arrojar una excepción es lo que estamos evitando, pero este sería un buen caso. –

+1

Yo diría que acceder al valor cuando es un estado de error es una situación ideal para arrojar una excepción, en realidad, ya que muestra un error obvio del programador: no se devuelve el error de comprobación. –

+0

@JUST: Y si piensa esto un poco más, llegará a arrojar excepciones de inmediato en lugar de confiar en los programadores para que comprueben los valores devueltos. – sbi

2

Puede usar excepciones.

+6

-1, lea la pregunta nuevamente. – adf88

+1

Antes de utilizar una excepción, debe preguntarse "¿es esto realmente una situación ** excepcional" que justifica el aumento masivo de gastos indirectos que conlleva lanzar una excepción?" –

+3

@ adf88: Acabo de leer la pregunta, y sigo pensando que swegi dio en el clavo.' + 1' de mí. – sbi

2

sugeriría siguiente:

class foo { 
public: 
    long doSomething(); 
    long doSomething(error_code &e); 
}; 

Dónde error_code es algún tipo de error que contiene. Puede ser un número entero o mejor algo basado en boost::system::error_code.

, y le proporcionamos dos funciones:

  1. Primera versión lanza el error, por ejemplo tirar boost::system::system_error que se crea desde boost::system::error_code.
  2. Segundo devuelve el código de error en e.
0

definen todos los códigos de error en un Archivo. según la categoría de error, puede devolver el código de error y la persona que llama puede decidir qué salió mal y la persona que llama puede devolver su propio código de error.

por ejemplo

#define FILE_ERROR  1 
#define SANITY_ERROR  2 

int WriteToFile(char* Data, int iErrorCode) 
{ 
    char* FileName; 

    if (!FileOpen(FileName, &iErrorCode)) 
    { 
    //Analyze error code and make decision on what to ignore or terminate 
    iErrorCode = FILE_ERROR; 
    return 0; 
    } 

} 

int FileOpen(char* FileName, int* iErrorCode) 
{ 

    if (FileName == null) 
    { 
     iErrorCode = SANITY_ERROR; 
     return 0; 
    } 

    ///// next code blocks 
    return 1; 
} 
0

Puede devolver una std::pair sujetando a la vez un código de error (o un objeto error) y el objeto de retorno deseado. El objeto de interés necesita un constructor o valor predeterminado para que pueda devolver algo incluso cuando se encuentre un error.

Cuestiones relacionadas