Is it valid C++ to cast an rvalue to a const pointer? - c++

In a moment of haste, needing a pointer to an object to pass to a function. I took the address of an unnamed temporary object and to my surprise it compiled (the original code had warnings turned further down and lacked the const correctness present in the example below). Curious, I set up a controlled environment with warnings all the way up and treating warnings as errors in Visual Studio 2013.
Consider the following code:
class Contrived {
int something;
};
int main() {
const Contrived &r = Contrived(); // this is well defined even in C++03, the object lives until r goes out of scope
const Contrived *p1 = &r; // compiles fine, given the type of r this should be fine. But is it considering r was initialized with an rvalue?
const Contrived *p2 = &(const Contrived&)Contrived(); // this is handy when calling functions, is it valid? It also compiles
const int *p3 = &(const int&)27; // it works with PODs too, is it valid C++?
return 0;
}
The three pointer initializations are all more or less the same thing. The question is, are these initializations valid C++ under C++03, C++11, or both? I ask about C++11 separately in case something changed, considering that a lot of work was put in around rvalue references. It may not seem worthwhile to assign these values such as in the above example, but it's worth noting this could save some typing if such values are being passed to a function taking constant pointers and you don't have an appropriate object lying around or feel like making a temporary object on a line above.
EDIT:
Based on the answers the above is valid C++03 and C++11. I'd like to call out some additional points of clarification with regard to the resulting objects' lifetimes.
Consider the following code:
class Contrived {
int something;
} globalClass;
int globalPOD = 0;
template <typename T>
void SetGlobal(const T *p, T &global) {
global = *p;
}
int main() {
const int *p1 = &(const int&)27;
SetGlobal<int>(p1, globalPOD); // does *p still exist at the point of this call?
SetGlobal<int>(&(const int&)27, globalPOD); // since the rvalue expression is cast to a reference at the call site does *p exist within SetGlobal
// or similarly with a class
const Contrived *p2 = &(const Contrived&)Contrived();
SetGlobal<Contrived>(p2, globalClass);
SetGlobal<Contrived>(&(const Contrived&)Contrived(), globalClass);
return 0;
}
The question is are either or both of the calls to SetGlobal valid, in that they are passing a pointer to an object that will exist for the duration of the call under the C++03 or C++11 standard?

An rvalue is a type of expression, not a type of object. We're talking about the temporary object created by Contrived(), it doesn't make sense to say "this object is an rvalue". The expression that created the object is an rvalue expression, but that's different.
Even though the object in question is a temporary object, its lifetime has been extended. It's perfectly fine to perform operations on the object using the identifier r which denotes it. The expression r is an lvalue.
p1 is OK. On the p2 and p3 lines, the lifetime of the reference ends at the end of that full-expression, so the temporary object's lifetime also ends at that point. So it would be undefined behaviour to use p2 or p3 on subsequent lines. The initializing expression could be used as an argument to a function call though, if that's what you meant.

The first one is good: the expression r is not in fact an rvalue.
The other two are technically valid, too, but be aware that pointers become dangling at the end of the full expression (at the semicolon), and any attempt to use them would exhibit undefined behavior.

While it is perfectly legal to pass an rvalue by const&, you have to be aware that your code ends up with invalidated pointers in p2 and p3, since the lifetime of the objects that they point is over.
To exemplify this, consider the following code that is often used to pass a temporary by reference:
template<typename T>
void pass_by_ref(T const&);
A function like this can be called with an lvalue or rvalue as its argument (and often is). Inside that function you can obviously take the reference of your argument - it is just a reference to a const object after all... You are basically doing the exact same thing without the help of a function.
In fact, in C++11, you can go one step further and obtain a non-const pointer to an temporary:
template<typename T>
typename std::remove_reference<T>::type* example(T&& t)
{
return &t;
}
Note that the object the return value points to will only still exist if this function is called with an lvalue (since its argument will turn out to be typename remove_reference<T>::type& && which is typename remove_reference<T>::type&).

Related

C++ reference to local temporary object

