Draft 2002-10-10

Chapter 4

Expressions

An expression is a combination of function calls, operators, and operands that expresses or computes a value. This chapter describes the rules for writing and understanding expressions.

Lvalues and Rvalues

An lvalue is an expression that yields an object reference, such as a variable name, an array subscript reference, dereferencing a pointer, or calling a function that returns a reference.

An rvalue is an expression that is not an lvalue. Examples of rvalues include literals, the results of a operators, and function calls that return non-references.

Strictly speaking, a function is an lvalue, but the only uses for a function lvalue are to call the function or to takes it address. Most of the time, when a C++ programmer uses the term lvalue, he or she means an object lvalue, and this book follows the convention.

The term lvalue originates in C, where an lvalue could be used on the left side of an assignment statement, and an rvalue was an expression that could be used only on the right side of an assignment. For example,

#define rvalue 42
int lvalue;
lvalue = rvalue;

In C++, these simple rules are no longer true, but the names remain because they are close to the truth. The most significant departure from C is that an lvalue might be const, in which case it cannot be the target of an assignment.

You must have an lvalue in order to modify an object, so assignment operators require their left operand to be an lvalue. The address (&) operator also requires an lvalue operand as do the increment (++) and decrement (--) operators. Other operators require rvalues.

Some other rules for lvalues are rvalues are as follows:

Example 4-1 shows several different kinds of rvalues and lvalues.

Example 4-1: Lvalues and rvalues.

class number {
public:
  number(int i = 0) : value(i) {}
  operator int() const { return value; }
  number& operator=(const number& n);
private:
  int value;
};

number operator+(const number& x, const number& y);

int main()
{
  number a[10], b(42);
  number* p;
  a;           // lvalue
  a[0];        // lvalue
  &a[0];       // rvalue
  *a;          // lvalue
  p;           // lvalue
  *p;          // lvalue
  10;          // rvalue
  number(10);  // rvalue
  a[0] + b;    // rvalue
  b = a[0];    // lvalue
}

Type Conversions

In an arithmetic expression, binary operators require operands of the same type. The type of one operand can be converted so it matches that of the other operand. The matching type is usually the type of the result. (Relational and equality operators yield a bool result.)

Type Promotion

Type promotion takes place when needed, automatically. The general rule for implicit type promotion is that promotion preserve the original value to the greatest extent possible. Specifically, the rules are as follows:

Automatic Type Conversion

In addition to type promotion, several other conversions are performed automatically when needed:

Note that these conversion decisions are based on the types, not on the values, so the result type is always known at compile time.

Conversion to bool

Arithmetic, enumeration, and pointer values can be converted to bool: null pointers and zero arithmetic values are false, and everything else is true. A common idiom is to test pointers as follows:

if (ptr)
  ... // do something with *ptr
else
  ... // pointer is null
if (! ptr)
  // another way to test if ptr is null

This idiom is so common that some classes have operators to convert an object to void*. For example, basic_ios defines operator void*() to return a null pointer if the iostream's failbit is set. (See <ios> in Chapter 13 for details.)

Type Casts

In addition to implicit type conversions and promotions, you can explicitly cast a value to a different type. C++ offers several different ways to cast a type. The preferred way is to use the template-like syntax, but two shorter forms are also accepted:

(type) expr
type ( expr )
const_cast< type >( expr )
dynamic_cast< type >( expr )
reinterpret_cast< type >( expr )
static_cast< type >( expr )

The first form is borrowed from C. It converts expr to a new value whose type is type. The second form is similar, but works only if type is a single identifier (such as a class name, enumeration name, a typedef name, or a single keyword for a fundamental type).

The last four forms are usually preferred over the first two because they require the programmer to be specific about the nature of the type cast. If you simply want to force an expression to be const, or to remove a const (say, prior to passing a pointer to a legacy library that is not written in C++ and does not know about const declarations), use const_cast<>.

If you have a pointer or reference to an object whose declared type is a base class, but you need to obtain a derived class pointer or reference, you should use dynamic_cast<>. The dynamic cast performs a runtime check to make sure the cast is valid. A dynamic cast works only with polymorphic classes, that is, classes with at least one virtual function.

For example, suppose you have a graphics package, where all graphical classes derive from the base class, shape. Various shapes have derived classes, such as circle and polygon. Suppose further that the application keeps a list of shape pointers for a drawing. Most of the application's work is done through virtual functions, such as shape::draw, but sometimes the application must cast a shape pointer to, say, a polygon pointer and perform polygon-specific work that is not exposed through a virtual function (e.g., display the number of edges). Use dynamic_cast<polygon*>(shape_ptr), which checks that the shape truly is a polygon.

If you must perform a downward cast on non-polymorphic types, you should first reexamine your design. Downward casts should be rare, and typically happen only in situations where you are working with polymorphic classes. Nonetheless, you can perform a non-polymorphic downward cast with static_cast<>. There is no runtime check, and errors result in undefined behavior.

The more common use for static_cast<> is to force one enumeration to a different enumerated type, to force an arithmetic type to a different type, or to force a particular conversion from a class-type object that has multiple type conversion operators.

