2010-06-15 32 views
8

Tengo una estructura Foo. En pseudocódigo:C++: Devuelve NULL en lugar de struct

def FindFoo: 
    foo = results of search 
    foundFoo = true if a valid foo has been found 

    return foo if foundFoo else someErrorCode 

¿Cómo puedo lograr esto en C++?

Editado para eliminar numerosas imprecisiones.

+0

Su tipo de devolución es inconsistente. Si la búsqueda tiene éxito, es 'Foo &'; si falla, es 'ErrorCode'. Una solución a este problema sería devolver un 'Foo *', que apunta al elemento que se encontró, o es NULL si no se encontró ningún elemento. – pyon

Respuesta

12

Los objetos C++ nunca pueden ser nulos o vacíos. Los punteros pueden contener un valor de puntero nulo que indica que apuntan a nada.

La solución típica sería lanzar una excepción. De lo contrario, use un puntero; solo asegúrate de no estar devolviendo la dirección de un temporal.

No recomendaría intentar enseñarte C++ con conocimiento de otros idiomas, te lastimarás. Tome una good beginner-level book, es la mejor manera de aprender.

+7

+1 para "No recomendaría intentar enseñarte C++ con conocimiento de otros idiomas" –

+1

Creo que la solución típica sería imitar el STL que devuelve un objeto similar a un iterador que apunta a objetos no válidos (uno más allá del final del contenedor). –

+0

@Martin: Solo diré que es un puntero más generalizado y te encontraré a mitad de camino. : P – GManNickG

1

Eso tampoco funciona en C#. Deberías devolver un puntero a Foo.

+3

@Dura, la pregunta es "¿Cómo puedo lograr esto en C++?" –

+0

¡También tiene una etiqueta C#! – nevets1219

0

No puede hacer esto en C# tampoco; deberá devolver new Foo(), no null para hacer feliz al compilador.

Lo mismo que en el caso de C++: necesita crear una instancia de una estructura si va a devolver por valor. Si no es así, debe regresar con un puntero (en cuyo caso sería new ing o devolver un puntero a uno asignado de otra manera, lo que genera una semántica desordenada de transferencia de propiedad en la ecuación).

EDIT: según su actualización. Parece que desea devolver un valor meta o un valor meta nulo que indique "no encontrado". Esto se puede hacer de varias maneras:

  1. throw si no funciona, por lo demás incondicionalmente devolver un valor
  2. devolver un puntero - pero esto deja la responsabilidad de delet ing hacia arriba en el aire si no es algo que va a permanecer en la memoria a largo plazo
  3. envuélvalo en un objeto envoltorio [plantilla] que maneja la condicionalidad de la misma manera que Nullable<T> .NET (voy a dejar que alguien repique con la derecha ACTUALIZACIÓN: @Mike Seymour dice que es boost::optional<foo>)
  4. usa el objeto nulo p attern para devolver un valor apropiado, que hace lo correcto cuando se trata como un resut válido en el lado del cliente
1

Una forma de hacerlo es a devolver un puntero a una foo:

public Foo* findFoo() 
{ 
    return fooFound ? new fooResult() : NULL; 
} 

Otra posibilidad para definir un NullFoo de algún tipo, posiblemente como struct extendiendo Foo con una implementación vacía. Para obtener más información sobre la última idea, puede leer sobre Null Object Pattern.

Editar: La pregunta modificada es algo diferente, y como otras personas han mencionado, es mejor que haga una excepción en lugar de hacer cualquiera de las anteriores.

+0

fooFound es solo la condición para verificar, fooResult es lo que se devuelve. –

+1

Otra posibilidad es 'boost :: optional '. Entonces no tienes que recordar borrarlo. –

+0

@Mike Seymour: gracias - insistiendo en que para completar mi respuesta # 3 –

1

No es posible en C++ sin recurrir a punteros o una solución de biblioteca fuera de la biblioteca estándar.(Boost no forma parte de la biblioteca estándar, es una solución de terceros).

En C#, puede usar un Nullable<Foo>.

Contrariamente a los comentarios de Billy, las estructuras son tipos de valor, no hacer referencia a tipos y anulables se puede aplicar a cualquier tipo de valor, no sólo los muebles empotrados. Lo siguiente compila muy bien:

struct Test { 
    int Blah; 
} 
void Main() { 
    System.Nullable<Test> proof; 
} 
+0

No, no puedes. En primer lugar, Nullable solo es válido en los tipos internos, no en los tipos definidos por el usuario como 'Foo'. En segundo lugar, incluso si fuera válido, no le ayudaría de todos modos porque las referencias de objetos ya pueden ser nulas. Y finalmente, el OP pidió devolver un código de error, no NULO. –

+0

@Billy: Fácil en -1. struct significa tipo de valor, no de referencia, y usted puede hacer un tipo de valor que puede ser anulado; ese es el punto completo –

+0

+1 corregido objetivamente en el bit de .NET. Lo mismo ocurre con el bit de C++, aunque omite maneras de pasar a punteros [como el patrón Objeto nulo, lanzar, envolver en un impulso :: opcional]. + 1 como respuesta no fuera del tema o incorrecta. Muchas más respuestas inapelables e incompletas se han subido de nivel aquí. –

4

Lanza una excepción. Para eso están para.

3

Puede consultar boost::optional y ver si se ajusta a sus necesidades. Sin embargo:

retorno foo si foundFoo demás someErrorCode

Esto me hace pensar que tal vez sería mejor lanzar una excepción si no encuentra foo.

1

¿No es encontrar un foo realmente una situación excepcional? Entonces lanza una excepción. Esperar a no encontrar foo? haga que la función devuelva un código de error y pase el foo hacia afuera a través de un parámetro de referencia, donde foo solo es válido si la función no devuelve ningún error.

+0

Ese sería mi enfoque. Manteniendo las cosas simples, y las dependencias mínimas. –