8

I got different results using auto and using Vector when summing two vectors.

My code:

#include "stdafx.h"
#include <iostream>
#include "D:\externals\eigen_3_1_2\include\Eigen\Geometry"

typedef Eigen::Matrix<double, 3, 1>       Vector3;

void foo(const Vector3& Ha, volatile int j) 
{
    const auto resAuto = Ha + Vector3(0.,0.,j * 2.567);
    const Vector3 resVector3 = Ha + Vector3(0.,0.,j * 2.567);

    std::cout << "resAuto = " << resAuto <<std::endl;
    std::cout << "resVector3 = " << resVector3 <<std::endl;
}

int main(int argc, _TCHAR* argv[])
{
    Vector3 Ha(-24.9536,-29.3876,65.801);
    Vector3 z(0.,0.,2.567);

    int j = 7;

    foo(Ha,j);
    return 0;
}

The results:

resAuto = -24.9536, -29.3876,65.801

resVector3 = -24.9536,-29.3876,83.77

Press any key to continue . . .

I understand that Eigen does internal optimization that generate different results. But it looks like a bug in Eigen and C++11.

qwerty_so
  • 35,448
  • 8
  • 62
  • 86
  • 1
    If it sounds like "a bug in Eigen and C++11", it probably isn't. Read the documentation again carefully, paying careful attention to expression templates. – Kerrek SB Jun 28 '15 at 11:34
  • It works successfully for me with eigen 3.2.2. – user2658323 Jun 29 '15 at 15:50
  • Expression templates and other classes that return proxy types (vector::operator[](size_t)) can be surprising when used with auto. Instead of getting the sum of your vectors you are getting a type that stores the expression of the sum of your two vectors. This is a template optimization that is often used for large objects live matrices. In other news, there was a proposal for 'operator auto' that would have allowed the Eigen class author to return an actual Vector3 in your case. I know gcc and I think clang have snuck it in. Maybe hack your own 'operator auto' and see. – emsr Jun 29 '15 at 20:04
  • From [the Eigen doc](https://eigen.tuxfamily.org/dox/TopicPitfalls.html), `auto` will use lazy evaluation. This will cause problem when either 1) any values changed between the expression was written and executed 2) reference to temporary object. For the second case (which is the cause of Rotem's problem), I think Eigen should just return eager evaluation if any value is r-value. :-/ – HKTonyLee Feb 15 '23 at 20:04

1 Answers1

4

The auto keyword tells the compiler to "guess" the best object based on the right hand side of the =. You can check the results by adding

std::cout << typeid(resAuto).name() <<std::endl;
std::cout << typeid(resVector3).name() <<std::endl;

to foo (don't forget to include <typeinfo>).

In this case, after constructing the temporary Vector3, the operator+ method is called, which creates a CwiseBinaryOp object. This object is part of Eigens lazy evaluation (can increase performance). If you want to force eager evaluation (and therefore type determination), you could use

const auto resAuto = (Ha + Vector3(0.,0.,j * 2.567)).eval();

instead of your line in foo.

A few side notes:

  • Vector3 is identical to the Vector3d class defined in Eigen
  • You can use #include <Eigen/Core> instead of #include <Eigen/Geometry> to include most of the Eigen headers, plus certain things get defined there that should be.
Avi Ginsburg
  • 10,323
  • 3
  • 29
  • 56