A reinterpret_cast<> is reserved for the rare situations when you need to interpret the raw representation of one object as a different type. For example, an internal debugging package might record debug log files. The logger might convert pointers to integers using reinterpret_cast<> and print the integers using a specific format.

If you try to perform the wrong kind of cast with one of the template-like cast operators, the compiler informs you of your mistake. For example, if you use static_cast<> and accidentally cast away const-ness, the compiler complains. Or if you use static_cast<> where you should have used reinterpret_cast<>, the compiler complains.

The short forms do not provide this extra level of error-checking because one form must do for the several different kinds of type casts. When you see a type cast, you should read it as a warning that something unusual is happening. The longer forms of type casts provide additional clues to the reader about the programmer's intent, and help the compiler enforce that intent.

Read the detailed rules for each form of type cast later in this chapter.

Constant Expressions

A constant expression is one that can be evaluated at compile time.

Integral Constant Expressions

Most of these contexts require an integer result: array bounds, enumerator values, case expressions, bit-field sizes, and static member initializers. Such expressions can involve only literals, enumerators, const variables, integral or enumerated template parameters, and sizeof expressions. Floating-point literals must be cast to integer or enumerated types. For example,

const int a = 39;
enum { x = int(3.14) + a / sizeof(char) };

The address of a static lvalue object is a constant address, as is the address of a function. A string literal, being a static array of characters is a constant address expression.

A static const data member can be initialized in the class declaration if the initializer is a constant integral or enumerated expression. The member can be used as a constant expression elsewhere in the class declaration. For example,

template<typename T, size_t size>
class array {
public:
  static const size_t SIZE = size;
  ...
private:
  T data[SIZE];
};

See Chapter 7 for more information about static data members.

Null Pointers

A constant expression whose value is the integer zero can be a null pointer constant. A null pointer constant can be converted to a null pointer value. The difference between the null pointer constant and a null pointer value is crucial.

A null pointer value has an implementation-defined bit pattern. Many implementations use all zero bits, but some do not. Thus, the null pointer constant is not representative of the bits that make up a null pointer value, but serves only as a mnemonic for the programmer, much as = 0 does for a pure virtual function (Chapter 6).

When you assign a null pointer constant to a pointer-type variable, the compiler takes care of converting the null pointer constant to a null pointer value of the appropriate type. Similarly, when comparing a pointer to a null pointer value, the compiler ensures the comparison is meaningful. In particular, a null pointer value is never equal to any other valid pointer value. A null pointer value is always equal to a null pointer value. A null pointer value, when converted to bool, is false.

The NULL macro, defined in <cstdlib> and other headers (see Chapter 13), expands to a null pointer constant, i.e., 0. Using NULL instead of 0 can be a helpful reminder to the reader or maintainer of a program, especially when typedefs obscure the nature of a type. For example,

Token tok1 = 0;     // Is Token a pointer or an integer?
Token tok2 = NULL;  // Token is probably a pointer

Expression Evaluation

At its most fundamental level, the execution of a C++ program is the successive evaluation of expressions, under the control of statements (Chapter 5), where some expressions can produce side effects. Any expression might have side effects: accessing a volatile object, modifying any object, calling a library function, or calling any other function that has side effects.

Sequence Points

During the execution of a program, there are well-defined points in time, called sequence points. At a sequence point, the side effects have all been completed for expressions that have been evaluated so far, and no side effects have yet started for any expression yet to be evaluated. Between sequence points, the compiler is free to reorder expressions in any way that preserves the original semantics.

There are sequence points in the following positions:

Order of Evaluation

In general, the order in which operands are evaluated is unspecified. For example, in the expression f() / g(), f() might be called first, or g() might be called first. The difference can be significant when the functions have side effects. Example 4-2 shows a contrived situation where a program prints 2 if g() is called first, or 1 if f() is called first.

Example 4-2: Demonstrating order of evaluation.

#include <iostream>
#include <ostream>

int x = 1;

int f()
{
  x = 2;
  return x;
}

int g()
{
  return x;
}

int main()
{
  std::cout << f() / g() << '\n';
}

A simpler example follows. The increment of i can happen before or after the assignment, so i might be 2 or 3.

int i = 1;
i = i++ + 1; // value of i is unspecified

In a function call, all arguments are evaluated before the function is called. As you might expect, the order in which the arguments are evaluated is unspecified.

Short Circuit Evaluation

The logical operators (&& and ||) perform short-circuit evaluation. The left operand is evaluated, and if the expression result is known, the right operand is not evaluated. For example,

if (false && f()) ... // f() is never called
if (true || f())  ... // f() is never called

If the logical operator is overloaded, however, it cannot perform short-circuit evaluation. Like any other function, all the arguments are evaluated before the function is called. For this reason, you should avoid overloading the && and || operators.

Expression Rules

C++ has the usual unary operators, such as logical negation (!a), binary operators such as addition (a+b), and even a ternary operator (a?b:c). Unlike many other languages, array subscripting is also an operator (a[b]), and a function call is an n-ary operator (e.g., a(b, c, d)).