Consider the following template class
template <typename T>
class A {
public:
virtual T const& getContent() = 0;
};
I derive this class using 'int*' as type 'T', as follows
class A1 : public A<int*> {
private:
int a;
public:
int* const& getContent() { return &a; }
};
I got the following warning: 'returning reference to local temporary object'.
Questions:
Does the compiler implicitly instantiate a local temporary object of type 'int * const' from '&a' before returning its reference?
As I do know that A.a really exists, then can I just ignore this warning? Will there be any undesirable side-effects of using this code?
What is the proper way of handling this situation? Do I need to work with the member variable 'int *a' instead. This would be cumbersome.
Yes.
You cannot ignore this warning. A.a exists, but that's not the issue. What you are returning is not a pointer to int, but a reference to a pointer to int, i.e. it is a double indirection. To be specific, a temporary int* was created inside getContent that pointed to A.a. A reference to that temporary was returned, and then the temporary was destroyed. Using the result of getContent will be undefined behavior.
The idiomatic way to handle this situation would typically be to store the member you are passing a const reference to. In other words, have a member int* a, and then simply return a in your function. Returning a const reference is a common way to expose the fully functionality of a data member without allowing the user of the class to mutate it, messing up your class' invariants.
This is incorrect:
T const& getContent() = 0;
You can do:
T const getContent() = 0;
int* const getContent() { return &a; }
First of all...
int* const&
Is the same as...
int *const&
Edit: Originally, I wrongly stated it was equivalent to const int*&. Sorry, that was my fault.
And, references to pointers are more "cumbersome" than pointer themselves (at least IMHO), don't you think so? There's a reason pointers and references shall never be mixed (unless it's a consecuence of template instantiation, of course)...
int const&*
This is impossible, invalid, and last but no least, insane. Although there's no practical way for references to be implemented other than by pointers, they are not objects, in the sense that they (themselves) don't have a sizeof that does not equals that of their referenced type, and the fact that they don't have address at all, at least as far as the Sacred Writings of N4296 are concerned.
But... pointers are objects! The expression &a returns a rvalue (that is basically an object without an address) of type int*. Now, the statement return &a; will take that value and wrap it up in a reference, because...
That's what the function return type expects.
The lifetime of an rvalue of type T can be extended by means of it being holded in a reference of type const T&. However, you can't use this to return references to temporary rvalues.
Now, because all this stuff implies that you're returning a reference to a temporary rvalue in an unallowed way, you where tempted and falled into Undefined Behaviour.
The solution? Simply don't use references to pointers at all in the first place...
int const *getContent() { return a; }
Or, if you prefer it, use references, but not pointers...
int const &getContent() { return *a; }
Now, to the questions!
*Does the compiler implicitly instantiate a local temporary object of type 'int * const' from '&a' before returning its reference?*: Yes and no. It does instantiate such a temporary as explained above (but usually optimized away), but it's type is int*, not int *const, although the latter gets implicitly casted into the former.
As I do know that A.a really exists, then can I just ignore this warning? Will there be any undesirable side-effects of using this code?: That depends on whether you would ignore a divide-by-zero warning.
What is the proper way of handling this situation? Do I need to work with the member variable 'int *a' instead. This would be cumbersome.: You may either use "cumbersome" pointers or "beatiful" references, see above.
I hope this has led some light on you!

Function-pointer syntax ambiguity

Take the following example. I create a function pointer named s, set it to f and call it. This compiles fine of course:
void f() {}
int main() {
void (*s)();
s = f;
s();
}
But take this next example, where I declare s now as a "function reference" (if it's so called) and set to f inline. This compiles fine as well:
void f() {}
int main() {
void (&s)() = f;
s();
}
What are the differences between these two ways to create and initialize a function-pointer? Note that when I use the reference syntax I am required to initialize it "in-line" to f whereas with the "pointer" syntax I had the ability to do it both ways. Can you explain that as well? And with that, can you explain what their differences are in terms of usability, and when must I use one form over the other?
Fundamentally the calling side has no distinct difference. But the decl side definitely does. As you have pointed out, references must be initialized to reference something. This makes them "safer", but even then there is no guarantee of "safety".
The function pointer need NOT point to a function at all. It could be NULL, or even uninitialized (pointing to garbage). Not that it matters, because you can always change it later (something you can NOT do with references).
void (*s)(); // uninitialized
or
void (*s)() = NULL; // set to null
and later
void foo()
{
}
s = foo;
You can do none of those with a reference. The reference must be initialized to something and preferabley something valid:
void (&f)() = foo; // ok. also references foo().
void (&f)() = *s; // also ok, but wait, is s valid?? does it have to be??
However, even here a function reference is not guaranteed to be safe, just safer. You can certainly do this:
void (*s)();
void (&f)() = *s;
You may get a compiler warning out of this (I do, "s used before being initialized") but in the end f still is now a reference to a "function" that isn't a function at all; just the random stack garbage in the s pointer. Worse, since references cannot be reassigned. this thing will always point at garbage.
The differences are the same as for any pointer/reference.
References must be initialized and cannot be reassigned later:
int i,j;
int &r = i;
r = j; // i = j, not &r == &j
References cannot be treated as objects distinct from the object they reference (as opposed to pointers, which are objects distinct from the object they point at)...
int i;
int *p = &i; // &p != &i
int &r = i; // &r == &i
Using a function pointer looks syntactically the same as using a reference, but that's because of a special rule with function pointers that allows you to use them without dereferencing them.
You said it yourself, a difference is that with a reference, you have to bind it upon declaration, which guarantees that references always refer to valid objects.
Another difference is that references cannot be rebinded after they are declared, so they refer to one and only one object throughout their lives.
Other than that they are the same thing.
I have met some purists that prefer references and said that pointers are a vestige of C that shouldn't be used.
Other people prefer pointers because they are more "explicit" about the fact that they are pointers.
Whether using one or the other depends on your needs. The way to choose is, use a reference if possible, but if you really need to be able to point it to a different function, then use a pointer.
A reference to a type P is a lot like a const pointer to a type P (not a pointer to a const P, which is different).
As it happens most of the ways they differ are not important if your type P is a function type. & behaves slightly differently, you can directly assign the pointer to a non const pointer, and functions that take one may not take the other.
If the type P was not a function type there would be loads of other differences -- operator=, lifetime of temporaries, etc.
In short, the answer is 'not much'.
Function identifiers are expressions of function type, but they implicitly convert to pointer-to-function type or reference-to-function type. So they can be passed to constructor of either reference or pointer and to operator= of pointer.
Since references syntactically behave like instances, there is no way to act on the reference rather than the referred object. That's why they can only be initialized. By the way prefered syntax in C++ is with parenthesis, not =.
You should use reference when possible and pointers only if you can't use reference. The reason is that since many things can't be done to reference (pointing to NULL, changing referred object, deleting it etc.) there is fewer things you have to look for when reading the code. Plus it saves some * and & characters.

Is there any point naming a local variable as a rvalue-ref?

Assuming the code compiles, is there any difference between:
A && a = .....
and
A & a = .....
? a is a local variable in a function or method, not a parameter.
By giving the rvalue-reference a name (a) it is effectively an lvalue for the rest of the scope? i.e. even with the former form, you'd have to use move(a) to enable pilfering when passing a to another function?
I appreciate there might be other problems with the second form, which prevent compilation, for example you can't have a (non-const) reference to a temporary. So, yes, I'm curious to know all the differences, but first I want to confirm my hunch that they are fully equivalent for the remainder of the scope.
Update: as an example of this 'temporary' problem, which #KerrekSB has reiterated, sometimes you must make the plain reference const. In that case, my question is whether there is a difference between:
const A && a = .....
and
const A & a = .....
There might be differences with operator A& and operator A&& being invoked in the one and other case respectively (You would need to check the spec and the DRs that modified/fixed that part of the spec).
What definitely is different is decltype(a) for both cases.
This works:
int foo();
int && a = foo();
This doesn't:
int & b = foo(); // error, cannot bind rvalue to non-const ref
The difference between A && a= ... and A & a= ... is that the former can bind to a temporary while the latter cannot. The C++ standard now specifies that a reference has to be non-volatile const or an rvalue reference to bind to a temporary (see 8.5.3 References [dcl.init.ref]), which can then extend the lifetime of the temporary (see 12.2 [class.temporary]).
EDIT: If you think about what rvalue references allow you to do, they have to be able to bind to temporaries, otherwise, you would not be able to express move semantics in C++.
(Answering my own question just to summarize what I think I've learned.)
In summary, what's the difference between A &a = ... and A &&a = ...? And between const A &a = ... and const A &&a = ...? If they are names of function parameters, then it affects function lookup clearly, but I'm just talking about local variables. The differences are:
(Obvious) const must be obeyed. A const reference can't be used to modify the object.
A &a = foo(); can't bind to a temporary (nothing new there), but the other three forms can and will extend the lifetime to the of the local variable.
decltype(a) will be different.
(Assuming there was no const problem), the initialization will likely be the same, except if there are operator & or operator && conversions to choose from.
In summary, there are fewer differences than I had originally assumed. Months ago, I had thought that
A &&a =...;
foo(a);
would call foo(A&&). But instead foo(move(a)) is required.
A C++03 programmer can fairly safely use A &&a = to extend the lifetime of temporaries without having to worry about other unexpected differences.
(Thanks to all)

Integral promotion when passing and returning argument by reference?

I'm reading something about overload resolution and I found something that bothers me...In the following code:
int const& MaxValue(int const& a, int const& b)
{
return a > b ? a : b;
}
void SomeFunction()
{
short aShort1 = 3;
short aShort2 = 1;
int const & r2 = MaxValue(aShort1, aShort2); // integral promotion
//is it safe to pass r2 around before function SomeFunction completes
// CallSomeOtherFunctionThatCallsSomethingElse(r2);
}
My understanding is that two temporary int's are created and they're allocated on the stack belonging to SomeFunction.
So when MaxValue returns, r2 referencing to one of those temp variables (in this case, the one that holds value 3).
Thus, is should be safe to pass r2 around.
The question is, if my understanding is fine, is this a standard behavior (please verify)? If not, please explain what is happening in above code.
Many Thanks
Welcome to why implicit casts suck. You now have a reference to a temporary, which has been destroyed. Hope you didn't want to do anything with it.
Yes, your understanding is fine and this is standard behaviour.
Except this:
Thus, is should be safe to pass r2 around.
which I do not understand.
// EDIT
You should use pointers instead of references here to achieve the same but without the problem. Using address of an argument passed by const reference is OK only within the function because it may point to local copy of an object.
Short answer: it is unsafe.
The standard guarantees that a temporary variable can be bound to a constant reference in which case the lifespan of the temporary expands to the lifetime of the bound reference. The problem in your particular case is what reference is actually binding the temporary.
When you call MaxValue( s1, s2 ), two temporary variables of type int are created and bound to the parameter arguments a and b in MaxValue. This means that the lifespan of those temporaries is extended to the completion of the function. Now, in the return statement of your function you are taking a second reference to one of the temporaries and that second reference will not extend the lifetime. r2 will not further extend the lifetime of the object, and you have a dangling reference.
Note that due to the separate compilation, the compiler cannot possibly know from outside of MaxValue whether the returned reference is to one of the arguments or to a completely different object that is not a temporary:
int const & OtherMaxValue( int const & a, int const & b ) {
static int value = 0;
value = (a > b? a : b);
return value;
}
So it cannot possibly guess whether any or which of the temporaries lifetime needs to be extended.
As a side note, for small objects (such as all integer types) passing by reference may be actually worse than passing by value. Also there is already an std::max template that actually implements this functionality.
You should return and pass by value for simple types.

Are all temporaries rvalues in C++?

I have been coding in C++ for past few years. But there is one question that I have not been able to figure out. I want to ask, are all temporaries in C++, rvalues?
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
No.
The C++ language specification never makes such a straightforward assertion as the one you are asking about. It doesn't say anywhere in the language standard that "all temporary objects are rvalues". Moreover, the question itself is a bit of misnomer, since the property of being an rvalue in the C++ language is not a property of an object, but rather a property of an expression (i.e. a property of its result). This is actually how it is defined in the language specification: for different kinds of expressions it says when the result is an lvalue and when it is an rvalue. Among other things, this actually means that a temporary object can be accessed as an rvalue as well as an lvalue, depending on the specific form of expression that is used to perform the access.
For example, the result of literal 2 + 3 expression is obviously an rvalue, a temporary of type int. We cannot apply the unary & to it since unary & requires an lvalue as its operand
&(2 + 3); // ERROR, lvalue required
However, as we all know, a constant reference can be attached to a temporary object, as in
const int &ri = 2 + 3;
In this case the reference is attached to the temporary, extending the lifetime of the latter. Obviously, once it is done, we have access to that very same temporary as an lvalue ri, since references are always lvalues. For example, we can easily and legally apply the unary & to the reference and obtain a pointer to the temporary
const int *pi = &ri;
with that pointer remaining perfectly valid as long as the temporary persists.
Another obvious example of lvalue access to a temporary object is when we access a temporary object of class type through its this pointer. The result of *this is an lvalue (as is always the case with the result of unary * applied to a data pointer), yet it doesn't change the fact that the actual object might easily be a temporary. For a given class type T, expression T() is an rvalue, as explicitly stated in the language standard, yet the temporary object accessed through *T().get_this() expression (with the obvious implementation of T::get_this()) is an lvalue. Unlike the previous example, this method allows you to immediately obtain a non-const-qualified lvalue, which refers to a temporary object.
So, once again, the very same temporary object might easily be "seen" as an rvalue or as an lvalue depending on what kind of expression (what kind of access path) you use to "look" at that object.
Prasoon Saurav already linked a very good clc++ thread. In there, James Kanze explains why the question doesn't really make sense. It boils down to:
rvalue-ness is a (boolean) property of expressions - each expression is either an lvalue or an rvalue
temporaries are not expressions
For that reason, the question doesn't make sense.
A good example is the following code:
int main() {
const int& ri = 4;
std::cout << ri << std::endl;
}
The temporary int with value 4 is not an expression. The expression ri that's printed is not a temporary. It's an lvalue, and refers to a temporary.
well, that array operator returns a reference, any function that returns a reference could be considered to do the same thing? all references are const, while they can be lvalues, they modify what they reference, not the reference itself. same is true for the *operator,
*(a temp pointer) = val;
I swear I used to use some compiler that would pass temp values to any function that took a reference,
so you could go:
int Afunc()
{
return 5;
}
int anotherFunc(int & b)
{
b = 34;
}
anotherFunc(Afunc());
can't find one that lets you do that now though, the reference has to be const in order to allow passing of temp values.
int anotherFunc(const int & b);
anyway, references can be lvalues and temporary, the trick being the reference it's self is not modified, only what it references.
if you count the-> operator as an operator, then temporary pointers can be lvalues, but the same condition applies, its not the temp pointer that would be changed, but the thing that it points to.
An array indexing operation is both a temporary and an lvalue, something like a[10] = 1 is an example of what you're looking for; the lvalue is a temporary, calculated pointer.
Short answer: yes, but I'm not going to quote the standard, because proving the point would require addressing every kind of temporary there is. By definition a temporary has a lifetime of one statement, so assigning things to one would be poor style at best.
Interesting answer: Copy elision can make (often makes) a temporary object identical with an lvalue object. For example,
MyClass blah = MyClass( 3 ); // temporary likely to be optimized out
or
return MyClass( 3 ); // likely to directly initialize object in caller's frame
Edit: as for the question of whether there is any temporary object in those cases, ยง12.8/15 mentions
the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy
which would indicate that there is a temporary object which may be identical with an lvalue.
It depends on what you consider a temporary variable is. You can write something like
#include <stdio.h>
int main()
{
char carray[10];
char *c=carray+1;
*(c+2+4) = 9;
printf("%d\n",carray[7]);
return 0;
}
This runs in VisualStudios and GCC. You can run the code in codepad
I consider (c+2+4) a rvalue although i want to assign to it. When i dereference it, it would become an lvalue. So yes all temporaries are rvalues. But you can make rvalues (thus a temporary) into an lvalue by dereferencing it
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
The following code binds a constant reference to a temporary object of type const float created by the compiler:
int i;
const float &cfr = i;
The behaviour is "as if":
int i;
const float __tmp_cfr = i; // introduced by the compiler
const float &cfr = __tmp_cfr;