You can define boost::assertion_failed(...)
and BOOST_ENABLE_ASSERT_HANDLER
to throw an exception from boost::optional
.
Code:
#include<boost/exception/to_string.hpp>
namespace boost{
void assertion_failed(char const* expr, char const* function, char const* file, long line){
throw std::runtime_error(std::string()
+ expr +
" from " + function +
" at " + file + ":" + boost::to_string(line)
);
}
}
#define BOOST_ENABLE_ASSERT_HANDLER
#include <boost/optional.hpp>
#undef BOOST_ENABLE_ASSERT_HANDLER
int main(){
double d = *boost::optional<double>{}; // throws! (width fairly useful msg)
(void)d;
}
The error message (if exception is not catched) will read something like:
terminate called after throwing an instance of 'std::runtime_error'
what(): this->is_initialized() from reference_type boost::optional<double>::get() [T = double] at /usr/include/boost/optional/optional.hpp:992
Other reference: http://boost.2283326.n4.nabble.com/optional-How-to-make-boost-optional-throw-if-trying-to-access-uninitialized-value-td2591333.html
Notes:
1) It may need a fine grained definition of assertion_failed
to be useful in general. If you want to throw a different kind of exception I don't know other way than having a conditional in the assertion_failed
function, (it is also too hacky for my taste):
namespace boost{
void assertion_failed(char const* expr, char const* function, char const* file, long line){
if(std::string("this->is_initialized()") == expr) throw std::domain_error("optional is not intialized");
throw std::runtime_error(std::string()
+ expr +
" from " + function +
" at " + file + ":" + boost::to_string(line)
);
}
}
2) I don't agree with the other answer, I think one should be able to choose the behavior. And being stuck with assert
is not a good option. There are in my opinion uses of boost::optional
in contexts not involving function returns.
3) There is now an std::experimental::optional
version. Curiously enough they decided to be agnostic about this problem when taking the value with *
(since an unchecked value is returned, this consistent with the raw pointer non-behavior) BUT the .value()
member can throw an std::experimental::bad_optional_access
exception. This is an interesting design choice (plus none of the two ways assert
s! which I think is the right thing.).