2010-11-24 33 views

Respuesta

54

int* test();

pero sería "más C++" usar vectores:

std::vector<int> test();

EDITAR
Voy a aclarar algún punto. Como mencionas C++, iré con los operadores new[] y delete[], pero es lo mismo con malloc/free.

En el primer caso, que voy a escribir algo como:

int* test() { 
    return new int[size_needed]; 
} 

pero no es una buena idea porque el cliente de su función no sabe realmente el tamaño de la matriz va a devolver, aunque el cliente puede desasignarlo de forma segura con una llamada al delete[].

int* theArray = test(); 
for (size_t i; i < ???; ++i) { // I don't know what is the array size! 
    // ... 
} 
delete[] theArray; // ok. 

Una mejor firma sería éste:

int* test(size_t& arraySize) { 
    array_size = 10; 
    return new int[array_size]; 
} 

Y su código de cliente sería ahora:

size_t theSize = 0; 
int* theArray = test(theSize); 
for (size_t i; i < theSize; ++i) { // now I can safely iterate the array 
    // ... 
} 
delete[] theArray; // still ok. 

Dado que este es C++, `std :: vector < T> es una solución ampliamente utilizada:

std::vector<int> test() { 
    std::vector<int> vector(10); 
    return vector; 
} 

Ahora usted no tiene que llamar delete[], ya que será manejado por el objeto, y se puede recorrer de forma segura con:

std::vector<int> v = test(); 
std::vector<int>::iterator it = v.begin(); 
for (; it != v.end(); ++it) { 
    // do your things 
} 

que es más fácil y más seguro.

+2

me gustaría ir con el retorno de una 'std :: vECTOR'. –

+8

Personalmente, creo que responder 'int * test();' a la pregunta "¿cómo devolver una matriz en un método C++?" [Sic] es engañoso si no explica que no devuelve una matriz pero un puntero. –

+0

Agregué algunas aclaraciones necesarias. – Simone

2

Bien, si desea devolver su matriz desde una función, debe asegurarse de que los valores no estén almacenados en la pila, ya que desaparecerán cuando salga de la función.

Por lo tanto, haga su matriz estática o asigne la memoria (o transfiérala pero su intento inicial es con un parámetro de vacío). Para su método Yo lo definiría como esto:

int *gnabber(){ 
    static int foo[] = {1,2,3} 
    return foo; 
} 
16

¿Cómo puedo devolver un array en un método C++ y ¿cómo debo declararlo? int [] test (void); ??

Esto suena como una pregunta simple, pero en C++ tiene bastantes opciones. En primer lugar, deberías preferir ...

  • std::vector<>, que crece dinámicamente a sin embargo muchos elementos que encuentro en tiempo de ejecución, o

  • std::array<> (introducida con C++ 11), que siempre almacena un número de elementos especificado en tiempo de compilación,

... ya que gestionan la memoria para usted, lo que garantiza un comportamiento correcto y simplificar considerablemente las cosas:

std::vector<int> fn() 
{ 
    std::vector<int> x; 
    x.push_back(10); 
    return x; 
} 

std::array<int, 2> fn2() // C++11 
{ 
    return {3, 4}; 
} 

void caller() 
{ 
    std::vector<int> a = fn(); 
    const std::vector<int>& b = fn(); // extend lifetime but read-only 
             // b valid until scope exit/return 

    std::array<int, 2> c = fn2(); 
    const std::array<int, 2>& d = fn2(); 
} 

La práctica de crear una referencia const a los datos devueltos a veces puede evitar una copia, pero normalmente sólo se puede confiar en la optimización del valor de retorno, o - para vector pero no array - mover la semántica (introducido con C++ 11) .

Si realmente desea utilizar un incorporado array (a diferencia de la clase de la biblioteca estándar llamado array mencionado anteriormente), una forma es para la persona que llama para reservar espacio y contar la función para utilizarla:

void fn(int x[], int n) 
{ 
    for (int i = 0; i < n; ++i) 
     x[i] = n; 
} 

void caller() 
{ 
    // local space on the stack - destroyed when caller() returns 
    int x[10]; 
    fn(x, sizeof x/sizeof x[0]); 

    // or, use the heap, lives until delete[](p) called... 
    int* p = new int[10]; 
    fn(p, 10); 
} 

Otra opción es envolver la matriz en una estructura, que - a diferencia de las matrices primas - son legales para volver por el valor de una función:

struct X 
{ 
    int x[10]; 
}; 

X fn() 
{ 
    X x; 
    x.x[0] = 10; 
    // ... 
    return x; 
} 

void caller() 
{ 
    X x = fn(); 
} 

a partir de lo anterior, si estás atascado utilizando C++ 03 es posible que desee generalizar en algo más cerca de la C++ 11 std::array:

template <typename T, size_t N> 
struct array 
{ 
    T& operator[](size_t n) { return x[n]; } 
    const T& operator[](size_t n) const { return x[n]; } 
    size_t size() const { return N; } 
    // iterators, constructors etc.... 
    private: 
    T x[N]; 
}; 

Otra opción es tener la función llamada asignar memoria en el montón:

int* fn() 
{ 
    int* p = new int[2]; 
    p[0] = 0; 
    p[1] = 1; 
    return p; 
} 

void caller() 
{ 
    int* p = fn(); 
    // use p... 
    delete[] p; 
} 

Para ayuda a simplificar la administración de los objetos de montón, muchos programadores de C++ usan "punteros inteligentes" que aseguran la eliminación cuando el puntero (s) del objeto abandona sus ámbitos. Con C++ 11:

std::shared_ptr<int> p(new int[2], [](int* p) { delete[] p; }); 
std::unique_ptr<int[]> p(new int[3]); 

Si está atrapado en C++ 03, la mejor opción es ver si la biblioteca de impulso está disponible en su máquina: proporciona boost::shared_array.

Otra opción es tener cierta memoria estática reservada por fn(), aunque esto NO ES HILO SEGURO, y significa que cada llamada a fn() sobrescribe los datos vistos por cualquier persona manteniendo los punteros de las llamadas anteriores. Dicho esto, puede ser conveniente (y rápido) para el código simple de un solo subproceso.

int* fn(int n) 
{ 
    static int x[2]; // clobbered by each call to fn() 
    x[0] = n; 
    x[1] = n + 1; 
    return x; // every call to fn() returns a pointer to the same static x memory 
} 

void caller() 
{ 
    int* p = fn(3); 
    // use p, hoping no other thread calls fn() meanwhile and clobbers the values... 
    // no clean up necessary... 
} 
+1

No creo que 'new [] int (10)' sea una nueva expresión válida. ¿Querías decir 'new int [10]'? –

+0

@Charles: probablemente, odio estar atrapado en C# todo el maldito día y luego tratar de responder algo aquí ... ahhhh ... ;-) Totalmente entiendo. –

9

No es posible devolver una matriz desde una función C++. 8.3.5 [dcl.fct]/6:

Las funciones no tendrán un tipo de retorno de la matriz o función de tipo [...]

alternativas más comúnmente son elegidos para devolver un valor de tipo de clase donde esa clase contiene una matriz, por ejemplo

struct ArrayHolder 
{ 
    int array[10]; 
}; 

ArrayHolder test(); 

O para devolver un puntero al primer elemento de una matriz asignada de forma estática o dinámica, la documentación debe indicar al usuario si necesita (y si es así cómo debería) desasignar la matriz que el puntero devuelto puntos a.

E.g.

int* test2() 
{ 
    return new int[10]; 
} 

int* test3() 
{ 
    static int array[10]; 
    return array; 
} 

Mientras que es posible para devolver una referencia o un puntero a una matriz, es muy rara ya que es una sintaxis más complejo con ninguna ventaja práctica sobre cualquiera de los métodos anteriores.

int (&test4())[10] 
{ 
     static int array[10]; 
     return array; 
} 

int (*test5())[10] 
{ 
     static int array[10]; 
     return &array; 
} 
-1

"¿Cómo puedo devolver una matriz en un c método ++ y cómo debe i declarar que int [] de prueba (void);? ??"

template <class X> 
    class Array 
{ 
    X  *m_data; 
    int m_size; 
public: 
    // there constructor, destructor, some methods 
    int Get(X* &_null_pointer) 
    { 
     if(!_null_pointer) 
     { 
      _null_pointer = new X [m_size]; 
      memcpy(_null_pointer, m_data, m_size * sizeof(X)); 
      return m_size; 
     } 
     return 0; 
    } 
}; 

sólo para int

class IntArray 
{ 
    int *m_data; 
    int m_size; 
public: 
    // there constructor, destructor, some methods 
    int Get(int* &_null_pointer) 
    { 
     if(!_null_pointer) 
     { 
      _null_pointer = new int [m_size]; 
      memcpy(_null_pointer, m_data, m_size * sizeof(int)); 
      return m_size; 
     } 
     return 0; 
    } 
}; 

ejemplo

Array<float> array; 
float *n_data = NULL; 
int  data_size; 
if(data_size = array.Get(n_data)) 
{  // work with array } 

delete [] n_data; 

ejemplo para int

IntArray array; 
int  *n_data = NULL; 
int  data_size; 
if(data_size = array.Get(n_data)) 
{ // work with array } 

delete [] n_data; 
Cuestiones relacionadas