2010-01-27 51 views
3

当试图获取boost :: optional对象的值时,BOOST_ASSERT用于确保对象确实已初始化。如何确保boost :: optional <T>对象在发布版本中初始化?

但是,我想在解除引用未初始化的可选项时引发异常 - 是否有任何方法在发布版本中获取此行为?如果没有,有没有其他类似的图书馆有这种行为?

我讨厌每次在解引用对象之前使用is_initialized方法,并且我还想避免在我自己的类中包装可选类以获得此行为。

+0

这是我从boost :: optional中错过的东西。有一个get_or_throw(例外)和get_or_else(另一个)会很好。我更愿意包装它,它能很好地传达我的想法。 – daramarak 2011-12-06 13:58:46

+0

@daramarak这里有一个'safe_get'代码:http://boost.2283326.n4.nabble。com/optional-how-to-make-boost-optional-throw-if-trying-to-access-uninitialized-value-tp2591333p2591334.html。另请参阅我的答案。 – alfC 2015-07-04 08:21:32

回答

3

不幸的是,可选项不提供这样的选项。可选的要点是能够通过使用重载的bool操作符来检查值是否存在。

可选为设计,允许在功能不要将抛出异常,但与返回值成功/失败来代替。

也许你应该总是返回一个值,而如果失败的话会抛出函数吗?

+1

这样做可能会违反允许可选返回值的目的,这正是我正在寻找的目标......如示例中所示: http://www.boost.org/doc/libs/1_41_0/libs/可选/ doc/html/boost_optional/examples.html#boost_optional.examples.optional_return_values – Danra 2010-01-27 10:59:20

+2

@Danra - 如果值不存在,您明确指出您希望有异常 - 因此为什么不将它放在函数中,哪里更多合乎逻辑地去做,而不是等待它被解除引用? – 2010-01-27 11:15:47

+2

它适用于很好地返回可选值。你问它是否返回了一个值,然后采取相应的行动。例外不应该是正常程序流程的工具。 – 2010-01-27 11:16:40

3

您可以定义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 

其他参考: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这两种方式都没有,我认为这是正确的选择)。