What is the meaning and name for "+=" in C++? - c++

I am fairly new to C++ and I have been reading and writing some of my own code. I see these operators from time to time, if that is even the right word to use?
+= // Not sure what it means
So my question is: what do they mean/do, and what are they called?
For further reference, I'd like to know what they are called so I can easily look it up (searching simply for "+=" for instance yielded nothing).
Edit: For anyone else who does not know the meaning (or in my case knew the name of these) I found this Wikipedia link which might come of handy to other people: http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B

Yes, these are operators. More specifically, they are known as compound assignment operators. Here's the full list of them:
*= /= %= += -= >>= <<= &= ^= |=
They are defined like so:
The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once.
So x += 5; is almost the same as x = x + 5;.
You can think of it as a modifying addition. If you just do x + 5, the result of the expression is what you get if you add x and 5 together, but x hasn't changed. If you do x += 5;, x actually has 5 added to its value.

its just an abbreviation:
a+=2; means a=a+2;
of course as many operators: you can overload it to give it alternative meaning, ans actually we do it often to provide meaning for example in the case what it means to add int to our class SomeClass:
SomeClass s;
s+=1; //operator+=(SomeClass& s, int i){} is used here
class A{
public:
A():i_(123){}
~A(){}
int i(){return i_;}
A const& operator+=(int i){
std::cout<<"operator+=";
this->i_=i_+i;
}
private:
int i_;
};
int main(int argc, char** argv) {
A a1;
a1+=3;
std::cout<<a1.i();
return OK;
}
output: operator+=126

Related

Operator Overload Confusion with custom Class

I am following this tutorial on operator overloading: https://www.geeksforgeeks.org/operator-overloading-c/
Code snippet:
class Complex {
private:
int real, imag;
public:
Complex(int r = 0, int i = 0) { real = r; imag = i; }
// This is automatically called when '+' is used with
// between two Complex objects
Complex operator + (Complex const& obj) {
Complex res;
res.real = real + obj.real;
res.imag = imag + obj.imag;
return res;
}
void print() { cout << real << " + i" << imag << endl; }
};
int main()
{
Complex c1(10, 5), c2(2, 4);
Complex c3 = c1 + c2;
c3.print();
}
My question is, how does c++ know what to pass in to &obj and how does it know what to give to real and imag within the operator function? Like how does it know 10 for c1 goes to real and 2 for c2 goes to obj.real? It was never specified which object gets assigned to obj. Hell how does it even know to parse c1's values to real and imag within the operator function?
c1 is the object you're working with. That probably sounds confusing, so let me explain.
When you do this:
c1 + c2;
ignoring the return value for a second, that code is the same as doing this:
c1.operator+(c2);
So, c1 is the base object on which the operator is called. In the same way that c1.print() uses c1's values, calling the operator uses c1's values by default, so to speak.
Why is c1 called here and not c2? Like why isn't it the same as:
c2.operator+(c1);
This is because c1 is on the left hand side. If c2 were on the left hand side, like in the example c2+c1, then operator+() would get called on c2 instead.
So, in short (and other words), C++ uses operator+()(and similar operators) by calling operator+() in the following format:
left.operator+(right);
This allows you to use real and imag like you would in print() for the left side's member variables, and other.real and other.imag for the right side's variables.
So, in the comments you asked a couple more questions that I figure might take more than a comment or two to answer, but are worth answering. So, here goes.
So if you call that + function, it ignores the c3 which I actually assumed was what we were working with, and looks at the left and right hand side of the operation to know what to assign to each side?
Correct. As far as inside the function, operator+() only looks at the objects immediately beside it (in this case, c1 and c2) to perform the calculation.
I am surprised because c3 technically is what I am working with,
Ah, okay. Not for the calculation itself. Let's look at your operator+() closely again:
Complex operator + (Complex const& obj) {
Complex res;
res.real = real + obj.real;
res.imag = imag + obj.imag;
return res;
}
Here, you have a current object (which is where real and imag come from) and another object (which is where obj.real and obj.imag come from). It's these that make up c1 and c2. These are the numbers you are actually adding.
c3, on the other hand, is the result of this addition. If I have something like this:
4 + 3 = 7
The operation 4+3 will have a result: 7. That's what c3 is here. Well, technically, that's what res is here. By returning res, you're returning the result. And in the case of c3, it's setting it's value to the returned result of operator+() via the assignment (=) operator.
Secondly, why do I need to return res?
Already sort of covered that, but to be clear: res is the result of the operation. C++ wouldn't know how to get the result otherwise.
res is only a local variable, wouldn't it's data get destroyed once + is done, instead of it passing the summation data to real and imag?
You seem to be confusing returning by reference and returning by value. If you return a local variable by reference, absolutely. This will get destroyed. However, if you return by value, the result gets copied out almost by definition, so you're totally fine here in this example.

