Search

Enter your search terms

Submit search form

1.5 — A first look at operators

By Alex on June 6th, 2007 | last modified by Alex on May 14th, 2017

Revisiting expressions

In lesson 1.1 -- Structure of a program, we had defined an expression as “A mathematical entity that evaluates to a value”. However, the term mathematical entity is somewhat vague. More precisely, an expression is a combination of literals, variables, functions, and operators that evaluates to a value.

Literals

A literal is a fixed value that has been inserted (hardcoded) directly into the source code, such as 5, or 3.14159. Literals always evaluate to themselves. Here’s an example that uses literals:

1

2

3

4

5

6

7

8

9

10

#include <iostream>

intmain()

{

intx=2;// x is a variable, 2 is a literal

std::cout<<3+4;// 3 + 4 is an expression, 3 and 4 are literals

std::cout<<"Hello, world!";// "Hello, world" is a literal too

return0;

}

Literals, variables, and function calls that return values are all known as operands. Operands supply the data that the expression works with. We just introduced literals, which evaluate to themselves. Variables evaluate to the values they hold. Functions evaluate to produce a value of the function’s return type (unless the return type is void).

Operators

The last piece of the expressions puzzle is operators. Operators tell the expression how to combine one or more operands to produce a new result. For example, in the expression “3 + 4”, the + is the plus operator. The + operator tells how to combine the operands 3 and 4 to produce a new value (7).

You are likely already quite familiar with standard arithmetic operators from common usage in math, including addition (+), subtraction (-), multiplication (*), and division (/). Assignment (=) is an operator as well. Some operators use more than one symbol, such as the equality operator (==), which allows us to compare two values to see if they are equal.

Note: One of the most common mistakes that new programmers make is to confuse the assignment operator (=) with the equality operator (==). Assignment (=) is used to assign a value to a variable. Equality (==) is used to test whether two operands are equal in value. We’ll cover the equality operator in more detail later.

Operators come in three types:

Unary operators act on one operand. An example of a unary operator is the - operator. In the expression -5, the - operator is only being applied to one operand (5) to produce a new value (-5).

Binary operators act on two operands (known as left and right). An example of a binary operator is the + operator. In the expression 3 + 4, the + operator is working with a left operand (3) and a right operand (4) to produce a new value (7).

Ternary operators act on three operands. There is only one of these in C++, which we’ll cover later.

Also note that some operators have more than one meaning. For example, the - operator has two contexts. It can be used in unary form to invert a number’s sign (eg. to convert 5 to -5, or vice versa), or it can be used in binary form to do arithmetic subtraction (eg. 4 - 3).

Conclusion

This is just the tip of the iceberg in terms of operators. We will take an in-depth look at operators in more detail in a future section.

75 comments to 1.5 — A first look at operators

I noticed that there is an operator for addition, subtraction, multiplication, division, and an operator for finding the remainder. However, I did not see an operator for finding the exponent. For example, I could not find a specific operator that does something like this:

2^3 = 8

I did a quick google search and was unable to find such an operator for C++. Referring to this website: https://www.geeksforgeeks.org/operators-c-c/ the '^' means "Bitwise exclusive OR" (I have no idea what that means.) If you have covered this topic in future lessons, please point me to that page.

This site will teach you the basics of C++. That will give you the knowledge to learn more about other related subjects. It's definitely not enough to get you a job in cyber security, but it's a good first step along that path.

Hey Alex, I'm curious about a few things I'm wondering you could tell me about, concerning expressions. The question itself isn't too bad, it's just difficult to word clearly and brief. After some research, I had come to this conclusion:

When an expression evaluates, a temporary object (often called a "temporary") is created to hold the result. This object exists until the end of the full expression, and then it is discarded. If nothing is done with the result of an expression (i.e., the expression has no side effect) it is generally considered a waste.

^ Not entirely sure if this is true. This is how I envision an expression evaluating:

int x = 0, y = 10, z = 15;
x = y + z;

1. x, y, and z "evaluate" but the order of such is not specified. A temporary object is created to hold each of their values.
2. y (10) and z (15) evaluate to 25, another temporary object is created to hold this value.
3. 25 is copied into x.
4. All temporaries are destroyed, in the reverse order they were created in, when the statement (or expression?) ends. More specifically, a "destructor" is called for them, much like the destructor of a class object when it goes out of scope.

