Как я могу убедиться, что объект boost :: option <T>инициализирован в release-build? - PullRequest
3 голосов
/ 27 января 2010

При попытке получить значение объекта boost :: option, BOOST_ASSERT используется, чтобы убедиться, что объект действительно инициализирован.

Но что я хотел бы, чтобы при разыменовании неинициализированного необязательного параметра было выброшено исключение - есть ли способ получить такое поведение в сборке выпуска? Если нет, то есть ли другая подобная библиотека, которая имеет такое поведение?

Я бы не хотел использовать метод is_initialized каждый раз перед разыменованием объекта, и я также хотел бы избежать оборачивания необязательного класса в моем собственном классе, чтобы получить такое поведение.

Ответы [ 2 ]

3 голосов
/ 04 июля 2015

Вы можете определить 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. Любопытно, что они решили быть неосмотрительными к этой проблеме, принимая значение с * (поскольку возвращается значение unchecked , что согласуется с отсутствием необработанного указателя) .value() участник может выдать исключение std::experimental::bad_optional_access. Это интересный выбор дизайна (плюс ни один из двух способов assert s! Который я считаю правильным.).

3 голосов
/ 27 января 2010

К сожалению, опция не дает такой опции. Весь смысл необязательного заключается в том, чтобы иметь возможность проверить, присутствует ли значение, используя перегруженный оператор bool.

Необязательно: предназначен , чтобы НЕ генерировал исключения в функциях, но вместо этого возвращал успех / неудачу со значением.

Может быть, вы должны вместо этого всегда возвращать значение и бросать в функцию, если оно не работает?

...