Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const auto reference binding to (null) pointer - what is the actual type?

While looking into some code, I came across a construct with the following line:

if (const auto& foo = std::get_if<MyType>(&bar)) // note the ampersand!

where bar is a std::variant<MyType, OtherType>. The problem here is that get_if may return a null pointer and I don't understand why the statement works.

Consider this similar MCVE:

#include <iostream>

struct Foo { int a = 42; };

Foo* f() { return nullptr; }

int main() {
    const auto& foo = f();          // Returns a nullptr that binds to Foo*& - UB?
    //static_assert(std::is_same<decltype(foo), const Foo*&>::value); // -> Fails
    //const Foo*& bar = f(); // -> Fails

    if (foo)    std::cout << foo->a << std::endl;
    else        std::cout << "nullpointer" << std::endl;
}

The first line of main() works fine, and I would expect the type of barto be const Foo*&, but the static assertion fails. Unsurprisingly, the following line also fails to compile with cannot bind non-const lvalue reference of type 'const Foo*&' to an rvalue of type 'const Foo*'.

What happens in the first statement of main? Is this UB or does the standard contain some hidden secret that allows this to be legal? What is the type of bar?

like image 653
andreee Avatar asked May 09 '19 09:05

andreee


People also ask

What happens when you reference a null pointer?

A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit. NULL pointer dereference issues can occur through a number of flaws, including race conditions, and simple programming omissions.

Can a reference to a pointer be null?

Of course, your compiler is free to give you a null reference in that case, and virtually all compilers will do that: The reference is just a pointer under the hood, and it shares its storage with a pointer you set to nullptr .

Can const pointers be null?

The preferred way to write a null pointer constant is with NULL . This is a null pointer constant. You can also use 0 or (void *)0 as a null pointer constant, but using NULL is cleaner because it makes the purpose of the constant more evident.

What does const auto mean?

auto will deduce type and the variable will have the same type as the parameter u (as in the // 1 case), const auto will make variable the same type as the parameter u has in the // 2 case.


1 Answers

Note that for const auto& foo, const is qualified on the auto part, i.e. the pointer but not the pointee. Then the type of foo would be Foo* const &, which is a reference to const (pointer to non-const Foo), but not const Foo* &, which is a reference to non-const (pointer to const Foo).

And the lvalue-reference to const could bind to rvalue returned by f(), so const auto& foo = f(); works fine; const Foo*& bar = f(); won't work because bar is an lvalue-reference to non-const; which can't bind to rvalue. Changing the type of bar to const Foo * const & or Foo* const & (same as foo) would make it work.

like image 81
songyuanyao Avatar answered Sep 28 '22 05:09

songyuanyao