Every operator has a precedence. Operators with higher precedence are grouped so they are evaluated before operators with lower precedence. (Note that precedence determines how the compiler parses the expression, not necessarily the actual order of computation.)

Some operators group left-to-right, as in x - y - z, which is equivalent to (x - y) - z. Other operators group right-to-left, as in x = y = z, which is equivalent to x = (y = z). The order is called the operator's associativity.

When reading C++ expressions, you must be aware of the precedence and associativity of the operators. For example, *ptr++ is read as *(ptr++) because the postfix ++ operator has higher precedence than the unary * operator.

The following sections describe all the expressions, grouped by precedence. Table 4-1 summarizes all the expressions and their associativity.

Table 4-1: Expressions grouped by precedence
Group Associativity Expression
Primary(Highest precedence) Left-to-right literalthis( expr )name:: nameclass-or-namespace :: name
Postfix Left-to-right pointer [ expr ]expr ( expr , ... )type ( expr , ... )object. memberpointer -> membercast_keyword < type >( expr )typeid( expr )typeid( type )lvalue ++lvalue --
Unary Right-to-left ++ lvalue-- lvalue~ exprcompl expr! exprnot expr+ expr- expr* pointer& lvaluesizeof exprsizeof( type )new-exprdelete-expr
Cast Right-to-left ( type ) expr
Member Left-to-right object .* exprpointer ->* expr
Multiply Left-to-right expr * exprexpr / exprexpr % expr
Add Left-to-right expr + exprexpr - expr
Shift Left-to-right expr << exprexpr >> expr
Relational Left-to-right expr < exprexpr > exprexpr <= exprexpr >= expr
Equality Left-to-right expr == exprexpr != exprexpr not_eq expr
Bitwise And Left-to-right expr & exprexpr bitand expr
Bitwise Exclusive Or Left-to-right expr ^ exprexpr xor expr
Bitwise Inclusive Or Left-to-right expr | exprexpr bitor expr
Logical And Left-to-right expr && exprexpr and expr
Logical Or Left-to-right expr || exprexpr or expr
Conditional Right-to-left expr ? expr : expr
Assignment Right-to-left expr = exprexpr op= exprthrow exprthrow
Comma (Lowest precedence) Left-to-right expr , expr

Primary Expressions

A primary expression is the basic building block for more complex expressions. It is either an expression in parentheses, a literal, or a name (possibly qualified). The various forms of primary expressions are as follows:

literal
Is a constant value. Chapter 1 describes the forms and types for literals. String literals (being arrays of const char or const wchar_t) are lvalues. All other literals are rvalues.
this
Refers to the target object in a non-static member function. Its type is the class type; its value is an rvalue.
( expression )
Has the type and value of expression.
unqualified-name
Names an entity, according to the name lookup rules in Chapter 3. The expression result is the entity itself, and the expression type is the entity's type. The result is an lvalue if the entity is a variable, data member, or function. Following are the various kinds of unqualified identifiers:
identifier
Is looked up according to the rules in Chapter 3. The type is the declared type of the entity. If the entity is a variable, data member, or function, the value is an lvalue; otherwise it is an rvalue.
operator symbol
Names an operator. See Chapter 6 for more information.
template-name < optional-template-args >
Names a template instance. See Chapter 8 for more information.
operator type
Names a type conversion operator. The type is a type specifier, possibly with one or more pointer symbols in the declarator. (See Chapter 3 for details about type specifiers and declarators.)
~ class-name
Names the destructor for class-name.
qualified-name
Uses the scope operator to qualify an identifier, operator, or destructor. The qualified name can be in the global scope or in the scope of a class or namespace:
:: identifier
Names a global identifier. The type is the declared type of the entity. If the entity is a variable, data member, or function, the value is an lvalue; otherwise it is an rvalue.
:: operator symbol
Names a global operator. See Chapter 6 for more information. Note that type conversion operators must be member functions, so there cannot be a global type conversion operator.
nested-name unqualified-name
nested-name template unqualified-name
Names an entity in a class or namespace scope. The nested-name has the form class-or-namespace-name :: nested-name or class-name :: template nested-name. See also Chapter 8 for information about template members.
:: nested-name unqualified-name
:: nested-name template unqualified-name
Names an entity in a class or namespace scope. The first (left-most) class or namespace name is looked up in the global scope.

In the rest of this chapter, the syntax element name-expr refers to a qualified or unqualified name, as described in this section. In particular, a name-expr can be used to the right of . or -> in a postfix expression. Example 4-3 shows some primary expressions.

Example 4-3: Primary expressions.

namespace ns {
  int x;
  class cls {
  public:
    cls(int);
    ~cls();
  };
}
int x;

3.14159         // literal
(2 + 3 * 4)     // parenthesized expression
x               // unqualified identifier
ns::x           // qualified identifier
ns::cls::cls    // qualified constructor
operator*       // unqualified operator name

Postfix Expressions

Some of the expressions in this group do not use postfix syntax, but they have the same precedence as the postfix operators, so they are lumped into the same group. The postfix expressions are as follows:

