当尝试获取 boost::optional 对象的值时,BOOST_ASSERT 用于确保对象确实已初始化。
但是,当取消引用未初始化的可选项时,我想要的是抛出异常 - 有没有办法在发布版本中获得这种行为?如果没有,是否有任何其他类似的库具有这种行为?
我不想每次在取消引用对象之前都使用 is_initialized 方法,而且我还想避免将可选类包装在我自己的类中以获得这种行为。
当尝试获取 boost::optional 对象的值时,BOOST_ASSERT 用于确保对象确实已初始化。
但是,当取消引用未初始化的可选项时,我想要的是抛出异常 - 有没有办法在发布版本中获得这种行为?如果没有,是否有任何其他类似的库具有这种行为?
我不想每次在取消引用对象之前都使用 is_initialized 方法,而且我还想避免将可选类包装在我自己的类中以获得这种行为。
不幸的是 optional 没有提供这样的选择。optional 的全部意义在于能够通过使用重载的 bool 运算符来检查值是否存在。
Optional旨在允许不在函数中引发异常,而是返回带有值的成功/失败。
也许您应该始终返回一个值,如果失败则将其放入函数中?
您可以定义boost::assertion_failed(...)
并BOOST_ENABLE_ASSERT_HANDLER
从boost::optional
.
代码:
#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;
}
错误消息(如果未捕获异常)将显示如下内容:
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
笔记:
1)它可能需要一个细粒度的定义assertion_failed
才能普遍有用。如果你想抛出一种不同的异常,我不知道除了在assertion_failed
函数中有一个条件之外的其他方法,(这对我来说也太老套了):
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)我不同意另一个答案,我认为应该能够选择行为。被困住assert
并不是一个好的选择。在我看来,boost::optional
在不涉及函数返回的上下文中使用。
3)现在有一个std::experimental::optional
版本。奇怪的是,他们决定在取值时不知道这个问题*
(因为返回了未经检查的值,这与原始指针非行为一致)但是成员.value()
可以抛出std::experimental::bad_optional_access
异常。这是一个有趣的设计选择(加上这两种方式都没有assert
!我认为这是正确的。)。