开发者

How can I make sure a boost::optional<T> object is initialized in release-build?

When trying to get the value of a boost::optional object, BOOST_ASSERT is used to make sure the object is indeed initialized.

But what I would like when dereferencing an uninitialized optional is for an exception to be thrown - is there any way to get this behaviour in a release build? If not, is there any other similar library which has this behaviour?

I would开发者_如何学编程 hate to use the is_initialized method each time before dereferencing the object, and I'd also like to avoid wrapping the optional class in my own class to get this behaviour.


Unfortunately optional doesn't give such an option. The whole point of optional is to be able to check if the value is present by using the overloaded bool operator.

Optional was designed to allow NOT to throw exceptions in functions, but return a success/failure with the value instead.

Maybe you should return a value always instead, and throw inside the function if it fails?


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 asserts! which I think is the right thing.).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