3

当尝试获取 boost::optional 对象的值时,BOOST_ASSERT 用于确保对象确实已初始化。

但是,当取消引用未初始化的可选项时,我想要的是抛出异常 - 有没有办法在发布版本中获得这种行为?如果没有,是否有任何其他类似的库具有这种行为?

我不想每次在取消引用对象之前都使用 is_initialized 方法,而且我还想避免将可选类包装在我自己的类中以获得这种行为。

4

2 回答 2

3

不幸的是 optional 没有提供这样的选择。optional 的全部意义在于能够通过使用重载的 bool 运算符来检查值是否存在。

Optional旨在允许不在函数中引发异常,而是返回带有值的成功/失败。

也许您应该始终返回一个值,如果失败则将其放入函数中?

于 2010-01-27T10:54:02.220 回答
3

您可以定义boost::assertion_failed(...)BOOST_ENABLE_ASSERT_HANDLERboost::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

其他参考:http ://boost.2283326.n4.nabble.com/optional-How-to-make-boost-optional-throw-if-trying-to-access-uninitialized-value-td2591333.html

笔记:

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!我认为这是正确的。)。

于 2015-07-04T08:20:31.230 回答