I try to find address of this pointer, but this code is showing a strange
error:
#include <iostream>
using namespace std;
class Base
{
public:
void test()
{
void *address_of_this =&this;
cout<<address_of_this<<endl;
}
};
int main()
{ Base k;
k.test();
return 0;
} //error non-lvalue in unary'&'
Can you explain this error ?
Also point that what is illegal in taking address of this?
this is a pointer containing the address to the "current object". It is not a variable that is stored somewhere (or could even be changed), it is a special keyword with these properties.
As such, taking its address makes no sense. If you want to know the address of the "current object" you can simply output:
std::cout << this;
or store as
void* a = this;
Quoting the 2003 C++ standard:
5.1 [expr.prim] The keyword this names a pointer to the object for which a nonstatic member function (9.3.2) is invoked. ... The type of the expression is a pointer to the function’s class (9.3.2), ... The expression is an rvalue.
5.3.1 [expr.unary.op] The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified_id.
To put it simply, & requires an lvalue. this is an rvalue, not an lvalue, just as the error message indicates.
this refers to the current object by using it's address.
In your problem, there are two errors:
this is not an lvalue.
The & requires an lvalue. lvalues are those that can appear on on the left-hand side of an assignment (variables, arrays, etc.).
Whereas this is a rvalue. rvalues can not appear on the left-hand side (addition, subtraction, etc.).
Reference: C++ Rvalue References Explained.
A hidden error which I'd like to also mention is thus:
address_of_this is actually receiving an address of an address.
Basically, &this is translated into something like &&object or &(&object).
Basically, think of this as &object (but only to remember because it is not that true).
Related
I have found multiple questions regarding the lvalue yielded by the arrow operator and the lvalue or rvalue yielded by the dot operator, but the answers are not quite coherent.
Chapter 4.6 of the book C++ Primer says:
The arrow operator requires a pointer operated and yields an lvalue. The dot operator yields an lvalue if the object from which the member is fetched is an lvalue; otherwise, the result is an rvalue.
Does the author only mean data members, or also member functions that can be used as an lvalue? Can someone give me an example where the behaviour of these two operators differs, and explain why that is?
Please excuse me if this has been answered elsewhere.
The quote is much easier to understand with some examples. I'll start with the "dot" operator first.
The "dot" operator
Lets consider data members first with a simple Person example:
struct Person {
std::string name;
};
In general when people use a struct or class, you'll normally see it accessed through a named-value which will always yield the standard/expected lvalue reference:
auto person = Person{"Foo"}
std::string& name = person.name;
However, this doesn't always have to be an lvalue. This member access through the "dot" operator will propagate the refness of the object being accessed. That means that you can implicitly get an rvalue ref of name if person is an rvalue (XValue):
auto person = Person{"Foo"};
std::string&& name = std::move(person).name;
Try it Online
or as a temporary (PRValue):
// Note: using a function call here so that the reference doesn't dangle
auto consume(std::string&&) -> void;
...
consume( Person{"Foo"}.name );
Try it Online
This is what the quote is referring to when it says:
The dot operator yields an lvalue if the object from which the member is fetched is an lvalue; otherwise, the result is an rvalue.
This value-propagation is somewhat true of member functions as well. Since C++11, it's been possible to ref-qualify member functions -- which will call the appropriate function based on the refness of the underlying object:
class Person {
...
auto get_name() && -> std::string&&;
auto get_name() const & -> const std::string&;
...
private:
std::string m_name;
};
...
auto person = Person{...};
person.get_name(); // calls 'get_name() const &'
std::move(person).get_name(); // calls 'get_name() &&'
Try it Online
Note: Unlike accessing a data member, the result of the function call need not actually match the value-category; this is just used for determining which function to call as a form of overload resolution.
Arrow Operator
For the default arrow operator (e.g. not a custom operator->), it can only operate on pointers. Pointers, unlike references, don't contain the underlying value-category of the pointee; they only know the value category of the pointer itself.
For example, std::moveing a Person* will yield a Person*&& -- which is an rvalue of the pointer, but not of the underlying pointed object. For this reason, dereferencing through operator-> can never yield an rvalue, since the pointee is never known to be an rvalue.
Custom operator-> definitions
The Arrow operator is also interesting because, for a custom class, it can be overloaded by defining operator->() -- but this operator will still be constrained by the same problem as described above!
Any definition of operator-> must return an object which either defines operator->, or is a pointer. This is done because any expression a->b in C++ will recursively call operator-> until it reaches a pointer in order to perform the dereference. As we know from above, a pointer does not contain a value category -- so once we reach this point we cannot get an rvalue.
Even if you were to attempt to combine this with ref-qualified functions, such as:
auto operator->() && -> SomeWrapper<T>;
you still won't be able to propagate the value-category to the reference because eventually it will come back down to a pointer which does not contain a value category.
Preface: the C++ system of value categories is rather abstruse; the terms 'lvalue' and 'rvalue' really aren't the whole story, so if you want the full explanation of value categories in all its technical glory, I advise you to check out https://en.cppreference.com/w/cpp/language/value_category as #Richard Critten said in the question comments.
Now, supposing you have a struct
struct S{
int member {5};
};
, the behaviour of the operators will differ when performing member access on temporary objects—since their addresses cannot be taken, member access can only take the form of the dot operator (since no pointer can be produced for the arrow operator):
int x = S().member; // Ok, x = 5
int x = (&(S()))->member; // Error: cannot take address of temporary object
In this case, S() is an rvalue expression, and we can use the dot operator on it, but there isn't really a way to use the arrow operator on it.
Regarding "member functions that can be used as an lvalue", I'm assuming you mean functions that return an lvalue reference, e.g.
struct S {
int member {5};
int& get_ref()
{
return member;
}
}
where the returned lvalue reference can be written to; I don't believe that there is any functional difference with the normal member access case.
I'm a rusty amateur C++ programmer coming back after along time and moving on from OpenGL 2.0 to Vulkan.
I'm trying to understand the code behind the tutorials I'm reading not just copy, but don't understand the & part of the following:
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
Why is the & after exception? My understanding is the pointer is usually after the variable and the address before it, such as:
int* pintVar;
pintVar = &intVar;
Has this got something to do with binding a constant reference 'exception' to a temporary object 'e'?
As you can see I'm trying to research/google it but not totally understanding it or why.
Any help would be appreciated.
& has different meanings depending on context. In a declaration, it means reference to. e.g.
int a = 42;
int &b = a; // b is a reference to a
// b is essentially an alias of a (they both have the same address, for example)
// i.e. changes to b will be reflected in a, and vice versa
Here's some reference that explains this in more depth.
When & is used on an already existing variable, this means address-of. e.g.
int a = 42;
int *b = &a; // b points to a (i.e. b holds the address of a).
So in your example, e is a const reference to whatever exception is passed in (since the parameter of a function declares a variable).
Analogous question:
int* pintVar;
"Why is the * after int? What is the indirection operator doing there? Why isn't it before the variable name such as in here?"
int intVar = *pintVar;
Well, you see * symbol has multiple meanings. Perhaps you already understand this: Within a compound type name, it signifies a pointer type. Within an expression it signifies an operator. It can be either the unary indirection operator (*pintVar) or the binary multiplication operator (a * b).
In the exactly same way, & symbol has multiple meanings. Within a compound type name, it signifies a reference type. Within an expression it signifies an operator. It can be either the unary addressof operator (&intVar) or the binary bitwise AND operator (a & b).
So, const T& is a reference to const T, just like const T* would be a pointer to const T.
Both reference and pointer are forms of indirection, and are quite smilar. Their differences are:
Pointers are objects, references are not objects
Because references are not objects, there is no way to take the address of a reference, and there is no such thing as a pointer to reference or a reference to reference.
There are also no arrays of references.
A (non-const) pointer can be assigned to point to another object. A reference is bound to a single object for its entire lifetime.
Pointer can be null, a reference cannot be.
You must indirect through a pointer explicitly using an indirection operator. All operations on a reference implicitly indirect through the reference, and apply to the referred object instead.
Assignment of reference is assignment of the referred object.
Taking the address of a reference variable is taking address of the referred object.
Pointers are iterators for arrays; You can do pointer arithmetic to iterate the elements. Adding one to a pointer results in pointer to the successive array element. There is no reference arithmetic. Because of the implicit indirection, adding one to reference adds one to the referred object.
Has this got something to do with binding a constant reference 'exception' to a temporary object 'e'?
There are many right words there, but I don't understand what you are trying to mean by them.
e is a variable. The type of the variable is const std::exception& i.e. reference to constant exception. Upon throw, the reference is bound to the exception object that was thrown.
class A {}
A foo() {
A a;
// some work
return a;
}
Here it returns an instance of A, and I saw many readings saying that this returns a rvalue.
My confusion is, since it's perfectly legit to do A b; a = b;, the variable a seems to be an lvalue. So why does it become rvalue when it's the returned one?
There is no such thing as an rvalue object.
Rvalue and lvalue refers to expressions.
One expression that refers to an object can be an rvalue, while another that refers to the same object can be an lvalue.
Originally "lvalue" referred to any expression that could be on the left hand side of C's =, while "rvalue" was any expression that could only be on the right side. Since then C++ has acquired const and references, and things have got complicated. But the early C view of things is useful to understand this.
Regarding …
” the variable a seems to be an lvalue. So why does it become rvalue when it's the returned one?
Well, the variable in itself is not an lvalue. The expression a is an lvalue. And the function does not return the variable: it returns the variable's value.
So, as I understand it there are two misconceptions involved in the question:
The idea that lvalue/rvalue is about objects. It's about expressions.
The idea that A foo() { return... } return a reference to an object (as in e.g. Java). It returns a value.
An lvalue is an expression that refers to a memory location and allows us to take the address of that memory location via the & operator. An rvalue is an expression that is not an lvalue.
See here http://thbecker.net/articles/rvalue_references/section_01.html
In your example, you're returning a copy of a stack allocated instance. But that is likely also on the stack and is a 'temporary copy', hence you cannot take the address of it. Hence it's not an lvalue, therefore it's an rvalue
Looking at the other questions regarding error C2106, I am still lost as to what the issue is with my code. While compiling I get the following errors:
c:\driver.cpp(99): error C2106: '=' : left operand must be l-value
c:\driver.cpp(169): error C2106: '=' : left operand must be l-value
The line of code is as follows:
payroll.at(i) = NULL; //Line 99
payroll.at(count++) = ePtr; //Line 169
I am failing to understand why this error is being thrown. In this project I have changed my driver.cpp from an array of employee object pointers to a custom Vector template that I made. I declare the Vector as follows...
//Declare an Vector to hold employee object pointers
MyVector <employee*> payroll;
Any help is appreciated...
This error is being thrown for the same reason you can't do something like this:
36 = 3;
Your version of Vector::at should be returning a reference rather than a value.
Lvalues are called Lvalues because they can appear on the left of an assignment. Rvalues cannot appear on the left side, which is why we call them rvalues. You can't assign 3 to 36 because 36 is not an lvalue, it is an rvalue, a temporary. It doesn't have a memory address. For the same reason, you cannot assign NULL to payroll.at(i).
Your definition:
template <class V> V MyVector<V>::at(int n)
What it should be:
template<typename V> V& MyVector::at(std::size_t n)
template<typename V> const V& MyVector::at(std::size_t n) const
The message says that you try to assign to an expression which is not an lvalue. For built-in types, you can only assign to lvalues (that's where the name comes from: lvalue = value that can be on the left hand side of the assignment operator, while rvalue = value that must be on the right hand side of the assignment operator).
So what is an lvalue or an rvalue? Consider the following code:
int a;
a = 3;
In this assignment a is an lvalue (if it weren't, the compiler would complain). That is, the expression a refers to an object which can be modified. On the other hand, 3 is an rvalue, that is, basically a value. Of course you cannot assign to 3; the compiler would complain about the statement 3=a; with exactly the same message you got in your code.
So as a first approximation, an lvalue designates an object, while an rvalue designates a value. Note that this is also true for assignment of the form
a = b;
where b also is a variable. What happens here is the so-called lvalue to rvalue conversion: What is assigned is not the object b, but its current value.
Now consider the following case:
int f();
f() = 3;
Here you might argue that the function f does return an object (if you use some user-defined type, you even can see its construction/destruction). But the compiler still complains with the message you got. Why?
Well, even if you consider f to return an object, it is a temporary object which will go away immediately. So it does not make much sense to assign a value because you cannot do anything with it anyway afterwards.
Therefore here's the second rule:
Whenever there's an expression which produces a temporary object, C++ defines that expression as rvalue.
And now we come to the definition of MyVector::at() which you did not show, but which, according to the error message, probably looks similar to this:
template<typename T>
T MyVector<T>::at(int i)
{
return data[i];
}
This has essentially the same form as f above, as it also returns a T (an employee* in your case). This is why the compiler complains.
And that complaint is helpful: Even if the compiler wouldn't complain, the code would not dio what you almost certainly intended. The return statement returns a copy of the object data[i]. Thus if the statement payment.at(i)=NULL; had compiled, what would actually happen would be the following:
The internal object data[i] (or however you called it in your code) is copied and the temporary copy returned.
The statement assigned that temporary copy, but leaves the original object in MyVector unchanged.
The temporary copy gets destructed, leaving no trace of your assignment.
This is almost certainly not what you wanted. You wanted to change the internal object. To do so, you have to return a reference to that object. A reference refers to the object it was initialized with instead of making a copy. Correspondingly, a reference, even when returned, is an lvalue (since C++11 there's a second type of reference which behaves differently, but we don't need to care about that here). Your corrected function then reads
template<typename T>
T& MyVector<T>::at(int i)
{
return data[i];
}
and with that definition, payment.at(i)=NULL; not only compiles, but actually does what you want: Change the internally stored i-th pointer in payment to NULL.
Your function MyVector::at(unsigned) is probably not correctly declared and looks like this:
T MyVector::at(unsigned i) { /* implementation detail */ }
What you want is for it to look like this:
T& MyVector::at(unsigned i) { /* implementation detail */ }
Notice the reference parameter (&), which will return whatever element by reference and allow the expression to be used as an l-value.
The real question is why aren't you use std::vector instead?
the term l-value in c++ means the 'left-value' is of the improper type. Since you are using the assignment operator on it, to be the proper type it must be a value that can be assigned a new value, which means it can not be a constant. Most likely, your call to payroll.at() is returning a constant value instead of a reference to the actual value. Trying to assign a new value to it will then cause an l-value error.
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; }
};