mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Fix dangling reference in IndexedView with expression indices
libeigen/eigen!2335 Closes #1943
This commit is contained in:
committed by
Rasmus Munk Larsen
parent
624ab58e8d
commit
b7f6aed1b9
@@ -125,6 +125,15 @@ struct SymbolicExpressionEvaluator<FixedInt<N>, SizeAtCompileTime, void> {
|
|||||||
// Handling of generic indices (e.g. array)
|
// Handling of generic indices (e.g. array)
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Detect Eigen expression types that are not plain objects (Matrix/Array).
|
||||||
|
// These types may hold internal references to temporaries and must be evaluated before storing.
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct is_eigen_index_expression : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_eigen_index_expression<T, std::enable_if_t<!std::is_same<T, typename T::PlainObject>::value>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
// Potentially wrap indices in a type that is better-suited for IndexedView evaluation.
|
// Potentially wrap indices in a type that is better-suited for IndexedView evaluation.
|
||||||
template <typename Indices, int NestedSizeAtCompileTime, typename EnableIf = void>
|
template <typename Indices, int NestedSizeAtCompileTime, typename EnableIf = void>
|
||||||
struct IndexedViewHelperIndicesWrapper {
|
struct IndexedViewHelperIndicesWrapper {
|
||||||
@@ -132,6 +141,15 @@ struct IndexedViewHelperIndicesWrapper {
|
|||||||
static const type& CreateIndexSequence(const Indices& indices, Index /*nested_size*/) { return indices; }
|
static const type& CreateIndexSequence(const Indices& indices, Index /*nested_size*/) { return indices; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Specialization for Eigen expression types (Reshaped, Block, CwiseOp, etc.) used as indices.
|
||||||
|
// These may hold dangling references to temporaries if not evaluated.
|
||||||
|
template <typename Indices, int NestedSizeAtCompileTime>
|
||||||
|
struct IndexedViewHelperIndicesWrapper<Indices, NestedSizeAtCompileTime,
|
||||||
|
std::enable_if_t<is_eigen_index_expression<Indices>::value>> {
|
||||||
|
using type = typename Indices::PlainObject;
|
||||||
|
static type CreateIndexSequence(const Indices& indices, Index /*nested_size*/) { return indices.eval(); }
|
||||||
|
};
|
||||||
|
|
||||||
// Extract compile-time and runtime first, size, increments.
|
// Extract compile-time and runtime first, size, increments.
|
||||||
template <typename Indices, typename EnableIf = void>
|
template <typename Indices, typename EnableIf = void>
|
||||||
struct IndexedViewHelper {
|
struct IndexedViewHelper {
|
||||||
|
|||||||
@@ -840,6 +840,61 @@ void check_tutorial_examples() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regression test for bug #1943: IndexedView with temporary expression indices.
|
||||||
|
void check_expression_indices() {
|
||||||
|
MatrixXd m(3, 4);
|
||||||
|
m << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12;
|
||||||
|
|
||||||
|
// Reshaped temporary as column index (was segfault before fix).
|
||||||
|
{
|
||||||
|
auto view = m(all, Array<int, 1, 1>{0}.reshaped());
|
||||||
|
VectorXd result = view;
|
||||||
|
VERIFY_IS_APPROX(result, m.col(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block expression as index.
|
||||||
|
{
|
||||||
|
ArrayXi idx(3);
|
||||||
|
idx << 0, 1, 2;
|
||||||
|
auto view = m(all, idx.head(2));
|
||||||
|
MatrixXd result = view;
|
||||||
|
VERIFY_IS_APPROX(result, m.leftCols(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// CwiseBinaryOp expression as index.
|
||||||
|
{
|
||||||
|
Array<int, 2, 1> base;
|
||||||
|
base << 0, 1;
|
||||||
|
auto view = m(all, base + 0);
|
||||||
|
MatrixXd result = view;
|
||||||
|
VERIFY_IS_APPROX(result, m.leftCols(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse expression as index.
|
||||||
|
{
|
||||||
|
Array<int, 3, 1> idx;
|
||||||
|
idx << 2, 1, 0;
|
||||||
|
auto view = m(all, idx.reverse());
|
||||||
|
MatrixXd result = view;
|
||||||
|
MatrixXd expected(3, 3);
|
||||||
|
expected << m.col(0), m.col(1), m.col(2);
|
||||||
|
VERIFY_IS_APPROX(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1D vector indexed view (VectorIndexedViewSelector path).
|
||||||
|
{
|
||||||
|
VectorXd v(5);
|
||||||
|
v << 10, 20, 30, 40, 50;
|
||||||
|
ArrayXi idx(3);
|
||||||
|
idx << 4, 2, 0;
|
||||||
|
auto view = v(idx.reverse());
|
||||||
|
VectorXd result = view;
|
||||||
|
VectorXd expected(3);
|
||||||
|
expected << 10, 30, 50;
|
||||||
|
VERIFY_IS_APPROX(result, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void check_aliasing() {
|
void check_aliasing() {
|
||||||
Eigen::Vector<float, 5> z = {0.0f, 1.1f, 2.2f, 3.3f, 4.4f};
|
Eigen::Vector<float, 5> z = {0.0f, 1.1f, 2.2f, 3.3f, 4.4f};
|
||||||
std::vector<int> left_indices = {0, 1, 3, 4};
|
std::vector<int> left_indices = {0, 1, 3, 4};
|
||||||
@@ -854,6 +909,7 @@ EIGEN_DECLARE_TEST(indexed_view) {
|
|||||||
CALL_SUBTEST_1(check_indexed_view());
|
CALL_SUBTEST_1(check_indexed_view());
|
||||||
}
|
}
|
||||||
CALL_SUBTEST_1(check_tutorial_examples());
|
CALL_SUBTEST_1(check_tutorial_examples());
|
||||||
|
CALL_SUBTEST_1(check_expression_indices());
|
||||||
CALL_SUBTEST_1(check_aliasing());
|
CALL_SUBTEST_1(check_aliasing());
|
||||||
|
|
||||||
// static checks of some internals:
|
// static checks of some internals:
|
||||||
|
|||||||
Reference in New Issue
Block a user