Is it possible to call the << operator using prefix notation?

I am wondering if I could write, for instance: <<(object, cout); or <<(cout,object); where object is a user defined class which has the << operator overloaded, just as one could write:
int a = +(2,3); and obtain the expected result, as in int a = 2 + 3;.
Furthermore, what should one do if this is possible, but requires a few steps? Should one overload the << operator with two different signatures?
just as one could write: int a = +(2,3); and obtain the expected
result, as in int a = 2 + 3;
No, you have a misunderstanding. +(2, 3) will go by the associativity of the comma operator and assign +3 (3) to the variable a.
Therefore, int a = +(2, 3) is the same as int a = 3, and not int a = 2 + 3
I am wondering if I could write, for instance: <<(object, cout); or
<<(cout,object);
No, you can't.
If you want to use the operators in that fashion then you should call its fully qualified name, for example:
operator+ instead of +
operator<< instead of <<
Note:
This will not work for fundamental datatypes. Take care of the class scope and namespaces when you are using the overloaded versions of these operators.
You can do this, e.g.
operator<<(std::cout, "hi");
This expression
int a = +(2, 3);
is not doing operator+. It's first applying the , sequence operator, which gives 3, and then applying unary +, which gives 3.
You can't do this
int a = operator+(2, 3); // error
because ints are fundamental types.
If you have user defined types S, then the following snippets have the same meaning
S s{};
std::cout << s;
auto x = s + s;
is the same as
S s{};
operator<<(std::cout, s);
auto x = operator+(s, s);
assuming the operators are defined for S, the correct operator will be called.

Using operator "/=" at 'declare&initialize' part

