Vishnu Kanwar
Vishnu Kanwar

Reputation: 783

How to handle return value of a member function which returns a reference in an exception condition?

NodeModularStructureBuilder::NodeSetT const&
NodeModularStructureBuilder::GetSimilarNodesAtLevel ( Node const* p_node,
                                                      size_t level )
{
    if ( p_node ) {
        string s_name = StructuralAnalysis::Util::GetNLevelModularName (
                p_node, level );
        return this->node_ms_map_[s_name]; // this return is fine...
    }

    // if p_node is NULL then throw exception
    throw Except::NullPointerCrash ( "Invalid node pointer passed to "
            "FlopModularStructureBuilder::GetSimilarNodesAtLevel "
            "output is not usable." );
    // return ??????????
}

Q1. To avoid compiler error we need to return something from above function. what should we return? or suggest me how you handle return value of a member function (on an exception) which returns a reference?

Q2. Will program execution ever hit this return statement?

Upvotes: 1

Views: 133

Answers (4)

ForEveR
ForEveR

Reputation: 55897

I think, that most simple way will be simply throw exception by condition.

if (!p_node)
{
    throw Except::NullPointerCrash ( "Invalid node pointer passed to "
            "FlopModularStructureBuilder::GetSimilarNodesAtLevel "
            "output is not usable." );
}

string s_name = StructuralAnalysis::Util::GetNLevelModularName (
     p_node, level );
return this->node_ms_map_[s_name]; // this return is fine...

also you can use some null object, or something like boost::optional. But anyway, nothing after unconditional throw will be executed, so, there is no error in your code.

n3376 15.1/2

When an exception is thrown, control is transferred to the nearest handler with a matching type (15.3); “nearest” means the handler for which the compound-statement or ctor-initializer following the try keyword was most recently entered by the thread of control and not yet exited

Upvotes: 4

Henrik
Henrik

Reputation: 23324

Q1: you don't need to return anything when you throw. Your code should compile without errors.

Q2: No. Most compilers would issue an "Unreachable Code" warning.

Upvotes: 4

neuro
neuro

Reputation: 15210

In this case you can easily invert the condition:

NodeModularStructureBuilder::NodeSetT const&
NodeModularStructureBuilder::GetSimilarNodesAtLevel ( Node const* p_node,
                                                  size_t level )
{
    if ( ! p_node ) {

        // if p_node is NULL then throw exception
        throw Except::NullPointerCrash ( "Invalid node pointer passed to "
            "FlopModularStructureBuilder::GetSimilarNodesAtLevel "
            "output is not usable." );
    }
    string s_name = StructuralAnalysis::Util::GetNLevelModularName (
        p_node, level );
    return this->node_ms_map_[s_name]; // this return is fine...
}

The other solution when you can not do something that simple is to use a fake NullObject. But as the code after the throw will never be called, it is somehow a waste. The NullObject pattern is useful to know, anyway.

Upvotes: 0

Mats Petersson
Mats Petersson

Reputation: 129524

When you throw, the the function doesn't return anything - any code after throw will not be executed, so there is no point in writing any code there. (As suggested in the other answer, reversing the condition, and throwing before a return would be a solution to avoid compiler warnings/errors).

Obviously, the calling code will need to care for "not using the value stored from the return value", but in this case that shouldn't be a problem, as this looks like a direct "Oops" type error - in other words, no point in continuing. However if you have something like this:

std::String s;
try 
{
    for(;;)
    {
        s = readLineFromFile();
    }
} 
catch (...)
{
    .... 
}
... use s

you'd be in trouble, because s may not be the value you expect...

Upvotes: 4

Related Questions