pointer [ expr ]
The subscript operator requires a pointer as the left operand. An array is implicitly converted to a pointer. The right operand is converted to an integer, and the expression is evaluated as *((pointer) + (expr)). If the array index is out of bounds, the behavior is undefined. The result is an lvalue whose type is the base type of pointer.
expr ( optional-expr-list )
The function call operator requires a function name, an expression that returns a function pointer, or an expression that returns an object with a function call operator as the left operand. (An operator name is the same as a function name in this case.) The optional-expr-list is a comma-separated list of zero or more assignment expressions. All the expressions in the expression list are evaluated, then the function is called. The result type is the return type of the function. If the return type is a reference type, the result is an lvalue; otherwise the result is an rvalue. If the return type is void, no value is returned. See Chapter 6 for more information about functions.
simple-type-specifier ( optional-expr-list )
Performs type conversion or construction. A simple-type-specifier is a single name: a fundamental type or a qualified name of a class, enumeration, or typedef. The result is an instance of the specified type, initialized as follows:
object . name-expr
Returns a member of an object. The name can be qualified to refer to a name in a base class (see Chapter 3). The return type is the type of name-expr. The return value depends on whether name-expr is a data member, member function, or enumerator:
pointer -> name-expr
Returns (*(pointer)).name-expr.
lvalue ++
Increments lvalue and returns its value prior to incrementing, as an rvalue. The type of lvalue must be arithmetic or a pointer. The new value is lvalue + 1.
If lvalue has type bool, the new value is always true. The bool-specific behavior is deprecated.
lvalue --
Decrements lvalue and returns its value prior to decrementing, as an rvalue. The type must be arithmetic or a pointer and cannot be bool. The new value is lvalue - 1.
const_cast< type >( expr )
Casts expr to type. If type is a reference, the result is an lvalue; otherwise it is an rvalue. The new type must match the type of expr, except that the const and volatile qualifiers can be changed.
A const_cast that removes a const qualifier is generally a bad idea,a nd modifying the resulting object results in undefined behavior. It is sometimes necessary to cast away const-ness, especially when passing pointers to legacy libraries. If you need to cast away const-ness to modify a data member of a const object, declare the member mutable.
dynamic_cast< type >( expr )
Casts a base class pointer or reference expr to a derived class type. A runtime check is performed to make sure the true value of expr is type or a class derived from type. The class must be polymorphic, that is, have at least one virtual function. A dynamic_cast<> cannot cast away const-ness. The cast works as follows:
Example 4-4 shows some uses of dynamic_cast<>.

Example 4-4: Using dynamic_cast<>.

#include <iostream>
#include <ostream>

class base {
public:
  virtual ~base() {}
};

class derived : public base {};
class most_derived : public derived {};
class other : public base {};

int main()
{
  base* b = new derived;
  dynamic_cast<most_derived*>(b); // null pointer
  dynamic_cast<derived&>(*b);     // okay
  dynamic_cast<other*>(b);        // null pointer

  derived* d = new most_derived;
  b = d;
  b = dynamic_cast<base*>(d);    // okay. but dynamic_cast<>
                                 // is unnecessary
}
reinterpret_cast< type >( expr )
Casts expr to type, possibly changing the representation. When using reinterpret_cast<>, no conversion functions or constructors are called. Casting to a reference yields an lvalue; otherwise it yields an rvalue. A reinterpret_cast<> cannot cast away const-ness. Only the following conversions are allowed:
Need for reinterpret_cast<> is rare is an ordinary application. Example 4-5 shows some uses of reinterpret_cast<>.

Example 4-5: Using reinterpret_cast<>.

#include <cassert>
#include <iomanip>
#include <iostream>
#include <ostream>

int foo()
{
  return 0;
}

int main()
{
  using namespace std;
  float pi = 3.1415926535897;
  int   ipi;

  // Print numbers in pretty hexadecimal.
  cout << setfill('0') << showbase << hex << internal;

  // Show the representation of a floating point number.
  assert(sizeof(int) == sizeof(float));
  ipi = reinterpret_cast<int&>(pi);
  cout << "pi bits=" << setw(10) << ipi << '\n';

  // Show the address of foo().
  cout << "&foo=" << setw(10) <<
    reinterpret_cast<int>(&foo) << '\n';

  // error: cannot mix object & function pointers.
  reinterpret_cast<int*>(&foo);
}
static_cast< type >( expr )
Casts expr to type using a standard or user-defined conversion. The result is an lvalue if type is a reference; otherwise the result is an rvalue. A static_cast<> cannot cast away const-ness. The permitted conversions are as follows:
Example 4-6 shows some uses of static_cast<>.

Example 4-6: Using static_cast<>.

#include <iostream>
#include <ostream>

class base {};
class derived : public base {};
class other : public base {};

enum color   { red, black };
enum logical { no, yes, maybe };

