Constant Reference Wrapper - c++

I came across the following piece of code in the book on data structures by Mark Allen Weiss.
template <class Object>
class Cref
{
public:
Cref ( ) : obj ( NULL ) { }
explicit Cref( const Object & x ) : obj ( &x ) {
const Object & get( ) const
{
if ( isNull( ) )
throw NullPointerException( ) ;
else
return *obj;
}
bool isNull( ) const
( return obj == NULL; }
private:
const Object *obj;
};
So the point here is to assign null/initialize a constant reference. But I am not sure I understand the following:
1. We initialize a constant reference with another constant reference x. But why is it again done as obj(&x) ? the & in const Object & x is different from the &x in obj(&x) ? I see this but not very clear why it should be so. Pls explain.
2. The get method() - We try to return a const reference of the private member obj of this class. It is already a const reference. Why return *obj and not just obj ?
3. Why explicit keyword ? What might happen if an implicit type conversion takes place ? Can someone provide a scenario for this ?
Thanks

The member obj is of type Object*, but the constructor takes a reference. Therefore to get a pointer, the address-of operator, &, has to be applied. And the member is a pointer because it can be NULL (set in the default constructor), and references never can be NULL.
The private member is not a const reference, but a poinetr to const. It is dereferenced to get a reference.
In this specific case, I cannot see any negative effect of a potential implicit conversion either.

1) &x in obj(&x) is used as the address-of operator.
2) No, it is a pointer. Its time is Object *, not Object &.
3) To prevent casting from incompatible pointer types which might have their own type-cast operator.
C++ has three flavors of null available:
NULL - obsolete; use it only for checking the return values of C functions which return pointers
0 - deprecated; the literal zero is defined in the Standard to be the null pointer
nullptr - as of C++11, this is the preferred way of testing for null. Furthermore, nullptr_t is a type-safe null.

1) The token & has three meanings:
Unary address-of operator: Take the address of any lvalue expression, giving a pointer to that object.
Reference sigil: In a declaration, means a reference type.
Binary bitwise AND operator - not used here
So it's important to know whether you're looking at a declaration or an expression.
explicit Cref( const Object & x )
Here the sigil appears in the declaration of a function parameter, meaning the type of parameter x is a reference to an Object which is const.
: obj ( &x ) {}
Here the operator is used in a member initializer expression. Member obj is initialized to be a pointer to x.
2) Since member obj is actually a pointer, the dereference operator unary * is needed to get a reference.
3) In general, it's a good idea to use explicit on any (non-copy) constructor which can take exactly one argument. It's just unfortunate that the language doesn't default to explicit and make you use some sort of "implicit" keyword instead when you mean to. In this case, here's one rather bad thing that could happen if the constructor were implicit:
Object create_obj();
void setup_ref(Cref& ref) {
ref = create_obj();
}
No compiler error or warning, but that setup_ref function stores a pointer to a temporary object, which is invalid by the time the function returns!

1) The type of obj is not a reference, obj is a pointer, and a const pointer must be initialized with a address, so, the address-of operator, &, must be applied.
2) The reference the get() method returns is not a reference to the class member obj, but a reference to the object which obj points, so you have to use * to deference it.
3) The keyword explicit means we reject the implicit conversions, that is, we tell the compiler, don't make implicit conversions with this constructor for us.
Example:
class Cref<Object> A;
Object B;
A=B;
It's OK without the explicit--Since we need a Cref object on the right side, the compiler will automate making a Cref object with constructor Cref( const Object & B ). But if you add an explicit, the compiler won't make conversions, there will be a compiling error.

Related

Why do we return *this in asignment operator and generally (and not &this) when we want to return a reference to the object?