I'm a student who got interested in computer science recently. I'm studying C++ because I am interested in embedded systems.
When I tried to test the operator /= on my own. I want to learn about it by doing. The code that I wrote was
int a /= --b + 3;
but the compiler gave me an error message. But when I modified it to
int a = 0;
a /= --b + 3;`
it worked well. I thought it is related to l-values and r-values. Why does the 1st example with operator /= give me an error but the 2nd example above is ok? Can I ask you for some reference to get a hint about this question?
PS: When I tested with
int t = t / (--a + 3);
it worked well too! What is the difference? Can you point me to some document about that?
I would like to mention two things.
What is the meaning of this code?
Is it valid C++ syntax?
Let's take a look at both.
when I tested "int a/=--b+3", it has error but when I modified to "int a=0;
a/=--b+3;" , it works well.
Unlike Java, C/C++ does not automatically initialize integer's value by 0 and it contains a garbage value(called "indeterminate value" officially). So int a/=--b+3; is more like int a; a/=--b+3; which is still be a meaningless value.
And when you declare a variable, C/C++ grammar does not allow /=. Here are the ways for variable declaration and initialization. I'm not sure there is more ways.
int a = 1;
int a(1);
int a{1}; (since C++11)
a /= b;
is the same as:
a = a / b;
so this means that this below statement makes no sense:
int a /= (--b + 3);
Because it's equivalent to:
int a = a / (--b + 3);
Assuming that b has already been defined here; the problem is that a hasn't been defined, and so can't be used as part of the assignment.
The problem here is the same as the problem with this statement:
int a = a;
This also explains why the following code does work:
int a = 0;
a /= (--b + 3);
Because it's equivalent to this:
int a = 0;
a = a / (--b + 3);
Because a is known in the second line above, the RHS can be defined, and the new value for a determined.
More generally, operators like /=, *=, +=, -= and %= shouldn't be used during initialisation of a variable. A compiler (such as g++) should respond with an error if you ever try to do this.

Incrementing a pointer while reading it?

The following code comes from Arduino's "Print.cpp":
size_t Print::print(const __FlashStringHelper *ifsh)
{
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
size_t n = 0;
while (1) {
unsigned char c = pgm_read_byte(p++);
if (c == 0) break;
n += write(c);
}
return n;
}
The __FlashStringHelper is basically a char array or string literal which is stored in PROGMEM (program memory) instead of RAM. It is declared as in WString.h:
class __FlashStringHelper;
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
I am interested in the unsigned char c = pgm_read_byte(p++); line and more spesifically the (p++) part. I assume that the value of the pointer p is read here and is also incremented by one byte here so that all the bytes in *ifsh can be read one after the other. Am I correct with that?
So I have 2 question considering the above;
What is the sequence in normal C/C++ compilers and what is the sequence in Arduino? Is the value first read and then the pointer incremented? Or is it the other way around?
Is the sequence always the same for C/C++ compilers or will it
differ between them?
The expression pgm_read_byte(p++) is equivalent to
pgm_read_byte(p);
p += 1;
And all C or C++ compilers that follow the standard will behave that way.
It's defined by C++ standard and:
It's the same (in this case it's post increment so it will happen after reading value from p)
Always the same.
Regarding the second question, this is from c89 standard:
The result of the postfix ++ operator is the value of the operand. After the result is obtained, the value of the operand is incremented.
I somehow believe that this is true for all newer c versions as well as cpp.
Arduino uses the avr-gcc compiler. So i can guess you can safely assume:
A = p++ is equal to A = p; p++;
The post-increment operator (i.e. variable++) will increment the variable but return the old value of the variable. It is equivalent to:
SomeType PostIncrement(SomeType& v)
{
SomeType oldValue = v;
v = v + 1;
return oldValue;
}
Example:
int x = 5;
int y = x++;
// Here x is 6 while y is 5 (i.e. the old value of x)
When you use post-increment on a variable you pass in a function call, the function will be called with the old value. Still the increment is done before the function call because the arguments will be fully evaluated before the call.
Example:
void f(int y)
{
// When execution arrives here, x is 6 while y is 5 (i.e. the old value of x)
}
int main()
{
int x = 5;
f(x++);
return 0;
}

Conditional operator always replaceable by if/else?

Until now I was thinking the conditional operator int a = b == 2 ? x1 : x2; is always replaceable by an if/else statement.
int a;
if (b == 2)
a = x1;
else
a = x2;
And the choice between one of the two is always a matter of taste. Today I was working with a task where a reference would be useful if I could write:
int& a;
if (b == 2)
a = x1;
else
a = x2;
This is not allowed and I tried the initialization of the reference with the conditional operator. This was working and I came to realize, that the conditional operator is not always replaceable by an if/else statement.
Am I right with this conclusion?
You are correct. The conditional operator is an expression, whereas if-else is a statement. An expression can be used where a statement can be used, but the opposite is not true.
This is a good counterexample to show when you come across somebody who insists that you should never, never, never, ever use conditional expressions, because if-else is "simple" and conditionals are "too complicated".
When C++ gets lambda expressions, then you may be able to use a lambda with an if-else in place of a conditional.
Well, there are obviously lots of places that you can't place an if. For example:
func( x ? 0 : 1 );
There is no way of writing that with an if statement. And this is a dupe, several times, not that I blame you for not finding it, because I can't.
Not exactly. You can always replace the reference (not re-seatable) with a pointer (re-seatable). So it's a matter of context.
E.g. you can write
int* pa;
if( b == 2 )
pa = &x1;
else
pa = &x2;
int& a = *pa;
No problemo, as someone once remarked to the Terminator.
And going all out for maximum "ugh what's that" effect,
int* pa;
switch( b == 2 )
{
case true:
pa = &x1; break;
default:
pa = &x2;
}
int& a = *pa;
But it's more clear with the conditional operator in this case. :-)
int& a = (b == 2? x1 : x2);
Cheers & hth.,
You are going to have more problems than that
// works
ostream *o;
if(x)
o = &myfiles;
else
o = &mystrings;
// stringstream* and fstream* -- incompatible!
ostream *o = x ? &myfiles : &mystrings;
You are right.
In C++ there are conditional assignment situations where use of the if-else statement is impossible, since this language explicitly distinguishes between initialization and assignment.
Furthermore, the ternary operator can yield an lvalue, i.e. a value to which another value can be assigned.
Also, some compilers in some cases may generate different code for ternary vs conditional if-then. GCC, for example, performs better code optimization if ternary operator is used.
See also ?: ternary operator in C++.
You can't use it directly, but you can always get around that restriction by turning your conditional into something that is evaluated as an expression...
int& initValue(int b, int& x1, int& x2){
if (b==2)
return x1;
return x2;
}
...
int& a = initValue(b, x1, x2);
Of course, this may be overkill for ints.
It depends on your definition of replaceable. For example, within a single function call, I cannot replace the following conditional operator with an if-else.
int n1 = 10;
int n2 = 20;
const int& i = x > 0 ? n1 : n2;
However, with the addition of another function, I've effectively replaced the conditional operator with an if-else.
const int& get_i(double x)
{
if(x > 0)
return n1;
else
return n2;
}
int main()
{
const int& i = get_i(x);
}
Acording to kodify.net we cannot replace every if/else statement with the conditional operator. There are two requirements for doing so: there must be one expression in both the if and the else block.