Overloaded ( ) operator - c++

The spec is to overload the parenthesis () operator to access and assign elements of a matrix, however, I am struggling to figure out what my overload function needs to return.
The Brief Main:
//The .h files and everything has been included, my other functions work just not this one
cout << "Test (): " << endl;
m0(0,0) = 17.25;
m0(1,5) = -2.33;
m0(5,5) = 233; // There is class exception handling I just haven't included it
The Function Implementation:
Matrix* Matrix::operator () (const unsigned int m, const unsigned int n) //We were told they HAD to be unsigned int
{
Matrix *ptr = &matrix[m][n];
return ptr;
}
The Error:
main.cpp: In function ‘int main()’:
main.cpp:59:15: error: lvalue required as left operand of assignment
m0(0,0) = 17.25;
^~~~~
main.cpp:60:16: error: lvalue required as left operand of assignment
m0(1,5) = -2.33;
^~~~
main.cpp:61:15: error: lvalue required as left operand of assignment
m0(5,5) = 233; // should throw an exception
I understand what the error is saying, so please don't just tell me to read it again and fix it. I'm not actually sure how to fix what my function is returning and make it so the double values in the main can actually be assigned to something.
Thanks in advance

If you check this line in your program:
m0(0,0) = 17.25;
You are trying to assign a double value to the value returned by the () operator.
That means that you should return something that allows a double value assigned to it - and the easiest way to do it, is to return a double.
Also, because you want to assign something to it, you should return a reference - otherwise, you would just return a simple temporary value, and assignment isn't allowed for that. Even if the compiler would allow it, you wouldn't see the changes in your matrix, as you would change a temporary value.
I also see that in your current implementation, you are returning a pointer. Pointers are similar to references, but if you think about it, you can't directly assign a value to the memory pointed by a pointer - you have to dereference it first:
double* d = ...; // points to some memory
*d = 5;
And that's why a reference is better in this case.

Related

Why I can take address of *v.begin() where v is a std::vector