int main()
{
  base* b = new derived;
  static_cast<derived&>(*b); // okay
  static_cast<other*>(b);    // undefined behavior

  derived* d = new derived;
  b = d;
  b = static_cast<base*>(d); // okay, but unnecessary

  color c = static_cast<color>(yes);

  int i = 65;
  std::cout << static_cast<char>(i);
}
typeid( expr )
Returns type information for the type of expr without evaluating expr. The type information is an lvalue of type const std::type_info (or an implementation-defined type that derives from type_info). See <typeinfo> in Chapter 13 for information about this class.
If expr is an lvalue of a polymorphic type (class with at least one virtual function), the type information is for the most derived class of expr. If expr is a dereference of a null pointer, bad_typeid is thrown.
If expr is not an lvalue, or the type is not polymorphic, the type information is for the static type of expr.
typeid( type )
Returns the type information for type as described under typeid( expr ). See Example 4-7 for uses of typeid.

Example 4-7: Using typeid.

#include <iostream>
#include <ostream>
#include <typeinfo>

class base {
public:
  virtual ~base() {}
};

class derived : public base {};
enum color   { red, black };

// The actual output is implementation-defined, but should
// reflect the types shown in the comments.
int main()
{
  base* b = new derived;
  std::cout << typeid(*b).name() << '\n';      // derived
  std::cout << typeid(base).name() << '\n';    // base
  derived* d = new derived;
  std::cout << typeid(*d).name() << '\n';      // derived
  std::cout << typeid(derived).name() << '\n'; // derived
  std::cout << typeid(red).name() << '\n';     // color
  std::cout << typeid(color).name() << '\n';   // color
}

Unary Expressions

A unary expression uses a unary prefix operator, as follows:

++ lvalue
Increments lvalue, which must be of arithmetic or pointer type, and returns the new value as an lvalue. The expression ++x is equivalent to x += 1, unless x is of type bool, in which case it is x=true.
-- lvalue
Decrements lvalue, which must be of arithmetic or pointer type (not bool), and returns the new value as an lvalue . The expression --x is equivalent to x -= 1.
* pointer
Dereferences pointer and returns an lvalue for the object that pointer points to. If pointer has type pointer to T, the expression has type T (preserving any cv qualifiers).
& lvalue
& qualified-name
Returns the address of lvalue or qualified-name. If lvalue has type T or qualified-name is a static member of type T, the result is the object's address, which is an rvalue of type pointer to T. If qualified-name is a non-static member of class C, the result type is a pointer to member of class C.
Note that a pointer to member is formed only by applying the & operand to a qualified name. Even in the scope of a class, &unqualified-name is not a pointer to member.
You cannot take the address of a bit field. To take the address of an overloaded function, the context must make it clear which function you mean. Example 4-8 shows examples of the & operator.

Example 4-8: Using the & operator.

class demo
{
public:
  int x;
  static int y;
  int get_x() { return x; }
};

int demo::y = 10;

int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }

int main()
{
  demo d;
  int demo::*p;
  int (demo::*func)();
  int *i;
  int local = 42;
  int *ptr = &local;

  p = &demo::x;
  i = &demo::y;
  func = &demo::get_x;
  d.*p = *ptr;
  *i = (d.*func)();

  int (*adder)(int, int);
  adder = &add;
  d.*p = adder(42, *i);

  return d.y;
}
+ expr
Returns expr, which must have arithmetic, enumeration, or pointer type. The usual type promotions take place, and the result type is the promoted type. The result is an rvalue.
- expr
Negates expr, which must have arithmetic or enumerated type. The usual type promotions take place, and the result type is the promoted type. The result is an rvalue. If the type is unsigned, the result is 2n - expr, where n is the number of bits in the result type.
~ expr
compl expr
Returns the bitwise complement of expr, which must have integral or enumeration type. The type is promoted according to the usual rules, and the result type is the promoted type. The result is an rvalue. Every zero bit in expr is converted to a one bit, and every one bit is converted to zero.
In the ambiguous case of ~C(), where C is a class name, ~C() is interpreted as the complement operator, not the destructor of C. If C does not have an overloaded operator~ or an implicit conversion to an integral or enumerated type, it is an error. To force a reference to C's destructor, use a member reference, e.g., this->~C(), or a qualified name, e.g., C::~C().
! expr
not expr
Returns the logical negation of expr, after converting it to bool. The result is an rvalue of type bool. If expr is true, the result is false; if expr is false, the result is true.
sizeof expr
sizeof ( type )
Returns the size in bytes of type or the type of expr (without evaluating expr). By definition, sizeof(char) == 1. You cannot take the size of a bit field, a function, or an incomplete type. The size of a reference is the size of the referenced type.
The sizeof operator always returns a value greater than zero for a class or object of class type. The size of a base class subobject within a derived class object can be zero, so the compiler is not necessarily wasting space. You can see this in Example 4-9, which shows that the size of the derived class is the same as the size of the base class.
The result is an rvalue of type size_t. (See <cstdlib> in Chapter 13.)

Example 4-9: Using the sizeof operator.

#include <iostream>
#include <ostream>

class base {};
class derived : public base {};

