Bind rvalue reference to lvalue with `void*`
Asked Answered
C

2

23

While trying to understand how rvalue references work I ended up with this piece of code:

int* iptr = nullptr;
int*&& irr = iptr;

Compiling the above code gives the following error:

error: rvalue reference to type 'int *' cannot bind to lvalue of type 'int *'

I understand this is correct, but why does the following code, where I bind using a void* instead of int*, compiles without any problem? Will the runtime behavior be correct or should I expect undefined behavior?

int* iptr = nullptr;
void*&& irr = iptr;
Calgary answered 20/4, 2018 at 7:56 Comment(0)
C
22

This is well-formed.

int* and void* are different types; you can't bind a int* to reference to void* directly. The int* needs to be converted to void* firstly, which is a temporary object and could be bound to rvalue-reference. (PS the lifetime of the temporary is extended to the lifetime of the reference.)

Note that irr doesn't bind to iptr; so any modification on it has nothing to do with iptr.

This is not special for void*, same thing happens for other types, e.g.

char c;
int&& r = c; // a temporary int is constructed from c and then bound to r;
             // its lifetime is extened to the lifetime of r
Chesterton answered 20/4, 2018 at 7:59 Comment(0)
H
11

In addition to @songyuanyao answer: you could make an rvalue out of iptr e.g. by means of static_cast:

  int* iptr = nullptr;
  int*&& irr = static_cast<int *>(iptr);
Heyerdahl answered 20/4, 2018 at 8:19 Comment(10)
Why not just std::move?Chesterton
@Chesterton because a move would actually bind irr to iptr.Indigestion
If you find the static_cast clunky, know that int *&&irr = +iptr; does the same thing :)Indigestion
@Indigestion Got it. Didn't think the conversion to same type also constructs a new temporary.Chesterton
@Chesterton consider that for a class type Foo(anotherFoo) and static_cast<Foo>(anotherFoo) are equivalent :)Indigestion
@Indigestion Yes I realised that. As you said, it's same as +iptr even one is explicit conversion the other is implicit conversion.Chesterton
@Indigestion could you expand your comment? what do you mean with actually bind? and what's the difference in those terms if I use the static_cast?Calgary
@Calgary it means that irr refers to (gives access to) iptr itself. With the cast, irr refers to the unnamed result of the cast (whose lifetime is extended to live as long as irr), which is a copy of iptr.Indigestion
@IgorR. Yes it is: "The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference".Indigestion
@Indigestion You're right. It turns out that the lifespan of prvalue is extended in such a case - but not of an xvalue.Heyerdahl

© 2022 - 2024 — McMap. All rights reserved.