While there are zillions of sources on clarifying the concept of references in C++, I'm trying to explain the concept of reference to someone who is familiar with pointers. In other words, I'm wondering whether the following semantic expression is ALWAYS true?
TYPE& == *(TYPE const *)
The expression
TYPE& == *(TYPE const *)
looks a bit of domain error as TYPE& is a type while *(TYPE const*) looks like an expression applied to a type. At the very least, the right hand side should be const pointer rather than a pointer to const, i.e.:
A TYPE& behaves like an auto-dereferenced immutable pointer, something like *(TYPE* const) with the implicit constraint that the pointer cannot be null.
The compiler does recognize references and in some cases, namely when binding temporaries to a reference to a const object (T const&) at function scope: the life-time of the temporary gets expanded until the reference goes out of scope! For example:
{
std::string const& s = std::string("longer lived");
// the original temporary created above still lives
} // <-- ... and gets destroyed when s goes out of scope here
Another major difference between pointers and references are semantics when it comes to operator overloading: pointers are consider built-in types and operators only involving built-in types cannot be overloaded. A reference of type T& behaves like a T object, i.e., overloaded operators for T& are considered. That is, while the a T& is identical to using a T* const from a representation point of view, the compiler understands the difference and treats the entities differently on a semantic level.
Yes, if you disassemble C++ code in Visual Studio, reference is nothing but const pointer. So both are almost equivalent.
But be aware, you cannot assign NULL (0/nullptr) to reference.
Probably the best way to explain references is to use Stroustroup's example showing how they allow creating functions that replace macros, something that would not be possible without references.
The stated possible type equivalence TYPE& == *(TYPE const *) does not make literal sense since the right hand side isn't a type, and since it's about a pointer to const instead of a const pointer.
However, considering the thing in an associative sense, one can imagine a rewrite rule where a reference declaration
T& r = o;
is rewritten as
T* const __p = &o;
and where every use of r is then rewritten as
(*__p)
Except for handling of the case where o is an rvalue expression it explains most and perhaps all practical properties of references.
However, as the relevant FAQ item “How can you reseat a reference to make it refer to a different object?” states,
” please don't confuse references with pointers; they're very different from the programmer's standpoint
One of the ways it differs, is that you cannot take the address of a reference,
but you can take the address of a pointer. Since you can take the address of a
pointer, it must have storage. However, references do not have to have storage
(they are defined in the standard as aliases), and as often the compiler can,
they will in fact not have storage.
Related
I often see statements like below in C++ books regarding reference:
Reference is just another name of the original object. When it is used, it is replaced by the original object (in most cases).
Here is the question:
If I bind a const ref to a non-const object, when this const ref being used and replaced by the original object, does the const-ness goes away?
int i = 42;
const int & r1 = i;
int & r2 = r1; // Question: shouldn't r1 here just be replaced by the original object, which is **non-const**?
Simple answer: No
Longer answer: You cannot do that. Once you have a const & it will always stay const (unless you do const casting or some other explicit things). This is by design as otherwise const-correctness wouldn't really mean much and also the reason why you cannot compile your code.
The reason why int & r2 = r1; fails is because you dropped cv-qualifier const when reference-relate r2 to r1.
See C++ standard working draft, n3797, 8.5.3/5:
If T1 is reference-related to T2, cv1 shall be the same cv-qualification as, or greater
cv-qualification than, cv2.
First of all, the provided code is not valid, since you cannot initialize non-constant reference with constant reference.
Regarding your question, it might be easier to consider reference as a special kind of pointer to the object, which is automatically referenced (the sentence you quoted is quite misleading).
Your question is confused, anyway, assigning to a reference does not change the constness of the original object.
And your code won't compile without const_cast.
int& r2 = const_cast<int&>(r1);
You can use const_cast for casting away the constness.
The books are lying. C++ references are * const pointers in disguise with some special syntax. A const reference can extend the life of a temporary, which pointers can't. That's it.
References were only invented to allow convenient syntax for operator overloading. I still like references and use them, but I'm under no illusions that they are "magical" and "totally different to pointers".
Say the object is
class A {
public : void Silly(){
this = 0x12341234;
}
I know I will get compiler error ' "this" is not a lvalue.' But then it is not a temporary either. So what is the hypothetical declaration of "this" ?
Compiler : GCC 4.2 compiler on mac.
For some class X, this has the type X* this;, but you're not allowed to assign to it, so even though it doesn't actually have the type X *const this, it acts almost like it was as far as preventing assignment goes. Officially, it's a prvalue, which is the same category as something like an integer literal, so trying to assign to it is roughly equivalent to trying to assign a different value to 'a' or 10.
Note that in early C++, this was an lvalue -- assigning to this was allowed -- you did that to handle the memory allocation for an object, vaguely similar to overloading new and delete for the class (which wasn't supported yet at that time).
It is impossible to provide a "declaration" for this. There's no way to "declare" an rvalue in C++. And this is an rvalue, as you already know.
Lvalueness and rvalueness are the properties of expressions that produce these values, not the properties of declarations or objects. In that regard, one can even argue that it impossible to declare an lvalue either. You declare an object. Lvalue is what is produced when you use the name of that object as an expression. In that sense both "to declare an rvalue" and "to declare an lvalue" are oxymoron expressions.
Your question also seems to suggest that the properties of "being an lvalue" and "being a temporary" are somehow complementary, i.e. everything is supposedly an lvalue or a temporary. In reality, the property of "being a temporary" has no business being here. All expressions are either lvalues or rvalues. And this happens to be an rvalue.
Temporaries, on the other hand, can be perceived as rvalues or as lvalues, depending on how you access the temporary.
P.S. Note, BTW, that in C++ (as opposed to C) ordinary functions are lvalues.
For one thing, this is not a variable - it's a keyword. When used as a rvalue, its type is A * or A const *. In modern C++, assigning to this is prohibited. You cannot take the address of this, either. In other words, it's not a valid lvalue.
To answer the second part, "why is this not an lvalue", I'm speculating as to the committee's actual motivation, but advantages include:
assigning to this doesn't make much logical sense, so there's no particular need for it to appear on the left-hand-side of assignments. Making it an rvalue emphasises that this doesn't make much sense by forbidding it, and means that the standard doesn't have to define what happens if you do it.
making it an rvalue prevents you taking a pointer to it, which in turn relieves the implementation of any need to furnish it with an address, just like a register-modified automatic variable. It could for example devote a register in non-static member functions to storing this. If you take a const reference, then unless the use permits cunning optimization it needs to be copied somewhere that has an address, but at least it needn't be the same address if you do it twice in quick succession, as it would need to be if this were a declared variable.
You get a compiler error because this is a const pointer to the instance of the class of the same type as that class. You can't assign to it although you can use it to change other class members in non-const qualified methods, call methods, and operators. Also note because it's an instance that static methods do not have a this pointer.
Hypothetical:
class Whatever
{
// your error because this is Whatever* const this;
void DoWhatever(const Whatever& obj) { this = &obj; }
// this is ok
void DoWhatever(const Whatever& obj) { *this = obj; }
// error because this is now: const Whatever* const this;
void DoWhatever(const Whatever& obj) const { *this = obj; }
// error because this doesn't exist in this scope
static void DoWhatever(const Whatever& obj) { *this = obj; }
};
Recently while I was explaining the basic difference between pointers and references(in context of C++ programming) to someone, I told the usual explanations which talk about different function argument passing conventions - Call by value, Call by pointer, Call by reference, and all the associated theory about references.
But then I thought whatever a C+ reference does in terms of argument passing,(Allows a memory efficient way of passing large structures/objects, at same time keeps it safe by not allowing the callee to modify any variables of the object passed as reference, if our design demands it)
A const pointer in C would achieve the same thing , e.g. If one needs to pass a structure pointer say struct mystr *ptr, by casting the structure pointer as constant -
func(int,int,(const struct mystr*)(ptr));
will ptr not be some kind of equivalent to a reference?
Will it not work in the way which would be memory efficient by not replicating the structure(pass by pointer) but also be safe by disallowing any changes to the structure fields owing to the fact that it is passed as a const pointer.
In C++ object context, we may pass const object pointer instead of object reference as achieve same functionality)
If yes, then what use-case scenario in C++, needs references.
Any specific benefits of references, and associated drawbacks?
thank you.
-AD
You can bind a const reference to an rvalue:
void foo(const std::string& s);
foo(std::string("hello"));
But it is impossible to pass the address of an rvalue:
void bar(const std::string* s);
bar(&std::string("hello")); // error: & operator requires lvalue
References were introduced into the language to support operator overloading. You want to be able to say a - b, not &a - &b. (Note that the latter already has a meaning: pointer subtraction.)
References primarily support pass by reference, pointers primarily support reference semantics. Yes I know, the distinction isn't always quite clear in C++.
There are two typical use-case scenarios:
First: Pointers denote optional arguments. Since, references cannot be NULL, but pointers can, document in the coding style that any argument that is notated as pointer, may be NULL, the function needs to handle that. Optional arguments can then be const or non-const, as can mandatory (reference) arguments.
Second: References are only used in conjunction with the const keyword, because the calling syntax suggests to the reader pass-by-value semantics, which is by definition constant. Then pointers are only used for arguments that can be changed by the callee.
I personally prefer the first option, because there each of the four cases "const reference", "non-const reference", "const pointer", "non-const pointer" has a different meaning. Option two only differentiates between two "things": "function may modify that value" vs. "function will not modify that value".
In terms of the referent object, what code can manipulate given a const reference is the same as what it can do with a pointer to a const object, and similarly what it can manipulate given a non-const reference is the same as given a pointer to a non-const object.
What a reference prevents the called function from doing is changing which object the reference refers to, or pointer arithmetic on the reference.
In terms of the caller, a const reference can be bound directly to an rvalue, and you have well defined semantics when creating and destroying objects passed as arguments. This is a common idiom - to construct a temporary for an argument:
// declaration
void bar ( const Foo& );
// use
bar ( Foo() );
But it isn't immediately obvious that the Foo object in these has a lifespan which exceeds the length of the function call:
// declaration
void bar ( const Foo* );
// use
Foo temp;
bar ( &temp );
// cast to avoid warning about taking address of temporary
bar ( &static_cast<const Foo&>( Foo() ) );
// helper function to same effect
template<typename T> const T* address_of ( const T& t) { return &t; }
bar ( address_of ( Foo() ) );
Though obviously the latter, being just a function call, should make it obvious it does.
Basically, the references are syntactic sugar for pointers which point to single objects, not the start of arrays.
What is the difference between:
const double& pi = 3.14;
and (no ampersand):
const double pi = 3.14;
They both seem to have the same L and R values so what is the difference?
For your particular example there's no difference.
And that means, no way to tell them apart, whatsoever.
However, since the first binds a reference to a temporary, when the type is of class type the temporary can be of a derived class, e.g. produced by a function! And it then has its destructor properly called at the end of the scope. This little el neato trick is used in ScopeGuard implementations (see the original ScopeGuard article in DDJ, by Petru Marginean and Andrei Alexandrescu -- Petru invented ScopeGuard and Andrei made a more general thing on top).
I once asked Bjarne Stroustrup, who created the C++ language, why the syntax in your first declaration is supported.
And his reply was that it was mostly to have uniform rules (i.e. to not make any special exception for local references as opposed to references as formal parameters). I think at that time neither of us were familiar with ScopeGuard. It's simple in retrospect, but it takes a mind like Petru's, or Andrei's, to come up with something like that! :-)
Cheers & hth.
The important difference with a reference is that a reference itself is inheritly constant. Once the reference itself has been initially assigned to a variable, it can not then reference another variable. All attempts to modify it will modify the variable it refers to. Given this, the const will mean that the reference is a reference to a const int.
const int A;
const int B;
const int& Reference = A;
Reference = B; // Error, the value of A can not be assigned, nor would this *ever* be able to make Reference refer to B.
You can also test this theory about a reference itself being constant like so:
const int& const Reference; // Should give a warning about the second const being redundant.
A bit of clarification about constant references, references and constants for doubles.
Reference
A reference refers to an existing an object and cannot be reseated. That is, once you declare (define) the reference, it will always refer to that item.
Constant Reference
The C++ language allows for declaring of a constant reference. This tells the compiler that the reference will not change. This may be redundant since references cannot be reseated. However, the language syntax allows it.
Constant
A constant is a value, and does not refer to anything.
Optimizations & Substitutions
The compiler is allowed to substitute (replace) a reference to an object, constant or literal with the corresponding object, constant or literal, provided that the compiler can guarantee that no write operations are performed to that object within the scope it is used in. This determination may become difficult when the reference is passed to methods or functions within that scope.
Specifying the const modifier to a reference will make the compiler's job easier for optimizing. The constant reference is a contract with the programmer and user that the reference will not be changed.
const double& is a reference to a constant double, the other one is a constant double. A reference is kind of a const pointer, a pointer that never changes.
In C++ the references are inherently const. Once they have been assigned you can not changes them. They must be both declared and initialized.
The reference isnt const only the value is const, so you should be able reassign referense, that means the following would be ok:
const double& pi = 3.14;
const double pi2 = 2.78;
pi = *(&pi2);
Which is better:
bool MyClass::someQuery() const;
const bool MyClass::someQuery() const;
I've been using 'const bool' since I'm sure I remember hearing it's "what the ints do" (for e.g. comparison operators) but I can't find evidence of that anywhere, mostly due to it being difficult to Google and Intellisense not helping out any ;) Can anyone confirm that?
To me returning const values (this isn't just about bools) makes more sense; it'll prevent temporaries being modified, which is almost always going to be a programmer mistake. I just want something to back that up so I can extol returning const values to my colleagues :)
This is the case when const adds no value but inflates the code and makes the reader think more. What's the point of this const? The caller can copy the value into some non-const variable and do whatever he wants with it anyway.
So you know it's right, you're just after the Voice of Authority?
Preventing accidental modification of temporaries is very valuable. In general, you should declare as many things as you possibly can const, it protects you from a variety of accidents and gives the optimiser useful hints.
D'you have a copy of Scott Meyers' "Effective C++" around? Point them at Item 3 (page 18 in the third edition) ;)
It gives the example of
class Rational {...};
const Rational operator* (const Rational& lhs, const Rational& rhs );
if( (a * b) = c ) // declaring operator *'s return value const causes error to be caught by compiler
Note that if((a*b) = c) won't compile for built-in types anyway, so it is very relevant here whether we're talking built-in types (your question asks for bool) or user-defined types.
For built-in types it makes no sense at all, so it shouldn't be used. And for user-defined types, I'm in jalf's camp: What if the caller wants to modify the returned object?
I'm not convinced that if((a*b) = c) is such a good argument for returning const user-defined types, since I can't remember the last time I've seen a compiler not warn about this.
To be a little more specific, only "objects" can be const. The C++ standard's definition of "object" includes everything an lvalue refers to ("has a name") and class-type temporaries. A boolean return value is an rvalue of a non-class type which is why a standards-compliant compiler will just ignore "const" in this case. As others said already, it's useless in this context.
When you returning a refernce to a member variable it makes sense to make it const. Here you are returning a copy, hence there is no need of const.
The const modifier is only used for return types that are returned by reference (either as reference const SomeObject& or via a pointer const SomeObject*), so the caller won't be able to modify the object via the reference/pointer. Primitive types are returned by value, which means that the caller receives a copy of the the object, not the object itself.
Therefore, const is not really appropriate for returned value types. Since the copy is outside of the control of the called function, the called function should not dictate to the caller that it cannot be changed.
This is an ancient post, but I think it's worth mentioning there is a potential corner case here since C++11. While, as stated by others, it will make no difference whether you use const bool or bool as return type in most cases, if you are using C++11 decltype and associates, e.g. result_of, you could declare a variable with the same type as the returning value of some function, and so the const would actually have an effect in this case.
It completely doesn't matter. Therefore, the consensus is to return just bool.
The reason that it doesn't matter is that you can't call non-const member functions anyway; bool is not a class or struct.
As bool is going to be copied, it's the same, to put const or not. Plus you'll may have some compil problems.
const return type
SUMMARY:
The value of a return type that is
declared const cannot be changed. This
is especially usefull when giving a
reference to a class’s internals, but
can also prevent rarer errors.
const bool func();
bool f = func();
0 errors, 0 warnings. What have you accomplished other than unnecessary code inflation?