1[section Gotchas] 2 3[section A note about optional<bool>] 4 5`optional<bool>` should be used with special caution and consideration. 6 7First, it is functionally similar to a tristate boolean (false, maybe, true) 8—such as __BOOST_TRIBOOL__— except that in a tristate boolean, the maybe state 9[_represents a valid value], unlike the corresponding state of an uninitialized 10`optional<bool>`. 11It should be carefully considered if an `optional<bool>` instead of a `tribool` 12is really needed. 13 14Second, although `optional<>` provides a contextual conversion to `bool` in C++11, 15 this falls back to an implicit conversion on older compilers. This conversion refers 16 to the initialization state and not to the contained value. Using `optional<bool>` 17 can lead to subtle errors due to the implicit `bool` conversion: 18 19 void foo ( bool v ) ; 20 void bar() 21 { 22 optional<bool> v = try(); 23 24 // The following intended to pass the value of 'v' to foo(): 25 foo(v); 26 // But instead, the initialization state is passed 27 // due to a typo: it should have been foo(*v). 28 } 29 30The only implicit conversion is to `bool`, and it is safe in the sense that 31typical integral promotions don't apply (i.e. if `foo()` takes an `int` 32instead, it won't compile). 33 34Third, mixed comparisons with `bool` work differently than similar mixed comparisons between pointers and `bool`, so the results might surprise you: 35 36 optional<bool> oEmpty(none), oTrue(true), oFalse(false); 37 38 if (oEmpty == none); // renders true 39 if (oEmpty == false); // renders false! 40 if (oEmpty == true); // renders false! 41 42 if (oFalse == none); // renders false 43 if (oFalse == false); // renders true! 44 if (oFalse == true); // renders false 45 46 if (oTrue == none); // renders false 47 if (oTrue == false); // renders false 48 if (oTrue == true); // renders true 49 50In other words, for `optional<>`, the following assertion does not hold: 51 52 assert((opt == false) == (!opt)); 53[endsect] 54 55[section Moved-from `optional`] 56 57When an optional object that contains a value is moved from (is a source of move constructor or assignment) it still contains a value and its contained value is left in a moved-from state. This can be illustrated with the following example. 58 59 optional<std::unique_ptr<int>> opi {std::make_unique<int>(1)}; 60 optional<std::unique_ptr<int>> opj = std::move(opi); 61 assert (opi); 62 assert (*opi == nullptr); 63 64Quite a lot of people expect that when an object that contains a value is moved from, its contained value should be destroyed. This is not so, for performance reasons. Current semantics allow the implementation of `boost::opiotnal<T>` to be trivially copyable when `T` is trivial. 65[endsect] 66 67[section Mixed relational comparisons] 68 69Because `T` is convertible to `optional<T>` and because `opiotnal<T>` is __SGI_LESS_THAN_COMPARABLE__ when `T` is __SGI_LESS_THAN_COMPARABLE__, 70you can sometimes get an unexpected runtime result where you would rather expect a compiler error: 71 72 optional<double> Flight_plan::weight(); // sometimes no weight can be returned 73 74 bool is_aircraft_too_heavy(Flight_plan const& p) 75 { 76 return p.weight() > p.aircraft().max_weight(); // compiles! 77 } // returns false when the optional contains no value 78 79[endsect] 80 81[section False positive with -Wmaybe-uninitialized] 82 83Sometimes on GCC compilers below version 5.1 you may get an -Wmaybe-uninitialized warning when copiling with option -02 on a perfectly valid `boost::optional` usage. For instance in this program: 84 85 #include <boost/optional.hpp> 86 87 boost::optional<int> getitem(); 88 89 int main(int argc, const char *[]) 90 { 91 boost::optional<int> a = getitem(); 92 boost::optional<int> b; 93 94 if (argc > 0) 95 b = argc; 96 97 if (a != b) 98 return 1; 99 100 return 0; 101 } 102 103This is a bug in the compiler. As a workaround (provided in [@http://stackoverflow.com/questions/21755206/how-to-get-around-gcc-void-b-4-may-be-used-uninitialized-in-this-funct this Stack Overflow question]) use the following way of initializing an optional containing no value: 104 105 boost::optional<int> b = boost::make_optional(false, int()); 106 107This is obviously redundant, but makes the warning disappear. 108 109[endsect] 110 111[endsect]