#include <vector>
#include <cstdio>
using namespace std;
int f()
{
int* a = new int(3);
return *a;
}
int main()
{
//printf("%p\n", &f());
vector<int> v{3};
printf("%p\n", &(*(v.begin())));
}
I cannot take address of the f(), If I comment "printf("%p\n", &f()); " out I will get error: lvalue required as unary ‘&’ operand.
but how is it possible to take address of *(v.begin())? Isn't * operator the same as a function?
The function f returns a temporary object of the type int
int f()
{
int* a = new int(3);
return *a;
}
You may not apply the address of operator for a temporary object.
You could return a reference to the created dynamically object like for example
int & f()
{
int* a = new int(3);
return *a;
}
And in this case this call of printf written like
printf("%p\n", ( void * )&f());
will be correct.
As for this expression &(*(v.begin())) then the dereferencing operator does return a reference to the pointed object by the iterator.
I cannot take address of the f(), If I comment "printf("%p\n", &f()); " out I will get error: lvalue required as unary ‘&’ operand
We cannot take the address of f() because f returns by value which means that the expression f() is an rvalue of type int which can't be the operand of the & since the operator & requires an lvalue operand which f() is not. This is exactly what the error says.
how is it possible to take address of *(v.begin())?
On the other hand, std::vector::begin returns an iterator to the first element of the vector(in case vector is non empty). Then applying * on v.begin() gives us that first element itself( i.e *(v.begin()) is an lvalue) whose address we can take.
As mentioned in the comments dereferencing interators returns a reference, i.e. a construct similar to a pointer (technically, under the hoods) – you now can take the address of *v.begin() (you don't need parentheses around, . has higher precedence than * anyway) because taking the address of a reference means taking the address of the referred object, which in this case is the first int of the vector. This is just the same as taking the address of a normal object or of the first element in an array, as if, within f, you did &a[0].
On the other hand f itself returns a value – this is just a temporary object that doesn't have a valid address (potentially at least – the value might be returned, according to calling convention, on the stack, then it does have an address, but as well in a CPU register, then there simply is no adress). This value first needs to be assigned to a variable so that you indeed can take the address of.
Indeed v.begin() returns rvalue iterator so &v.begin() will not work. But dereference operator of itirator *v.begin() returns const int& which in turn is lvalue reference what allows to call addressof on it.

overload operator [ ] to enable element assignment

I've already overloaded operator [ ] to enable element access.
definition
double Matrix::operator[ ](const & int i){
return data[i]; // data[] is a member array: thrust:: device_vector
}
usage
Matrix m = ... // initialize
std::cout << m[3] << std::endl;
But now I want to access element by index so that assign new value to it.
usage
m[3] = 0.;
I understand the return value of the operator overload function must be an lvalue. I guess I should return a reference, but not sure how this is done. Thanks!
EDIT
Now I changed my definition to double &, but it still complains:
error: initial value of reference to non-const must be an lvalue
The array refers to a thrust::device_vector, which can be assigned value by index:
Thrust::device_vector<double> M(10);
M[3] = 0.;
Just replace
double ....
with
double& .....
change your definition to
double& Matrix::operator[ ](const & int i){
return data[i]; // data[] is a member array
}
Note, you should not use reference for an integer argument. It is usually used for complex classes for avoiding the copy. I would also suggest as a side note, to use m_memberVariable unless you use pimpl. This is what you should write:
double& Matrix::operator[ ] (const int i) {
return m_data[i]; // data[] is a member array
}
Note, you will need to add the '&' marker also in the class header where the method is declared.
This is all provided you have something like this in the class header:
class Matrix
{
private:
double m_data[100];
public:
double& operator[] (const int i);
};
Here you can read further details on the subscript operator overloading. This is another url for learning more about references.
As for a bit of inline explanation why it works like that:
You are trying to use the subscript operator on the left hand for assignment, hence the return value of such an operator overload has to be an l-value as you correctly state it. This is because if you return a value instead of reference, the left hand side in the usage would simply return that value which would evaluate to x = 0 where replace x with a value like 1. That is why you will get a compiler error in such cases.
Usually you chose to have a pair of operators. One for access:
double Matrix::operator[ ] const (const & int i){
return data[i];
}
and the other for assigment:
double &Matrix::operator[ ](const & int i){
return data[i];
}
If you call [ ] operator on a const object the first operator is really called. In other cases, both in access as well as assgnement, the second one is called.
You get error:
error: initial value of reference to non-const must be an lvalue
because data is (probably) a local variable. Make it a Matrix class private data member if it's not already.

C++ interview about operator

Here is the code which basically implementing the = assignment for a class named CMyString, and the code is right.
CMyString& CMyString::operator =(const CMyString &str) {
if(this == &str)
return *this;
delete []m_pData;
m_pData = NULL;
m_pData = new char[strlen(str.m_pData) + 1];
strcpy(m_pData, str.m_pData);
return *this;
}
The instance is passed by reference, and the first 'if' is checking whether the instance passed in is itself or not. My question is: why does it use &str to compare, doesn't str already contain the address of the instance? Could any one explain how this line works?
Also, I just want to make sure that this contains the address of the object: Is this correct?
isn't str already contains the address of the instance
No. A reference is the object itself. It's not a pointer to the object.
(I. e., in the declaration of the function, &str stands for "reference to str" and not "address of str" - what you're talking about would be right if the function was declared like this:
CMyString& CMyString::operator =(const CMyString *str);
but it isn't.)
Address-of Operator and Reference Operator are different.
The & is used in C++ as a reference declarator in addition to being the address-of operator. The meanings are not identical.
int target;
int &rTarg = target; // rTarg is a reference to an integer.
// The reference is initialized to refer to target.
void f(int*& p); // p is a reference to a pointer
If you take the address of a reference, it returns the address of its target. Using the previous declarations, &rTarg is the same memory address as &target.
str passed by to the assignment operator is passed by reference, so it contains the actual object, not its address. A this is a pointer to the class a method is being called on, so if one wants to compare, whether passed object is the same object itself, he has to get the address of str in order to compare.
Note, that & behaves differently, depending on where it is used. If in statement, it means getting an address to the object it is applied to. On the other hand, if it is used in a declaration, it means, that the declared object is a reference.
Consider the following example:
int i = 42;
int & refToI = i; // A reference to i
refToI = 99;
std::cout << i; // Will print 99
int j = 42;
int * pJ = &j; // A pointer to j
*pJ = 99;
std::cout << j; // Will print 99
this is a pointer to the instance, so yes, it contains the address.
The whole point of verifying, if the passed object is this or not is to avoid unnecessary (or, possibly destructive) assignment to self.
While indeed a variable reference - denoted by the symbol & after the type name - underlying implementation is usually a pointer, the C++ standard seemingly does not specify it.
In its usage anyway, at the syntax level, a reference is used like a non referenced value of the same type, ie. more strictly speaking :
If the type of the variable is T &, then it shall be used as if it were of type T.
If you must write str.someMethod() and not str->someMethod() (without any overloading of the arrow operator), then you must use & to obtain the address of the value. In other words, a reference acts more or less like an alias of a variable, not like a pointer.
For more information about references and pointers, see these questions:
What's the meaning of * and & when applied to variable names?
What are the differences between a pointer variable and a reference variable in C++?
Why 'this' is a pointer and not a reference?

Why cant I pass a non const pointer to a function taking a reference to a pointer to a const as its argument

Here's a code snippet that hopefully conveys what I'm trying to do:
void updatePointer(const int*& i)
{
i++;
}
int main() {
int array[5];
int* arrayPtr = array;
updatePointer(arrayPtr );
return 0;
}
This gives compiler error:
prog.cpp: In function ‘int main()’:
prog.cpp:16: error: invalid initialization of reference of type ‘const int*&’ from
expression of type ‘int*’
prog.cpp:5: error: in passing argument 1 of ‘void updatePointer(const int*&)’
Supposing that you could do it, you could write the following:
const int c = 0;
void updatePointer(const int* &i) {
i = &c;
}
int main() {
int *ptr;
updatePointer(ptr);
*ptr = 1; // attempt to modify the const object c, undefined behavior
}
The purpose of const is to ensure that user code cannot attempt to modify a const object unless it contains a const-cast (or equivalent). So the compiler has to refuse this code. Forbidding a const int*& from binding to an int* is the only place in the code above that's reasonable for the compiler to refuse: every other line is fine.
It's the same reason you can't implicitly convert int** to const int **.
Aside from the motivation in terms of const-safety, you can think if it in terms of int* being a different type from const int*, that just so happens to be convertible to it. Likewise, you can convert int to double, but a double& can't bind to an int lvalue. That's not the full reason, because actually int* and const int* have the same size and representation, whereas int and double don't. So there could be a special-case to allow it if not for the fact that it would break the const system.
The reason that C++ has both const and non-const overloads for strchr is related to this issue: your function updatePointer modifies its input rather than returning the updated value, but the principle is similar. The C-style single strchr allows you to "launder" a pointer-to-const into a pointer-to-non-const without a cast, and it's a hole in the const system. C++ (a) has overloading and (b) has a stricter type system than C, so it closes that hole.
If you want your real function updatePointer to work like strchr -- examine the data pointed to and compute a new value for the pointer, then you're in the same situation that strchr is. That's regardless of what it does with the new value (return it in the case of strchr, write it back in the case of updatePointer), because the issue is that you want the new pointer to have the same const-qualification as the input. You need to provide either const- and non-const overloads or a function template.
If you only need your real function updatePointer to move a pointer by a certain distance, regardless of the data pointed to, you could use std::advance instead.
What you wrote is a function taking a reference to a pointer to a const int. What you're asking for would be
updatePointer(int* const & i);
However this doesn't make much sense. Passing a reference to a pointer seems to imply that you intend to modify the pointer, but you cannot do it because it is declared const. As it is you'd obtain the same effect by just passing your pointer as in
updatePointer(int* i);
Found this
Copied here in case the link breaks in future:
The reasoning is a little awkward to comes to grips with. The main question is:
Since a "const int&" can be bound to an "int", why can't a "const int*&" be bound to a "int*"?
Basically, once you add a level of indirection (a pointer) then the rules change. With just a single level of indirection (as in a single *), the rule can be stated as:
A reference to a pointer to a cv-qualified type can be bound to anything of that same type whose cv-qualifications are less than or equal to that of the pointer (which is a reference).
(Read that a few times.)
So the reason a "const int*&" can't be bound to a "int*" is because "const int*" and "int*" are two different types (underlined part of the rule is broken).

Does dereferencing a pointer make a copy of it?

Does dereferencing a pointer and passing that to a function which takes its argument by reference create a copy of the object?
In this case the value at the pointer is copied (though this is not necessarily the case as the optimiser may optimise it out).
int val = *pPtr;
In this case however no copy will take place:
int& rVal = *pPtr;
The reason no copy takes place is because a reference is not a machine code level construct. It is a higher level construct and thus is something the compiler uses internally rather than generating specific code for it.
The same, obviously, goes for function parameters.
In the simple case, no. There are more complicated cases, though:
void foo(float const& arg);
int * p = new int(7);
foo(*p);
Here, a temporary object is created, because the type of the dereferenced pointer (int) does not match the base type of the function parameter (float). A conversion sequence exists, and the converted temporary can be bound to arg since that's a const reference.
Hopefully it does not : it would if the called function takes its argument by value.
Furthermore, that's the expected behavior of a reference :
void inc(int &i) { ++i; }
int main()
{
int i = 0;
int *j = &i;
inc(*j);
std::cout << i << std::endl;
}
This code is expected to print 1 because inc takes its argument by reference. Had a copy been made upon inc call, the code would print 0.
No. A reference is more or less just like a pointer with different notation and the restriction that there is no null reference. But like a pointer it contains just the address of an object.