Return of a function a dynamic C ++ matrix

0

I have a function that performs some operations dynamically creating in its response a vector and a size matrix that depends on its inputs.

The problem and the basis of my query is that I have been able to get back the vector that is generated but not the matrix.

The prototype of the function is like this: k (matrix) and weights63 (vector) is the return and Q60,120 ... are inputs

void kapeso(double k[][3], double *pesos63, double Q60[3][3], double Q120[3][3], double Q180[3][3], double Q240[3][3], double Q300[3][3])

As you can see the first term is a matrix in which the number of rows is not specified but its columns are

This code works perfectly if we enter the size of the matrix from the main

But instead if I create a dynamic matrix and use the same prototype

As you can see, this error jumps in Visual Studio, an error that I searched but I do not see any sense, argument 1 does not change the type.

    
asked by Alvaro 01.06.2017 в 14:46
source

1 answer

0

Suppose a matrix such that:

int matriz[3][3];

and you fill in your positions with numbers from 1 to 9. In memory it would look like this:

1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
---------   ---------   ---------
  FILA 0     FILA 1       FILA 2

That is, the values of the matrix will occupy consecutive positions in the memory.

If now, instead, we have this:

int ** matriz = new int*[3];
for( int i=0; i<3; i++ )
   matriz[i] = new int[3];

And fill in the matrix, the result in memory will be rather:

MEMORIA 0x0000 0x0001 0x0002 ... 0x1000 0x1001 0x1002 ... 0x1020 0x1021 0x1022 ...
VALOR   0x1000 0x1020 0x1250 ...   1      2      3    ...   4      5      6    ...
        ^^^^^^ ^^^^^^ ^^^^^^      ^^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^
              Punteros              Valores fila 0          Valores fila 1

That is, although some features can be used equally in the language:

std::cout << matriz[1][2];

At the level of memory and machine instructions, they do not resemble each other at all.

If you do not need to pull dynamic memory better still use the matrices of the first example ... otherwise the most advisable would almost create a class Matriz that encapsulates the complexity associated with the management of dynamic memory. A possible silly example:

class Matriz
{
  double* m_datos;
  const int m_filas;
  const int m_columnas;

public:

  class MatrizRef
  {
    friend class Matriz;
    double* m_ptr;

    MatrizRef(double* ptr)
      : m_ptr(ptr)
    { }

  public:

    double& operator[](int index)
    { return m_ptr[index]; }
  };

  Matriz(int filas, int columnas)
    : m_filas(filas), m_columnas(columnas), m_datos(new double[filas*columnas])
  { }

  ~Matriz()
  { delete[] m_datos; }

  MatrizRef operator[](int index)
  { return MatrizRef(m_datos+(index*m_columnas)); }

  int Filas() const
  { return m_filas; }

  int Columnas() const
  { return m_columnas; }
};

And an example of use:

int main()
{
  Matriz m(3,3);
  for( int i=0; i<m.Filas(); i++ )
    for( int j=0; j<m.Columnas(); j++ )
      m[i][j] = i*3+j+1;

  for( int i=0; i<m.Filas(); i++ )
  {
    for( int j=0; j<m.Columnas(); j++ )
      std::cout << m[i][j] << ' ';
    std::cout << '\n';
  } 
}

That applied to your code would result in a function with the following signature:

void kapeso(Matriz& k, double *pesos63, Matriz& Q60, Matriz& Q120, Matriz& Q180, Matriz& Q240, Matriz& Q300)

Just in case someone thinks that the use of the nested class is totally inefficient, I invite you to verify that this is not the case. The following example:

// Función externa (para evitar optimizaciones en este punto)
extern void Func(int&);

int main()
{
  Matriz m(3,3);
  for( int i=0; i<m.Filas(); i++ )
    for( int j=0; j<m.Columnas(); j++ )
      m[i][j] = i*3+j+1;

  int total = 0;
  for( int i=0; i<m.Filas(); i++ )
  {
    for( int j=0; j<m.Columnas(); j++ )
      Func(m[i][j]);
  }
}

Generates the following assembly:

main:                                   # @main
    push    r14
    push    rbx
    push    rax
    mov     edi, 36
    call    operator new[](unsigned long)
    mov     rbx, rax
    movaps  xmm0, xmmword ptr [rip + .LCPI0_0] # xmm0 = [1,2,3,4]
    movups  xmmword ptr [rbx], xmm0
    movaps  xmm0, xmmword ptr [rip + .LCPI0_1] # xmm0 = [5,6,7,8]
    movups  xmmword ptr [rbx + 16], xmm0
    mov     dword ptr [rbx + 32], 9
    mov     rdi, rbx
    call    Func(int&)
    lea     rdi, [rbx + 4]
    call    Func(int&)
    lea     rdi, [rbx + 8]
    call    Func(int&)
    lea     rdi, [rbx + 12]
    call    Func(int&)
    lea     rdi, [rbx + 16]
    call    Func(int&)
    lea     rdi, [rbx + 20]
    call    Func(int&)
    lea     rdi, [rbx + 24]
    call    Func(int&)
    lea     rdi, [rbx + 28]
    call    Func(int&)
    mov     rdi, rbx
    add     rdi, 32
    call    Func(int&)
    mov     rdi, rbx
    call    operator delete[](void*)
    xor     eax, eax
    add     rsp, 8
    pop     rbx
    pop     r14
    ret
    mov     r14, rax
    mov     rdi, rbx
    call    operator delete[](void*)
    mov     rdi, r14
    call    _Unwind_Resume

As you can see, the compiler is able to eliminate the nested class and offer direct access to memory:

    mov     rdi, rbx         # Se carga en rdi el valor m_datos[0]
    call    Func(int&)       # Llamada a Func() 
    lea     rdi, [rbx + 4]   # Se carga en rdi m_datos[1] ( 4=sizeof(int) )
    call    Func(int&)
    lea     rdi, [rbx + 8]   # Se carga en rdi m_datos[2]
    call    Func(int&)
    lea     rdi, [rbx + 12]  # Se carga en rdi m_datos[3]
    call    Func(int&)
    # ...

The example can be verified here

    
answered by 01.06.2017 / 15:19
source