Reputation: 686
I have following code that shrinks an Eigen MatrixXd by removing the last line. Anyway, that seems to corrupt the matrix. Also valgrind is very upset on that code. What is the proper way to perform that task?
#include <Eigen/Core>
#include <iostream>
int main() {
Eigen::MatrixXd A(3, 4);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; j++)
A(i, j) = i * j + i + j + 5;
std::cout << "A = \n" << A << std::endl;
A = A.block(0, 0, 2, 4);
std::cout << "A = \n" << A << std::endl;
return 0;
}
This code produces the following output on my machine (note 5 became 0)
A =
5 6 7 8
6 8 10 12
7 10 13 16
A =
0 6 7 8
6 8 10 12
Upvotes: 3
Views: 1431
Reputation: 44023
Eigen::Block<...>
(which the block()
member function returns) does not make a copy of the values involved but acts as a reference to part of the matrix. You can see this with
A.block(0, 0, 2, 4) *= 2; // this will change A
Because of this, an Eigen::Block
object remains valid only as long as the underlying matrix does not relocate its values, which it will if you assign something with a different geometry to it (such as A.block(0, 0, 2, 4)
). Once the underlying matrix has released its pre-assignment memory, using the Block
object constitutes use-after-free and causes undefined behavior, and the assignment operator will, of course, attempt to read the values from the then-defunct Block
.
As you have found out yourself in the meantime, you can use
A.conservativeResize(2, 4);
for your particular case, because you want to shrink towards the upper left corner. For the general case, you can use (for example)
A = A.block(1, 1, 2, 3).eval();
.eval()
forces immediate instead of lazy evaluation, which in this case essentially means that a temporary copy of the block is made and then assigned to the matrix. More detail about all this can be found here in the Eigen documentation.
Upvotes: 4