int main()
{
  // The values actually printed depend on the
  // implementation, but many common implementations
  // print the values shown.
  using namespace std;
  cout << sizeof(base)  << '\n';      // prints 1
  cout << sizeof(derived)  << '\n';   // prints 1
  base b[3];
  cout << sizeof(b) << '\n';          // prints 3
  derived d[5];
  cout << sizeof(d) << '\n';          // prints 5
}
new type
new type ( optional-expr-list )
new (expr-list) type
new (expr-list) type ( optional-expr-list )
Allocates a dynamic object or array of objects. The parts of a new expression are as follows:
new
::new
The new keyword can be prefixed with the global scope operator. The actual memory allocation is performed by an allocation function. A class can provide its own allocation function by overriding operator new. A plain new expression looks up the allocation function first in the class (if the allocated type is a class type), and if not found, in the global scope. Use the global scope operator to look only in the global scope. (See <new> in Chapter 13 for the default allocation functions.)
( expr-list )
An expression list in parentheses is called the placement. The placement is optional. If present, the expressions are passed directly to the allocation function without further interpretation. The placement is optional, but if used, must contain at least one expression.
type
Is the type to allocate and has the following form (optionally in parentheses):
type-specifiers ptr-operators dimensions
See Chapter 3 for information about type specifiers and type declarations. The ptr-operators are optional and can be * or & for pointers or references. The array dimensions are optional. All dimensions except the first must be a constant integral expression (enclosed in square brackets). The first dimension can be any integral expression.
The compiler reads the longest sequence of declarators as the type, even if that results in a syntax error. To force a particular type declaration, surround type with parentheses.
( optional-expr-list )
Is the optional initializer. If you omit the initializer and allocate a POD type, the object is unitialized. If you omit the initializer for a non-POD type, or if the expression list is empty (that is, the initializer is ()), the object is initialized to a default value (that is, by calling a default constructor if one is present, or initializing to a "zero" value: arithmetic zero, false, or null pointer).
If the expression list has a single expression, and a single object is allocated, the expression is the object's initial value.
If multiple expressions are in the initializer, the type must be a class type, and the expression list is passed to a suitable constructor.
An array cannot have an initializer. If the base type is a POD type, the array elements are uninitialized; otherwise they are initialized to the default value.
See Chapter 7 for a comparison of POD and non-POD types.
The allocation function (operator new) is called with at least one argument: the number of bytes to allocate. If a placement is used, the placement arguments are passed as additional arguments to the allocation function. If the allocation function cannot fulfill the request, it typically throws bad_alloc. If you pass std::nothrow as the placement argument, though, the default allocation function returns a null pointer for an error, instead of throwing bad_alloc.
Allocating an array is different from allocating a scalar. The allocation function is operator new[]. The requested size is the number of elements time the size of each element. Even if the array size is zero, the returned pointer is not null. The allocation function might allocate additional memory to store the size of the array (so all the array elements can be properly destroyed when the memory is freed). The allocated memory is aligned to the most restrictive boundary for any type. Thus, you can, say, allocate an array of char and use the memory to store any object. The standard containers often do this; see <memory> in Chapter 13 for algorithms that work with uninitialized memory.
If an exception is thrown during initialization, the memory is freed by calling a corresponding deallocation function (corresponding to the equivalent delete expression). Following are some examples of new expressions:
int n = 10;        // note that n is not const
new int            // pointer to uninitialized int
new int()          // pointer to int, initialized to 0
new int[n]         // n uninitialized ints
new (int*)         // pointer to uninitialized pointer to int
new (int (*[n])()) // n function pointers
typedef int (*int_func)();
new int_func[n];   // n function pointers
new (int*[n][4])   // n×4 array of pointers to int
new complex<int>(42) // pointer to a complex object
new complex<int>[5]  // 5 default-initialized complex objects
delete pointer
delete[] pointer
Frees a dynamic object or array of objects and returns void. The delete keyword can be prefixed with the global scope operator. The actual memory deallocation is performed by a deallocation function. A class can provide its own deallocation function by overriding operator delete. A plain delete expression looks up the deallocation function first in the class (if the pointer type is a pointer to a class type), and if not found, in the global scope. Use the global scope operator to look only in the global scope. (See <new> in Chapter 13 for the default deallocation functions.)
To free an array, you must use delete[]. To free a scalar, you must use plain delete. If you make a mistake, the results are undefined. Note that the compiler cannot, in general, help you avoid mistakes because a pointer to a scalar cannot be distinguished from a pointer to an array. (Some libraries are more forgiving of this error than others.)
The expression is evaluated once. If pointer is a pointer to a class type or is an array of class objects, the destructors are called. The value of pointer, is then passed to the deallocation function.
You can delete a pointer to a const object. It is safe to delete a null pointer value, in which case the deallocation function is not called.

Cast Expressions

The cast expression is a holdover from C. In C++, the preferred cast syntax uses one of the explicit cast operators, which are described under Postfix Expressions earlier in this chapter. The C-style casts are still used for their brevity, though.

( type ) expr
The C-style cast converts expr to type using one of the following type conversions. The first conversion that is syntactically allowed is used, even if it is not permitted semantically. If type is a reference, the result is an lvalue; otherwise the result is an rvalue.
Where type1 is type with the same cv qualifiers as the type of expr. Thus, the type cast can mix a const-cast with a static or reinterpret cast.

Pointers to Members

The pointer to class member operators bind a member pointer to an object. The result can be a data member or a member function. A member function can be used only to call the function. Example 4-8, earlier in this chapter, shows some uses of pointers to members.