I'm learning C++ and pointers and I thought I understood pointers until I saw this.
On one side the asterix(*) operator is dereferecing, which means it returns the value in the address the value is pointing to, and that the ampersand (&) operator is the opposite, and returns the address of where the value is stored in memory.
Reading now about assignment overloading, it says "we return *this because we want to return a reference to the object". Though from what I read *this actually returns the value of this, and actually &this logically should be returned if we want to return a reference to the object.
How does this add up? I guess I'm missing something here because I didn't find this question asked elsewhere, but the explanation seems like the complete opposite of what should be, regarding the logic of * to dereference, & get a reference.
For example here:
struct A {
A& operator=(const A&) {
cout << "A::operator=(const A&)" << endl;
return *this;
}
};
this is a pointer that keeps the address of the current object. So dereferencing the pointer like *this you will get the lvalue of the current object itself. And the return type of the copy assignment operator of the presented class is A&. So returning the expression *this you are returning a reference to the current object.
According to the C++ 17 Standard (8.1.2 This)
1 The keyword this names a pointer to the object for which a
non-static member function (12.2.2.1) is invoked or a non-static data
member’s initializer (12.2) is evaluated.
Consider the following code snippet as an simplified example.
int x = 10;
int *this_x = &x;
Now to return a reference to the object you need to use the expression *this_x as for example
std::cout << *this_x << '\n';
& has multiple meanings depending on the context. In C and used alone, I can either be a bitwise AND operator or the address of something referenced by a symbol.
In C++, after a type name, it also means that what follows is a reference to an object of this type.
This means that is you enter :
int a = 0;
int & b = a;
… b will become de facto an alias of a.
In your example, operator= is made to return an object of type A (not a pointer onto it). This will be seen this way by uppers functions, but what will actually be returned is an existing object, more specifically the instance of the class of which this member function has been called.
Yes, *this is (the value of?) the current object. But the pointer to the current object is this, not &this.
&this, if it was legal, would be a pointer-to-pointer to the current object. But it's illegal, since this (the pointer itself) is a temporary object, and you can't take addresses of those with &.
It would make more sense to ask why we don't do return this;.
The answer is: forming a pointer requires &, but forming a reference doesn't. Compare:
int x = 42;
int *ptr = &x;
int &ref = x;
So, similarly:
int *f1() return {return &x;}
int &f1() return {return x;}
A simple mnemonic you can use is that the * and & operators match the type syntax of the thing you're converting from, not the thing you're converting to:
* converts a foo* to a foo&
& converts a foo& to a foo*
In expressions, there's no meaningful difference between foo and foo&, so I could have said that * converts foo* to foo, but the version above is easier to remember.
C++ inherited its type syntax from C, and C type syntax named types after the expression syntax for using them, not the syntax for creating them. Arrays are written foo x[...] because you use them by accessing an element, and pointers are written foo *x because you use them by dereferencing them. Pointers to arrays are written foo (*x)[...] because you use them by dereferencing them and then accessing an element, while arrays of pointers are written foo *x[...] because you use them by accessing an element and then dereferencing it. People don't like the syntax, but it's consistent.
References were added later, and break the consistency, because there isn't any syntax for using a reference that differs from using the referenced object "directly". As a result, you shouldn't try to make sense of the type syntax for references. It just is.
The reason this is a pointer is also purely historical: this was added to C++ before references were. But since it is a pointer, and you need a reference, you have to use * to get rid of the *.

Why is conversion from const pointer-to-const to const pointer-to-nonconst in an initializer list allowed

