Hi,
As of boost 1.59 (and presumably boost 1.60 is the same), boost.geometry assumes that a default-constructed point_type is well-defined. For instance, struct segment_intersection_points defined in boost\geometry\strategies\intersection_result.hpp
may be copied while count < 2, i.e., when some points have not yet been assigned a well-defined value. As we all know, with uninitialized memory, any access including copy or move is undefined behavior.
At think-cell, we believe in tight life cycles and undefined behavior. For all purposes in our own code, default-constructed variables of point_type are uninitialized rather than default-initalized, meaning not only that any value stored
in there must not be used, but also that the contents of those variables must not be copied or moved. This works very well for our purpose and helps to discover bugs that otherwise are still there but go unnoticed. In theory, this paradigm also facilitates
additional compile-time optimization which may or may not be leveraged in current compilers. In our opinion, default-initialization to, e.g., zero, is quite arbitrary and meaningless. If you want to construct an object of point_type with some specific value,
it is entirely adequate to require that this specific value be explicitly stated upon construction.
In this regard, we follow the gist of the C++ standard: “8.5.12: If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object
has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.18). […] If an indeterminate value is produced by an evaluation, the behavior is undefined except in
the following cases: [… all cases only apply to unsigned char …]”
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4582.pdf
That said, I have some questions to the boost.geometry team:
-
Can you tell if you actually use the values that happen to be found in a default-constructed object? Does your code rely on specific values as the result of default construction, e.g., zero?
-
Do you think you could avoid access to default-constructed objects, e.g., by using boost::optional, or variant, or dynamically sized containers, or some other obvious tools?
Currently, we use some work-around and provide a special point_type class for boost.geometry for the sole purpose of default-initialization to keep your code from entering UB. Perspectively, we’d love to remove that workaround and simply
use our own point_class which after default-construction contains uninitialized memory.
It would be very helpful to know where you are heading: Do you think that our approach is a good idea, or do you see some benefits to having default-constructed objects initialized with some arbitrary but specific value? If so, would you
amend your documentation to explicitly state that default-constructed objects must be well-defined, and which specific value (zero?) you expect?
Any feedback is appreciated!
Volker
--
Volker Schöch | vschoech@think-cell.com
Senior Software Engineer
think-cell Software GmbH | http://www.think-cell.com | |
Chausseestr. 8/E | phone / fax | +49 30 666473-10 / -19 |
10115 Berlin, Germany | US phone / fax | +1 800 891 8091 / +1 212 504 3039 |
Amtsgericht Berlin-Charlottenburg, HRB 85229 | European Union VAT Id DE813474306 | ||
Directors: Dr. Markus Hannebauer, Dr. Arno Schödl |