It's possible only one temporary is made, or none. I don't actually know what the truth is, so I come to you 🙂 I had drawn the conclusion that ALL expressions discard their values in the end (the temporaries created) whether or not their result is used, but I could be--and probably am--wrong about that, too. This might at least explain why an l-value reference cannot bind to something like 5 + 5, but an r-value reference can, one of the reasons I was curious about how expressions are carried out by the machine.

You're on the right track. Expressions do create temporary values that are discarded if nothing is done with them. However, expressions do have specific orders in which they are evaluated -- we cover this in lesson 3.1.

In the above case, y + z are evaluated first, producing temporary rvalue 25. Then operator= is called, and that value of 25 is assigned to variable x. Done.

Ah! I meant the operands themselves may not evaluate in a specified order (well, I mean not specified by the C++ language, so it is left up to the designers of the compiler itself to decide, or maybe the compiler chooses based on what is more efficient).

I read something out of curiosity, which led to one thing, which led to another thing, and now I'm so far off my tracks I can't remember how I got where I'm at, or where I was. I believe it was a wikipedia article on "Sequence Points," something I saw and took note of. According to that, all operands of expressions, and arguments of functions--which I guess could be thought of as arguments of the function call operator ()--aren't guaranteed to evaluate in any specific order. Which is probably why something like:

Some places call it "Order of Evaluation" instead of "Sequence Points." And even more confusing, I stumbled across this article while researching it: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r1.pdf

Looks like they're trying to change this issue in C++17. If they do, I'll have to get used to that right after learning about it, LOL. I guess it's better they keep improving C++, it's probably worth the headache.

P.S. When the assignment operator = assigns a value, is this value copied into the variable, or is it "bound" like a reference? Or is the temporary value created by evaluation always discarded, regardless of what happens at the end of an expression?

Also, thank you for responding to me. And thank you for this web site! It's made learning the language so much easier. I bought a few of the recommended books (recommended from Stack Oveflow) and they don't really go out of their way to explain much. After going through a few chapters on this site, and THEN reading the book (not all of it, but one day), the book makes perfect sense, so that tells you a whole lot about how good this site is.

Don't worry about sequence points for now. As long as you avoid using a variable with side effects applied more than once in a single expression, you'll be fine. I cover side effects in more detail in chapter 3.

When you use assignment, the value is copied. C++ does support references as well -- we also talk about those in chapter 6.

Any temporary values from expressions are discarded at the end of the expression. Whether you copy those values to a variable (via assignment or initialization) is your choice. We talk more about initialization and assignment in chapter 2.

I think it's great that you're going off the rails and doing your own explorations. Just note that a LOT of your questions are probably covered in future lessons, so keep reading!

The reason this site exists is because I found most books to be very difficult to understand if you didn't already know what they were talking about. I try to assume you don't know anything here. Additionally, this site has gone through a lot of refinement based on reader questions, thoughts, and feedback. That's one advantage an online site has over a book!

Alex, can you explain what a "Primary Expression" is? It's a term I've started to run into since taking a break from learning C++. I come back, and now I'm seeing "Primary Expression," "Postfix Expression," and "l-value" and "r-value" has been appended with "x-value," "gl-value," and "pr-value." It's like I fell through a hole in time-space and woke up in a different dimension. What the heck does all this new stuff mean? Things used to be so simple!

Yeah, C++11 kind of made a mess of things due to move semantics. From http://en.cppreference.com/w/cpp/language/value_category:

a glvalue is an expression whose evaluation determines the identity of an object, bit-field, or function
a prvalue is an expression whose evaluation either computes the value of the operand of an operator (such prvalue has no result object), or initializes an object or a bit-field (such prvalue is said to have a result object). All class and array prvalues have a result object even if it is discarded.
an xvalue is a glvalue that denotes an object or bit-field whose resources can be reused
an lvalue is a glvalue that is not an xvalue.
an rvalue is a prvalue or an xvalue.

There are a bunch of examples of each on that page.

But honestly, I wouldn't sweat about any of them right now except lvalue and rvalue. You can learn about glvalues, prvalues, and xvalues if and when they become useful in some context that's relevant to something you need to know.