I read the question posted on
Why does C++ not have a const constructor?
I am still confused why that program can compile. And I tried to offer my opinion on the question, I don't know why it was deleted. So I have to ask the question again.
Here is the program
class Cheater
{
public:
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) //conceptually odd legality in const Cheater ctor
{}
Cheater& getCheaterPtr() const {return *cheaterPtr;}
int value;
private:
Cheater * cheaterPtr;
};
int main()
{
const Cheater cheater(7); //Initialize the value to 7
// cheater.value = 4; //good, illegal
cheater.getCheaterPtr().value = 4; //oops, legal
return 0;
}
And my confusion is :
const Cheater cheater(7)
creates a const object cheater, in its constructor
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) //conceptually odd legality in const Cheater ctor
{}
'this' pointer was used to initialize cheaterPtr.
I think it shouldn't be right. cheater is a const object, whose this pointer should be something like: const Cheater* const this; which means the pointer it self and the object the pointer points to should both const, we can neither change the value of the pointer or modify the object the pointer points to.
but object cheater's cheaterPtr member is something like Cheater* const cheaterPtr. Which means the pointer is const but the object it points to can be nonconst.
As we know, pointer-to-const to pointer-to-nonconst conversion is not allowed:
int i = 0;
const int* ptrToConst = &i;
int * const constPtr = ptrToConst; // illegal. invalid conversion from 'const int*' to 'int*'
How can conversion from pointer-to-const to pointer-to-nonconst be allowed in the initializer list? What really happened?
And here is a discription about "constness" in constructors I tried to offer to the original post:
"Unlike other member functions, constructors may not be declared as const. When we create a const object of a class type, the object does not assume its 'constness' until after the constructor completes the object's initialization. Thus, constructors can write to const objects during their construction."
--C++ Primer (5th Edition) P262 7.1.4 Constructors
If constructors were const, they couldn't construct their object - they couldn't write into its data!
The code you cite as "legal:"
cheater.getCheaterPtr().value = 4; //oops, legal
is not actually legal. While it compiles, its behaviour is undefined, because it modifies a const object through a non-const lvalue. It's exactly the same as this:
const int value = 0;
const int * p = &value;
*const_cast<int*>(p) = 4;
This will also compile, but it's still illegal (has UB).
Your assumptions are incorrect. Taking them one at a time, first code annotation.
class Cheater
{
public:
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) // NOTE: perfectly legal, as *this is non-const
// in the construction context.
{}
// NOTE: method is viable as const. it makes no modifications
// to any members, invokes no non-const member functions, and
// makes no attempt to pass *this as a non-const parameter. the
// code neither knows, nor cares whether `cheaterPtr`points to
// *this or not.
Cheater& getCheaterPtr() const {return *cheaterPtr;}
int value;
private:
Cheater * cheaterPtr; // NOTE: member pointer is non-const.
};
int main()
{
// NOTE: perfectly ok. we're creating a const Cheater object
// which means we cannot fire non-const members or pass it
// by reference or address as a non-const parameter to anything.
const Cheater cheater(7);
// NOTE: completely lega. Invoking a const-method on a const
// object. That it returns a non-const reference is irrelevant
// to the const-ness of the object and member function.
cheater.getCheaterPtr().value = 4;
return 0;
}
You said:
I think it shouldn't be right. cheater is a const object whose this pointer should be something like: const Cheater* const this
cheater is const after construction. It must be non-const during construction. Further, the constructor does not (and cannot) know the caller has indicated the object will be const. All it knows is its time to construct an object, so thats what it does. Furthermore, after construction &cheater is const Cheater *. Making the actual pointer var itself also const is simply non-applicable in this context.
And then...
...object cheater's cheaterPtr member is something like Cheater* const cheaterPtr;
This is actually an incredibly accurate way to describe this. Because cheater is const its members are as well, which means the cheaterPtr member is const; not what it points to. You cannot change the pointer value, but because it is not a pointer-to-const-object you can freely use that pointer to modify what it points to, which in this case happens to be this.
If you wanted both the pointer and its pointed-to-object to be const you whould have declared it as const Cheater *cheaterPtr; in the member list. (and doing that, btw, makes only that mutable action through the getCheaterPointer() invalid. It would have to return a const Cheater* as well, which means of course the assignment would fail.
In short, this code is entirely valid. What you're wanting to see (construction awareness of the callers const-ness) is not part of the language, and indeed it cannot be if you want your constructors to have the latitude to... well, construct.

how *return implicitly return a reference

this is a const ptr to the object/instance which a member function receive implicitly, so how does return *this returns a reference ?
As of what I know , a pointer dereferencing to a variable means it holds it's memory address , so return *this should return value dereferenced by this const pointer which is what? An object?
Also, why you can't do something like this:
Calc cCalc;
cCalc.Add(5).Sub(3).Mult(4);
Without having all that member functions to return *this?
I would want to know how pointers and reference treat objects/instances.
Let's try to untangle:
this is a const ptr to the object/instance which a member function receive implicitly
member functions indeed receive this pointer implicitly. The type is T* or const T* depending on the member function signature -- you get const placing const keyword at the tail after the ().
so how does return *this returns a reference ?
*this dereference the pointer, thus creating lvalue of type T or const T respectively. If your question is meant how you get T& from *this in a const funstion, the answer that you don't, that attempt would be ill-formed code.
As of what I know , a pointer dereferencing to a variable means it holds it's memory address , so return *this should return value dereferenced by this const pointer which is what? An object?
*this denotes the instance. And it is lvalue expression. So you can get its address agan (providing same as this), or can bind it to a reference -- including the case for a return.
The chaining you show can actually be done if the functions returned Calc instead of Calc& or returned some different object than *this -- but then the result of calculations would end up in that place. Not where you expect it: in cCalc.
As it stands, when all three functions return *this leads first Add taking &cCalc in this, and returns cCalc. The next call to Sub has the same situation. And Multiply too.
Add member doesnt have Sub function. Compiler give an error.
But, if you return *this, you are returning your own object (not reference). Now you have one cCalc object that can use Sub(3). Sub(3) return your object and can use Mult(4).

Why do we use the reference operator twice?

My question refers to pointers with classes and the keyword this.
class class1 {
public:
bool isitme(class1& temp){
if(this == &temp)
return true;
else return false;
}
};
int main () {
class1 c3;
class1* c2 = &c3;
if(c3.isitme(*c2))
cout << "c3 == c2"; //it is returning that
system("pause");
}
The code above is working, but what I do not understand is why it works only when bool isitme(class1& temp) and if(this == &temp) are in the same function isitme().
I mean, we already read the block of memory class1& temp of temp in the class parameters and should be able to compare that block of memory with the keyword this. Why is the function only true when I double get the reference (this == &temp)?
Thanks
this is a pointer, whereas temp is a reference. When you write &temp in your if statement, you are taking the address of temp. This converts it to a pointer that can then be compared to this.
Do not confuse reference declarations with use of the address-of operator. When & identifier is preceded by a type, such as int or char, then identifier is declared as a reference to the type. When & identifier is not preceded by a type, the usage is that of the address-of operator.
Taken from: http://msdn.microsoft.com/en-us/library/w7049scy(v=vs.71).aspx
It's been a while since c/c++ days, but let me take a stab at this...
You're not using the reference operator twice. When you specify class1& you're only specifying the type of the parameter (the type is "reference of type class1"), not actually doing anything to temp. Later you actually dereference the parameter with &temp. It's only the second appearance of the ampersand that actually is a reference operator.
The & operator within the method declaration simply means that the object passed should not be copied, but rather point to the same location as the object passed to it (it's a reference). The & operator in if(this == &temp) is needed to actually get the address of that object (a pointer) so that you can compare it to the this pointer.
The reference "operator" in the signature of the isitme method denotes a reference, that is, an alias for the object itself.
On the other hand, in the line if(this == &temp), the operator is used directly on the object and thus returns the address of the object (a pointer to it).
So, if you want to check if the entered reference is equal to this, you need to compare to a pointer, which is exactly what the referance operator returns.
& in the class parameter list means the object is passed by-reference. That is, temp is an alias for the class1 object. &temp is simply taking the address of that object and comparing it to the object pointed to by this. The two syntaxes are semantically different, you're not taking the address twice.

Is using "operator &" on a reference a portable C++ construct?

Suppose I have:
void function1( Type* object ); //whatever implementation
void function2( Type& object )
{
function1( &object );
}
supposing Type doesn't have an overloaded operator &() will this construct - using operator & on a reference - obtain the actual address of the object (variable of Type type) on all decently standard-compliant C++ compilers?
Yes, and the reason is that on the very beginning of evaluating any expression, references are being replaced by the object that's referenced, as defined at 5[expr]/6 in the Standard. That will make it so the &-operator doesn't see any difference:
If an expression initially has the type "reference to T" (8.3.2, 8.5.3), the type is adjusted to "T" prior to any further analysis, the expression designates the object or function denoted by the reference, and the expression is an lvalue.
This makes it so that any operator that operates on an expression "sees through" the reference.
Yes, it takes the address of the object referred to. Once you have an initialised reference, ALL operations on it are performed on the referred to object.
This is actually a fairly frequently used trope:
struct A {
A( X & x ) : myx( &x ) {}
X * myx;
};
Yes, in 15 characters or more.