c++ - valor - retornar una matriz en java
¿Cómo devolver una matriz desde una función? (5)
¿Cómo puedo devolver una matriz desde un método y cómo debo declararla?
int[] test(void); // ??
"¿cómo puedo devolver una matriz en un método de c ++ y cómo debo declararlo? int [] test (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;
}
};
solo 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;
¿Cómo puedo devolver una matriz en un método de c ++ y cómo debo declararlo? int [] test (void); ??
Esto suena como una pregunta simple, pero en C ++ tienes bastantes opciones. En primer lugar, deberías preferir ...
std::vector<>
, que crece dinámicamente con todos los elementos que encuentres en el tiempo de ejecución, ostd::array<>
(introducido con C ++ 11), que siempre almacena una cantidad de elementos especificados en tiempo de compilación,
... a medida que administran la memoria para usted, asegurando el comportamiento correcto y simplificando las cosas considerablemente:
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 solo puede confiar en la optimización del valor de retorno o, para vector
pero no en la array
, semántica de movimiento (presentada con C ++ 11).
Si realmente desea usar una matriz incorporada (distinta de la clase de biblioteca estándar denominada array
mencionada anteriormente), una de las formas es que la persona que llama reserva espacio y le dice a la función que la use:
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 en bruto, es legal para devolver 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();
}
Comenzando con lo anterior, si está atrapado usando C ++ 03, puede generalizarlo en algo más cercano a 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 hacer que la función llamada asigne 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 ayudar 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á atascado 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 THREAD SAFE, y significa que cada llamada a fn()
sobrescribe los datos vistos por cualquier persona que mantenga 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...
}
Bueno, si quieres devolver tu matriz desde una función, debes asegurarte de que los valores no estén almacenados en la pila, ya que desaparecerán cuando abandones la función.
Por lo tanto, haga que su matriz sea 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 lo definiría así:
int *gnabber(){
static int foo[] = {1,2,3}
return foo;
}
No es posible devolver una matriz desde una función de C ++. 8.3.5 [dcl.fct] / 6:
Las funciones no deben tener un tipo de retorno de tipo matriz o función [...]
Las alternativas más comúnmente elegidas son 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 estática o dinámicamente, la documentación debe indicar al usuario si necesita (y si es así cómo debería) desasignar la matriz a la que apunta el puntero devuelto.
P.ej
int* test2()
{
return new int[10];
}
int* test3()
{
static int array[10];
return array;
}
Si bien es posible devolver una referencia o un puntero a una matriz, es extremadamente raro ya que es una sintaxis más compleja sin ninguna ventaja práctica sobre ninguno de los métodos anteriores.
int (&test4())[10]
{
static int array[10];
return array;
}
int (*test5())[10]
{
static int array[10];
return &array;
}
int* test();
pero sería "más C ++" usar vectores:
std::vector< int > test();
EDITAR
Aclararé algún punto. Como mencionas C ++, iré con new[]
operadores new[]
y delete[]
, pero es lo mismo con malloc / free.
En el primer caso, escribirás 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 que está devolviendo, aunque el cliente puede desasignarlo con una llamada para 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 esta:
int* test(size_t& arraySize) {
array_size = 10;
return new int[array_size];
}
Y su código de cliente ahora sería:
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.
Como esto es C ++, `std :: vector <T> es una solución ampliamente utilizada:
std::vector<int> test() {
std::vector<int> vector(10);
return vector;
}
Ahora no tiene que llamar a delete[]
, ya que será manejado por el objeto, y puede iterarlo 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 seguro