如何创建Eigen::Ref向量?引用Eigen::MatrixXd非连续行遇异常求解
Hey there! Let's figure out why all your Eigen::Ref entries are pointing to the last row of your matrix, and how to fix this so you can safely reference non-continuous rows without copying data.
What's Causing the Problem?
This issue boils down to misunderstanding Eigen's expression templates and temporary object lifetimes, combined with incorrect usage of Eigen::Ref:
- Temporary Expression Objects: When you call
P.row(i), you don't get a standalone vector—you get anEigen::RowXpr, which is an expression template. It doesn't store data itself; it's just a view pointing to the original matrix's row. - Incorrect Ref Binding: If your code was storing these views into a
vector<Eigen::Ref<...>>incorrectly (e.g., copying the row to a local temporary variable first, then bindingRefto that temp), all refs end up pointing to the same temp memory. As you loop, that temp gets overwritten with the last row, so all refs show that value. - Ref's Continuous Memory Assumption:
Eigen::Refis designed for continuous memory blocks. While individual rows are continuous, if you're not binding directly to the original row's memory (or using the wrong template parameters), you can end up with invalid or duplicated references.
Fixes That Work
Based on your goal—frequently selecting rows, no data copying, read-only access—here are three solid solutions:
Solution 1: Use ConstMap for Row Views
Since your matrix is row-major, each row is a continuous block of memory. Eigen::ConstMap lets you bind directly to that block without copying:
#include <Eigen/Dense> #include <vector> int main() { Eigen::MatrixXd P(5, 3); // Example row-major matrix P << 1,2,3, 4,5,6, 7,8,9, 10,11,12, 13,14,15; std::vector<int> selected_rows = {0, 2, 4}; // Rows we want to reference std::vector<Eigen::VectorXd::ConstMapType> row_refs; for (int i : selected_rows) { // Bind directly to the start of row i, with length equal to number of columns row_refs.emplace_back(P.row(i).data(), P.cols()); } // Test output: Should print [1 2 3], [7 8 9], [13 14 15] for (const auto& ref : row_refs) { std::cout << ref.transpose() << "\n"; } return 0; }
- Pros: Zero data copying, maximum performance, type-safe.
- Critical Note: Ensure the original matrix
Poutlives yourrow_refs—don't resize or destroyPwhile using the refs.
Solution 2: Use IndexedView for a Single View of Selected Rows
If you don't need individual row refs (just a single view of all selected rows), Eigen::IndexedView is the cleanest, most idiomatic approach:
#include <Eigen/Dense> #include <vector> // Function that accepts the view (no copying!) void process_rows(const Eigen::Ref<const Eigen::MatrixXd>& rows) { std::cout << "Processing selected rows:\n" << rows << "\n"; } int main() { Eigen::MatrixXd P(5, 3); P << 1,2,3, 4,5,6, 7,8,9, 10,11,12, 13,14,15; std::vector<int> selected_rows = {0, 2, 4}; // Convert selected indices to Eigen's ArrayXi Eigen::ArrayXi indices(selected_rows.size()); for (size_t i = 0; i < selected_rows.size(); ++i) { indices(i) = selected_rows[i]; } // Create a view of the selected rows (no data copied!) auto selected_view = P(indices, Eigen::all); process_rows(selected_view); return 0; }
- Pros: No need to manage a vector of refs—just pass a single view to your function. Eigen handles the non-continuous indexing efficiently.
- Tip: Use
const Eigen::Ref<const Eigen::MatrixXd>to accept the view in your function, avoiding template bloat.
Solution 3: Correctly Use vector<Eigen::Ref<const Eigen::VectorXd>>
If you really want a vector of Eigen::Ref, make sure you bind directly to the original matrix's rows (no temp variables!) and use const refs (since you don't need to modify the matrix):
#include <Eigen/Dense> #include <vector> int main() { Eigen::MatrixXd P(5, 3); P << 1,2,3, 4,5,6, 7,8,9, 10,11,12, 13,14,15; std::vector<int> selected_rows = {0, 2, 4}; std::vector<Eigen::Ref<const Eigen::VectorXd>> row_refs; for (int i : selected_rows) { // Bind directly to the original row—no copying! row_refs.push_back(P.row(i)); } // Test output for (const auto& ref : row_refs) { std::cout << ref.transpose() << "\n"; } return 0; }
- Why This Fixes It: Your original mistake was likely either using non-const refs unnecessarily, or copying rows to a temp variable first (which made all refs point to the same temp memory).
Key Takeaways
- Lifetime Matters: Always ensure your original matrix
Pexists longer than any references/views you create from it—otherwise you'll get dangling references and undefined behavior. - Avoid Temp Copies: Never bind
Refto a temporary row copy (likeEigen::VectorXd temp = P.row(i);). Always reference the original matrix directly. - Prefer Idiomatic Eigen: For non-continuous row selection,
IndexedViewis the most maintainable and efficient option recommended by Eigen's docs.
内容的提问来源于stack exchange,提问作者yfi

