Assigning return value of a function to reference variable

Reference variables cannot be initialized to null, but what if I assign return value of a function to a reference and the return value is null?

How would compiler avoid null getting assigned to a ref variable in that case?

For instance:

const MyType& myRefVar = func();
Last edited on
If the function returns a non-const lvalue - for instance: int& foo() ;
we can initialise an lvalue reference with the result: int& i = foo() ; const int& c = foo() ;

If the function returns a const lvalue - for instance: const int& bar() ;
we can initialise an lvalue reference to const with the result: const int& c = bar() ;

If the function returns a prvalue - for instance: int foobar() ;
we can initialise an lvalue reference to const or an rvalue reference with the result:
const int& c = foobar() ; int&& rvr = foobar()

Value category: http://en.cppreference.com/w/cpp/language/value_category
Reference initialisation: http://en.cppreference.com/w/cpp/language/reference_initialization
And what would be the value of the ref variable, if the function returns null? Especially when reference vars can't be null.

Do I need a defensive null check on the ref var, which doesn't seem right.

Thanks!
And what would be the value of the ref variable, if the function returns null
In your example return type of function func is either value or reference. Both of which cannot be naturally null.
> if the function returns null?

What does 'null' mean in this context?

If the function returns void, we can't use references at all; void is not an object-type.
void foo() ; const auto& v = foo() ; // *** error: cannot form a reference to 'void'

If the function returns a pointer, we can initialise a references with it; a pointer is an object-type.
int* bar() ; const int*& p = bar() ; // fine: but p may me referring to a nullptr
In this case, you may want to check if p == nullptr.

With incorrectly written functions like these
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct my_type { /* ... */ };

const my_type& my_bad_func()
{
    my_type m ;
    return m ; // this is wrong. a diagnostic may be generated
               // *** warning: reference to local variable 'm' returned
}

const my_type& my_worse_func()
{
    my_type* p = nullptr  ;
    return *p ; // this too is wrong. though a diagnostic may not be generated
}

there is really nothing much that the calling code can do.

Other than something like:
1
2
3
4
const auto& ref = my_worse_func() ;
assert( std::addressof(ref) != nullptr ) ;
if( std::addressof(ref) == nullptr )
    throw std::logic_error( "my_worse_func engendered undefined behaviour" ) ;

Even that is not guaranteed to work (though it usually does); the undefined behaviour had occurred earlier.



What can we do to catch programming errors?

Write idiomatic C++ code.
Strongly favour using the standard library over home-grown solutions.
Identify invariants and assert them in the code.

Turn on all compiler warnings, and pay attention to them.

A compiler can't be expected to catch all mistakes; so:
Compile with more than one compiler. If possible, run one or more static-code-analysis tools.

Subject the code to a formal peer-review.

Even if all this is done, there may be errors that are not detected.
So test the code: as early, as thoroughly, and as often as possible.

That is the best we can do; minimise the probability of undetected errors.
Rest with the knowledge that an undetected error may still be lurking in the released code.
Topic archived. No new replies allowed.