mirror of
https://gitlab.com/libeigen/eigen.git
synced 2024-12-21 07:19:46 +08:00
150 lines
6.9 KiB
Plaintext
150 lines
6.9 KiB
Plaintext
namespace Eigen {
|
|
|
|
/** \page TopicPitfalls Common pitfalls
|
|
|
|
|
|
\section TopicPitfalls_template_keyword Compilation error with template methods
|
|
|
|
See this \link TopicTemplateKeyword page \endlink.
|
|
|
|
|
|
\section TopicPitfalls_aliasing Aliasing
|
|
|
|
Don't miss this \link TopicAliasing page \endlink on aliasing,
|
|
especially if you got wrong results in statements where the destination appears on the right hand side of the expression.
|
|
|
|
|
|
\section TopicPitfalls_alignment_issue Alignment Issues (runtime assertion)
|
|
|
|
%Eigen does explicit vectorization, and while that is appreciated by many users, that also leads to some issues in special situations where data alignment is compromised.
|
|
Indeed, prior to C++17, C++ does not have quite good enough support for explicit data alignment.
|
|
In that case your program hits an assertion failure (that is, a "controlled crash") with a message that tells you to consult this page:
|
|
\code
|
|
http://eigen.tuxfamily.org/dox/group__TopicUnalignedArrayAssert.html
|
|
\endcode
|
|
Have a look at \link TopicUnalignedArrayAssert it \endlink and see for yourself if that's something that you can cope with.
|
|
It contains detailed information about how to deal with each known cause for that issue.
|
|
|
|
Now what if you don't care about vectorization and so don't want to be annoyed with these alignment issues? Then read \link getrid how to get rid of them \endlink.
|
|
|
|
|
|
\section TopicPitfalls_auto_keyword C++11 and the auto keyword
|
|
|
|
In short: do not use the auto keywords with %Eigen's expressions, unless you are 100% sure about what you are doing. In particular, do not use the auto keyword as a replacement for a \c Matrix<> type. Here is an example:
|
|
|
|
\code
|
|
MatrixXd A, B;
|
|
auto C = A*B;
|
|
for(...) { ... w = C * v; ...}
|
|
\endcode
|
|
|
|
In this example, the type of C is not a \c MatrixXd but an abstract expression representing a matrix product and storing references to \c A and \c B.
|
|
Therefore, the product of \c A*B will be carried out multiple times, once per iteration of the for loop.
|
|
Moreover, if the coefficients of `A` or `B` change during the iteration, then `C` will evaluate to different values as in the following example:
|
|
|
|
\code
|
|
MatrixXd A = ..., B = ...;
|
|
auto C = A*B;
|
|
MatrixXd R1 = C;
|
|
A = ...;
|
|
MatrixXd R2 = C;
|
|
\endcode
|
|
for which we end up with `R1` ≠ `R2`.
|
|
|
|
|
|
Here is another example leading to a segfault:
|
|
\code
|
|
auto C = ((A+B).eval()).transpose();
|
|
// do something with C
|
|
\endcode
|
|
The problem is that \c eval() returns a temporary object (in this case a \c MatrixXd) which is then referenced by the \c Transpose<> expression.
|
|
However, this temporary is deleted right after the first line, and then the \c C expression references a dead object.
|
|
One possible fix consists in applying \c eval() on the whole expression:
|
|
\code
|
|
auto C = (A+B).transpose().eval();
|
|
\endcode
|
|
|
|
The same issue might occur when sub expressions are automatically evaluated by %Eigen as in the following example:
|
|
\code
|
|
VectorXd u, v;
|
|
auto C = u + (A*v).normalized();
|
|
// do something with C
|
|
\endcode
|
|
Here the \c normalized() method has to evaluate the expensive product \c A*v to avoid evaluating it twice.
|
|
Again, one possible fix is to call \c .eval() on the whole expression:
|
|
\code
|
|
auto C = (u + (A*v).normalized()).eval();
|
|
\endcode
|
|
In this case, \c C will be a regular \c VectorXd object.
|
|
Note that DenseBase::eval() is smart enough to avoid copies when the underlying expression is already a plain \c Matrix<>.
|
|
|
|
|
|
\section TopicPitfalls_header_issues Header Issues (failure to compile)
|
|
|
|
With all libraries, one must check the documentation for which header to include.
|
|
The same is true with %Eigen, but slightly worse: with %Eigen, a method in a class may require an additional \c \#include over what the class itself requires!
|
|
For example, if you want to use the \c cross() method on a vector (it computes a cross-product) then you need to:
|
|
\code
|
|
#include<Eigen/Geometry>
|
|
\endcode
|
|
We try to always document this, but do tell us if we forgot an occurrence.
|
|
|
|
|
|
\section TopicPitfalls_ternary_operator Ternary operator
|
|
|
|
In short: avoid the use of the ternary operator <code>(COND ? THEN : ELSE)</code> with %Eigen's expressions for the \c THEN and \c ELSE statements.
|
|
To see why, let's consider the following example:
|
|
\code
|
|
Vector3f A;
|
|
A << 1, 2, 3;
|
|
Vector3f B = ((1 < 0) ? (A.reverse()) : A);
|
|
\endcode
|
|
This example will return <code>B = 3, 2, 1</code>. Do you see why?
|
|
The reason is that in c++ the type of the \c ELSE statement is inferred from the type of the \c THEN expression such that both match.
|
|
Since \c THEN is a <code>Reverse<Vector3f></code>, the \c ELSE statement A is converted to a <code>Reverse<Vector3f></code>, and the compiler thus generates:
|
|
\code
|
|
Vector3f B = ((1 < 0) ? (A.reverse()) : Reverse<Vector3f>(A));
|
|
\endcode
|
|
In this very particular case, a workaround would be to call A.reverse().eval() for the \c THEN statement, but the safest and fastest is really to avoid this ternary operator with %Eigen's expressions and use a if/else construct.
|
|
|
|
|
|
\section TopicPitfalls_pass_by_value Pass-by-value
|
|
|
|
If you don't know why passing-by-value is wrong with %Eigen, read this \link TopicPassingByValue page \endlink first.
|
|
|
|
While you may be extremely careful and use care to make sure that all of your code that explicitly uses %Eigen types is pass-by-reference you have to watch out for templates which define the argument types at compile time.
|
|
|
|
If a template has a function that takes arguments pass-by-value, and the relevant template parameter ends up being an %Eigen type, then you will of course have the same alignment problems that you would in an explicitly defined function passing %Eigen types by reference.
|
|
|
|
Using %Eigen types with other third party libraries or even the STL can present the same problem.
|
|
<code>boost::bind</code> for example uses pass-by-value to store arguments in the returned functor.
|
|
This will of course be a problem.
|
|
|
|
There are at least two ways around this:
|
|
- If the value you are passing is guaranteed to be around for the life of the functor, you can use boost::ref() to wrap the value as you pass it to boost::bind. Generally this is not a solution for values on the stack as if the functor ever gets passed to a lower or independent scope, the object may be gone by the time it's attempted to be used.
|
|
- The other option is to make your functions take a reference counted pointer like boost::shared_ptr as the argument. This avoids needing to worry about managing the lifetime of the object being passed.
|
|
|
|
|
|
\section TopicPitfalls_matrix_bool Matrices with boolean coefficients
|
|
|
|
The current behaviour of using \c Matrix with boolean coefficients is inconsistent and likely to change in future versions of Eigen, so please use it carefully!
|
|
|
|
A simple example for such an inconsistency is
|
|
|
|
\code
|
|
template<int Size>
|
|
void foo() {
|
|
Eigen::Matrix<bool, Size, Size> A, B, C;
|
|
A.setOnes();
|
|
B.setOnes();
|
|
|
|
C = A * B - A * B;
|
|
std::cout << C << "\n";
|
|
}
|
|
\endcode
|
|
|
|
since calling \c foo<3>() prints the zero matrix while calling \c foo<10>() prints the identity matrix.
|
|
|
|
*/
|
|
}
|