When does boost::lexical_cast to std::string fail?
Asked Answered
P

3

9

I'm writing unit tests and trying to have all my code covered.

I have in my code something like this:

template<typename ValueType>
std::string ConvertToStringUsingBoost(ValueType const& v)
{
    try 
    {
        return boost::lexical_cast<std::string, ValueType>(v);
    }
    catch(boost::bad_lexical_cast const& e)
    {
        LOG_ERR("Fail to cast %s to string", e.source_type().name);
        return std::string();
    }
}

I was reading these docs and couldn't find any information about when boost::lexical_cast to std::string can throw an exception.

Can you please help me with that?

If it's impossible I'll simply delete this try-catch. If it's possible, I'd prefer to cover this in unit testing.

Pianette answered 1/5, 2019 at 11:30 Comment(1)
You probably could use boost::conversion::try_lexical_convert function to of avoid throwing bad_lexical_cast exception.Inquest
C
8

It can fail for example if a user-defined conversion throws:

enum class MyType {};

std::ostream& operator<<( std::ostream&, MyType const& )
{
    throw "error";
}

int main()
{
    try 
    {
        boost::lexical_cast< std::string >( MyType{} );
    }
    catch(...)
    {
        std::cout << "lexical_cast exception";
    }
}

As you have no control about the type of exceptions thrown by user-defined conversions, catching boost::bad_lexical_cast won't even be enough. Your unit test has to catch all exceptions.

Live Demo

Cymophane answered 1/5, 2019 at 12:23 Comment(3)
mmm I read the question as being about bad_lexical_cast specifically but this is a good pointAlisiaalison
In the OPs code, he specificly only catches boost::bad_lexical_castAnnapolis
@Annapolis Question title and description are generic though: "when boost::lexical_cast to std::string can throw an exception". OP didn't ask when it can throw boost::bad_lexical_cast. A code sample only accompanies a question and it can be wrong.Cymophane
A
10

I can't think of any reason for lexical cast to string to throw bad_lexical_cast, except with user-defined types. If the ValueType stream insertion operator can set an error flag on the stream then that's going to result in a bad_lexical_cast. Otherwise, not.

Personally I'd keep the catch in, even if you're just converting built-ins like ints; it doesn't hurt, and may catch bugs if you change the lexical_cast in some manner, or if there's some edge case that neither you nor I has considered; if you're not handling the resulting exception, you'll get an abort at runtime!

If you're concerned about the overhead of an exception, you can use try_lexical_cast instead and check that it returns true rather than catching. However, if the ValueType stream insertion operator can throw then you'd still need to be able to catch that exception anyway.

Alisiaalison answered 1/5, 2019 at 11:56 Comment(4)
I always get bad_weather_cast whenever I go outside.Schiedam
@SombreroChicken Switch to overcast for expected behaviourAlisiaalison
Since there is a catch, adding noexcept specifier to the function can make the calling code smaller/faster.Hellion
Indeed, looking at the boost source where bad_lexical_cast is an expected result as in the file lexical_cast_empty_input_test.cpp - when converting to a string an empty string is expected. Couldn't find an instance of to-string conversion throwing.Desiredesirea
C
8

It can fail for example if a user-defined conversion throws:

enum class MyType {};

std::ostream& operator<<( std::ostream&, MyType const& )
{
    throw "error";
}

int main()
{
    try 
    {
        boost::lexical_cast< std::string >( MyType{} );
    }
    catch(...)
    {
        std::cout << "lexical_cast exception";
    }
}

As you have no control about the type of exceptions thrown by user-defined conversions, catching boost::bad_lexical_cast won't even be enough. Your unit test has to catch all exceptions.

Live Demo

Cymophane answered 1/5, 2019 at 12:23 Comment(3)
mmm I read the question as being about bad_lexical_cast specifically but this is a good pointAlisiaalison
In the OPs code, he specificly only catches boost::bad_lexical_castAnnapolis
@Annapolis Question title and description are generic though: "when boost::lexical_cast to std::string can throw an exception". OP didn't ask when it can throw boost::bad_lexical_cast. A code sample only accompanies a question and it can be wrong.Cymophane
A
1

The only safe and futureproof (eg. no nasty surprises after an update of ) is to impair your code with something (ugly) like this:

template<typename ValueType>
std::string ConvertToStringUsingBoost(ValueType const& v)
{
    try 
    {

#ifdef UNITTEST
      if (unittest == case_fail) {
        throw boost::bad_lexical_cast();
      }
#endif
        return boost::lexical_cast<std::string, ValueType>(v);
    }
    catch(boost::bad_lexical_cast const& e)
    {
        LOG_ERR("Fail to cast %s to string", e.source_type().name);
        return std::string();
    }
}

Now you should be able to get to that ~100% code coverage !

Annapolis answered 1/5, 2019 at 12:12 Comment(2)
Not valid syntaxAlisiaalison
true, it was mostly the concept i was aiming at.Annapolis

© 2022 - 2024 — McMap. All rights reserved.