norlab-ulaval / libnabo

A fast K Nearest Neighbor library for low-dimensional spaces

Home Page:http://norlab-ulaval.github.io/libnabo/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Prevent confusion about the lifetime expectation of createKDTreeLinearHeap regarding its cloud argument

HannesSommer opened this issue · comments

As the history of issues #9, #34, #38 impressively demonstrate the signature of createKDTreeLinearHeap does not warn enough about the fact the the cloud argument must stay alive for its returned object to work properly. This is especially bad for implicit casting of Eigen matrices. If the cloud does not fit the expected Matrix type exactly it will be casted into a temporary matrix, of which a reference will be stored (this caused #9, #34 and was not even really understood with some effort).

See https://github.com/ethz-asl/libnabo/blob/master/nabo/nabo.h#L357.

Of course we should at least update the documentation of that function to include a suitable warning.

But I would suggest to go further and change the signature and accept a raw or smart pointer instead. A runtime check could be added to prevent null pointers. This will be more warning "within the code / signature" and prevent temporary objects from being used accidental.
In case of a raw pointer one could add a boolean flag that can optionally requests the libnabo to take over ownership. By providing a value to that flag users will be forced to think about lifetime.

If this is too much of a API change one could overload it with templated function that gets resolved whenever the type does not exactly match and issues a meaningful static assertion. This would at least catch temporary objects cases stemming from implicit casts.

I am already working on a solution which accepts different types. I however also expect users to read the existing documentation and examples which clearly state the expectations of nabo. I am unsure if adding more information to the existing documents will resolve the issue of users not reading the docs in the first place.

I don't know how familiar you are with Eigen, but it is non trivial to make static assertions that would catch cases of wrong derived types without changing the API. Anyhow, I am working on a proposal for this, happy to get feedback on it then. (ETA <1week)

It does not seem to be a part of the methods documentation. That at least it should be, because it is pretty unusual to store a const reference argument. About the static assertion. Why not just have a function templated on exactly this first parameter. So e.g.

template <typename WrongMatrixType>
static NearestNeighbourSearch* createKDTreeLinearHeap(WrongMatrixType cloud, const Index dim = std::numeric_limits<Index>::max(), const unsigned creationOptionFlags = 0, const Parameters& additionalParameters = Parameters()) {
  typedef int Please_make_sure_that_the_decltype_of_the_first_parameter_is_equal_to_the_Matrix_typedef[sizeof(WrongMatrixType) > 0 ? -1 : 1];
  Please_make_sure_that_the_decltype_of_the_first_parameter_is_equal_to_the_Matrix_typedef dummy;
  return 0;
}

This should catch all non exact matches, because it can match without any conversion but is a template function so there is exactly one way to be a truly better match : to match exactly but as a non-template function (if I'm not mistaken).

It only looks that ugly because libnabo does apparently not rely on c++11, yet. So I could not just use a static_assert(sizeof(WrongMatrixType) < 0, "Please make sure that the decltype of the first parameter is equal to the Matrix typedef")

well, there are examples that go with it which all use the Nabo provided typedef. I don't know why a user would just pass a wrong type to a function and expect things to work, i.e.:

float Foo(float bar) {
 return bar * 2.f;
}

double value = 0.0;
double result = Foo(value);

Nobody would complain about the narrowing conversion, right?

Yes, we can add the template to make this a compilation error, this is a good point.

This was solved in #41.