Память для адреса указателя время от времени изменяется до и после возврата функции - PullRequest
0 голосов
/ 21 октября 2019

Память по указанному адресу не идентична до и после возврата функции, и основа для этого поведения неясна. Вызов функции несколько раз будет время от времени приводить к правильному результату;однако, огромная доля времени, память была изменена.

Необходимо надежно возвращать простой массив C / C ++ float (в отличие от std :: vector / array и т. д.)

#include <iostream>
#include <Eigen/Dense>

using namespace Eigen;

float* derive_inverse(float* wasm_memory_address, int size) {

  MatrixXf matrix_from_memory = Map<Matrix<float, Dynamic, Dynamic, RowMajor> >(wasm_memory_address, size, size);

  std::cout << '\n';
  std::cout << "Matrix" << '\n';
  std::cout << matrix_from_memory << '\n' << '\n';

  MatrixXf inverse = matrix_from_memory.inverse();

  std::cout << "Inverse" << '\n';
  std::cout << inverse << '\n' << '\n';

  float* vc = inverse.data();

  std::cout << "inverse address prior to return: " << vc << '\t' << '\n';
  std::cout << "first few entries (column major order):" << '\n';
  std::cout << vc[0] << '\t' << vc[1] << '\t' << vc[2] << '\n' << '\n';

  return vc;
}

int main() {

  float numbers[25] = { 1, 8, -9, 7, 5, 0, 1, 0, 4, 4, 0, 0, 1, 2, 5, 0, 0, 0, 1, -5, 0, 0, 0, 0, 1};
  float* inverse = derive_inverse(&numbers[0], 5);

  std::cout << "inverse address following return: " << inverse << '\t' << '\n';
  std::cout << "first few entries (column major order):" << '\n';
  std::cout << inverse[0] << '\t' << inverse[1] << '\t' << inverse[2] << '\n' << '\n';

  std::cout << "entire inverse matrix following return:" << '\n';
   for (int col = 0; col < 5; col++) {
     for (int row = 0; row < 5; row++) {
       int index = row * 5 + col;
       std::cout << inverse[row * 5 + col] << '\t';
     }
     std::cout << '\n';
   }
   std::cout << '\n';
}

Пример последовательных вызовов, приводящих к ошибочным и правильным результатам:

$ ./foo

Matrix
 1  8 -9  7  5
 0  1  0  4  4
 0  0  1  2  5
 0  0  0  1 -5
 0  0  0  0  1

Inverse
  1  -8   9   7  17
  0   1   0  -4 -24
  0   0   1  -2 -15
  0   0   0   1   5
  0   0   0   0   1

inverse address prior to return: 0x7ff5c8500ba0 
first few entries (column major order):
1   0   0

inverse address following return: 0x7ff5c8500ba0    
first few entries (column major order):
0   -3.68935e+19    0

entire inverse matrix following return:
0   -8  9   7   17  
-3.68935e+19    1   0   -4  -24 
0   0   1   -2  -15 
-3.68935e+19    0   0   1   5   
2.52234e-44 0   0   0   1   

$ ./foo

Matrix
 1  8 -9  7  5
 0  1  0  4  4
 0  0  1  2  5
 0  0  0  1 -5
 0  0  0  0  1

Inverse
  1  -8   9   7  17
  0   1   0  -4 -24
  0   0   1  -2 -15
  0   0   0   1   5
  0   0   0   0   1

inverse address prior to return: 0x7f96afd000a0 
first few entries (column major order):
1   0   0

inverse address following return: 0x7f96afd000a0    
first few entries (column major order):
1   0   0

entire inverse matrix following return:
1   -8  9   7   17  
0   1   0   -4  -24 
0   0   1   -2  -15 
0   0   0   1   5   
0   0   0   0   1

1 Ответ

3 голосов
/ 21 октября 2019

Ваша функция возвращает указатель на внутренние данные объекта, который не существует после возврата из функции. Разыменование этого указателя в вызывающей функции вызывает неопределенное поведение.

float* vc = inverse.data();   // inverse is not alive after the function returns.

...


return vc;  // The returned pointer becomes a dangling pointer once the function returns.

Один из способов решения этой проблемы - возврат объекта вместо указателя на внутренние данные.

MatrixXf derive_inverse(float* wasm_memory_address, int size) {
   ...

   return inverse;
}
...