object .* expr
Binds expr to object, where expr is a pointer to member of class C, and the type of object is C or a class derived from C. The result is an lvalue if object is an lvalue and expr points to a data member; otherwise the result is an rvalue. The type of the result is determined by the type of expr. The behavior is undefined if expr is a null pointer to member.
pointer ->* expr
Binds expr to the object that pointer points to, where expr is a pointer to member of class C, and the type of object is C or a class derived from C. The result is an lvalue if expr points to a data member. The type of the result is determined by the type of expr. The behavior is undefined if pointer is null or if expr is a null pointer to member.

Multiplicative Expressions

The multiplicative operators require arithmetic or enumeration types; the usual conversions are performed, and an rvalue is returned. If the result is too large, the behavior is undefined (except for unsigned types, where arithmetic is performed modulo the integer size; see Chapter 1 for details). Many C++ implementations ignore integer overflow.

expr1 * expr2
Performs multiplication.
expr1 / expr2
Performs division. If the divisor is zero, the behavior is undefined.
expr1 % expr2
Returns the remainder of dividing expr1 by expr2. The operands must have integral or enumerated types. If expr2 is zero, the behavior is undefined; otherwise the value is such that (a/b)*b + a%b == a. If both operands are non-negative, the result is non-negative; otherwise, the sign of the result is implementation-defined.

Additive Expressions

If the operands both have arithmetic or enumerated types, the usual conversions are performed, and the result has the expected value. If the result is too large, the behavior is undefined (except for unsigned types, where arithmetic is performed modulo the integer size; see Chapter 1 for details). Many C++ implementations ignore integer overflow.

expr + expr
Performs addition. If one operand has a pointer type, the other must have an integral or enumeration type. The result is a pointer to the same array, but with the index offset by N positions (which can be positive, negative or zero), where N is the integral operand. The resulting pointer must be within the bounds of the array or point to one past the end of the array. Note that a pointer to any object can be treated as a one-element array.
expr - expr
Performs subtraction. If both operands have arithmetic or enumeration types, the usual promotions apply and the result is the difference of the operands.
If both operands are pointers, they must point to elements of the same array, or to one past the end of the array. The result has type ptrdiff_t (declared in <cstdlib>), and is equal to the difference of the indices of the two objects.
If left operand is a pointer and the right operand has integral or enumeration type, the result is the same as expr1 + (-(expr2)).

Shift Expressions

A shift expression shifts the bits of the left operand by an amount specified by the right operand. The operands must be an integral or enumerated type, which are promoted to integral types. The result type is the promoted type of the left operand.

The result is undefined if the right operand is negative or is larger than the number of bits in the left operand.

expr1 << expr2
Performs a left shift of expr1 by expr2 bits. Vacated bits are filled with zero. If expr1 is unsigned, the result is equal to multiplying expr1 by 2 raised to expr2 (modulo the integer size; see Chapter 1 for more information about unsigned integer arithmetic).
expr1 >> expr2
Performs a right shift of expr1 by expr2 bits. If the expr1 is unsigned, or if it is signed and has a positive value, vacated bits are filled with zero. The result is equal to dividing expr1 by 2 raised to expr2 (truncated to an integer). If expr1 has a signed type and negative value, the result is implementation-defined.

Relational Expressions

A relational expression compares two values for relative order. Note that they have higher precedence than the equality operators, so the following two expressions are equivalent:

a < b == c > d
(a < b) == (c > d)

The result is an rvalue of type bool. The operands must have arithmetic, enumeration, or pointer type. For arithmetic and enumeration types, the usual conversions are performed, and the resulting values are compared.

When comparing pointers, the pointers must have the same type (after the usual conversions and ignoring cv-qualification), one must be a pointer to void, or one operand must be a null pointer constant. If the pointer types are compatible, they are compared as follows (where p is the left operand and q is the right operand):

Example 4-10 shows some pointer comparisons.

Example 4-10: Comparing pointers

#include <iostream>
#include <ostream>

struct Demo {
  int x;
  int y;
};

union U {
  int a;
  double b;
  char c[5];
  Demo d;
};

int main()
{
  Demo demo[10];
  std::cout << std::boolalpha;
  // Everything prints "true"
  std::cout << (&demo[0]   < &demo[2])   << '\n';
  std::cout << (&demo[0]   == demo)      << '\n';
  std::cout << (&demo[10]  > &demo[9])   << '\n';
  std::cout << (&demo[0].x < &demo[0].y) << '\n';

  U u;
  std::cout << (&u.d == static_cast<void*>(u.c)) << '\n';
  std::cout << (&u.a == static_cast<void*>(&u.b)) << '\n';
}
expr1 < expr2
Return true if expr1 is less than expr2.
expr1 > expr2
Return true if expr1 is greater than expr2.
expr1 <= expr2
Return true if expr1 is less than or equal to expr2.
expr1 >= expr2
Return true if expr1 is greater than or equal to expr2.

Equality Expressions

The equality expression compares two values to see if they are equal or different. Note that they have lower precedence than the relational operators, so the following two expressions are equivalent:

a < b == c > d
(a < b) == (c > d)

The result is an rvalue of type bool. The operands must have arithmetic, enumeration, or pointer type. For arithmetic and enumeration types, the usual conversions are performed, and the resulting values are compared.

Warning

Note that comparing the results of floating point values for equality rarely has the result you want. Instead, you probably want a fuzzy comparison that allows for floating-point imprecision. See Appendix ### for more information.

When comparing pointers, the pointers must have the same type (after the usual conversions). The pointers are equal if any of the following conditions hold:

expr == expr
Returns true if the operands are equal.
expr != expr
expr not_eq expr
Returns false if the operands are equal.

Bitwise And Expressions

The bitwise and expression is permitted only on integral types after the usual arithmetic conversions.

expr & expr
expr bitand expr
Performs the bitwise conjunction of the operands. Each bit of the result is 1 if the corresponding bits of the operands are both 1; otherwise the result bit is 0.

Bitwise Exclusive Or Expressions

The bitwise exclusive or expression is permitted only on integral types after the usual arithmetic conversions.

expr ^ expr
expr xor expr
Performs the bitwise exclusive or of the operands. Each bit of the result is 1 if the corresponding bits of the operands are different; otherwise the result bit is 0.

Bitwise Inclusive Or Expressions

The bitwise inclusive or expression is permitted only on integral types after the usual arithmetic conversions.

expr | expr
expr bitor expr
Performs the bitwise disjunction of the operands. Each bit of the result is 0 if the corresponding bits of the operands are both 0; otherwise the result bit is 1.

Logical And Expressions

The logical and expression implicitly converts its operands to type bool. The result has type bool: true if both operands are true, otherwise false. The logical and operator is a short-circuit operator, so the second operand is evaluated only if the first is true.

expr && expr
expr and expr
Performs the logical conjunction of the operands.

Logical Or Expressions

The logical or expression implicitly converts its operands to type bool. The result has type bool: false if both operands are false, otherwise true. The logical and operator is a short-circuit operator, so the second operand is evaluated only if the first is false.

expr || expr
expr or expr
Performs the logical disjunction of the operands.

Conditional Expressions

The conditional expression is like an if statement in an expression.

condition ? true-expr : false-expr
Converts its first argument to bool. If the value is true, only the second operand is evaluated; if false, only the third operand is evaluated. The result of the conditional expression is the result of the second or third operand, whichever is evaluated.
The type of the expression depends on the types of the second and third operands: If both operands are lvalues of the same type, the result is an lvalue of that type. If one operand is an lvalue of type T, and the other operand is an lvalue that can be implicitly converted to a reference to T, the result is an lvalue of type T. Otherwise, the result is an rvalue, and the type is determined as follows:

Assignment Expressions

In addition to plain assignment (x = y), there are several other assignment statements, each of which is a shorthand for an arithmetic operation and an assignment. The left operand must be a modifiable lvalue. The result is the resulting value of the left operand, and the result type is the type of the left operand.

lvalue = expr
If the left operand has class type, a suitable assignment operator is called. See Chapter 7 for more information. If the left operand is not of class type, the right operand is converted to the type of the left operand.
lvalue += expr
lvalue -= expr
The assignment operator x op= y is shorthand for x = x op y, except that x is evaluated only once. The type of x must be an arithmetic type or a pointer. The usual conversions are performed for op, and the result is converted to the type of x.
lvalue *= expr
lvalue /= expr
lvalue %= expr
lvalue <<= expr
lvalue >>= expr
lvalue &= expr
lvalue and_eq expr
lvalue ^= expr
lvalue xor_eq expr
lvalue |= expr
lvalue or_eq expr
The assignment operator x op= y is shorthand for x = x op y, except that x is evaluated only once. The type of x must be arithmetic. The usual conversions are performed for op, and the result is converted to the type of x.
throw expr
throw
Throws an exception. The first form throws expr as the exception object. The second form rethrows the current exception object. If no exception is being handled, it calls terminate(). (See <exception> in Chapter 13 for more information about terminate().)
You can throw any expression, but the convention is to throw an object of type exception or a derived class, especially derived from one of the standard exception classes (see <stdexcept> in Chapter 13).
The exception expression initializes a temporary exception object, and that object is thrown to the exception handler, which can copy the exception object in its catch clause. When the handler finishes, the object is destroyed. An implementation can optimize away the extra copy and initialize the catch object directly with the exception expr. Even if the object is never copied, the class must have a copy constructor.
See the try statement in Chapter 5 for a description of how exceptions are handled and for examples of throw expressions. See also Chapter 6 for information about throw specifications in function declarations.

Comma Expressions

The comma operator evaluates its left operand, discards the result, and then evaluates the right operand. The result is the value of the right operand, and the type is the type of the right operand. If the right operand is an lvalue, the result is an lvalue; otherwise the result is an rvalue.

expr1 , expr2
Evaluates expr1, then expr2 and returns expr2. To use a comma expression as a function argument or in other contexts where a comma is significant, enclose the comma expression in parentheses, for example,
sin((angle = 0.0, angle + 1.0));