100% found this document useful (1 vote)
519 views1,237 pages

C++ Development in Visual Studio

This document provides an overview of modern C++ programming practices, highlighting features introduced since C++11 that make code safer, simpler and more elegant compared to traditional C-style programming. It discusses how resources and smart pointers help prevent memory leaks by following the RAII principle. It also recommends using std::string instead of C-style strings, std::vector instead of raw arrays, and other standard library containers and types instead of custom data structures. The goal is to write code that is as fast and efficient as C code while avoiding common bugs associated with manual memory management and other C-style idioms.

Uploaded by

zhbhatti80
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
519 views1,237 pages

C++ Development in Visual Studio

This document provides an overview of modern C++ programming practices, highlighting features introduced since C++11 that make code safer, simpler and more elegant compared to traditional C-style programming. It discusses how resources and smart pointers help prevent memory leaks by following the RAII principle. It also recommends using std::string instead of C-style strings, std::vector instead of raw arrays, and other standard library containers and types instead of custom data structures. The goal is to write code that is as fast and efficient as C code while avoiding common bugs associated with manual memory management and other C-style idioms.

Uploaded by

zhbhatti80
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1237

Tell us about your PDF experience.

C++ language documentation


Learn to use C++ and the C++ standard library.

Learn C++ in Visual Studio

a DOWNLOAD

Download Visual Studio for Windows

Install C/C++ support in Visual Studio

Download only the command-line build tools

b GET STARTED

Hello world in Visual Studio with C++

Create a console calculator in C++

q VIDEO

Learn C++ - A general purpose language and library

d TRAINING

Welcome back to C++ - Modern C++

Samples and the sample archive

What's new for C++ in Visual Studio

h WHAT'S NEW

What's new for C++ in Visual Studio

C++ conformance improvements

e OVERVIEW

Overview of C++ development in Visual Studio

Supported target platforms

Help and community resources


p y

Report a problem or make a suggestion

Use the compiler and tools

i REFERENCE

C/C++ build reference

Projects and build systems

Compiler reference

Linker reference

Additional build tools

Errors and warnings

C++ language

i REFERENCE

C++ language reference

C++ keywords

C++ operators

C/C++ preprocessor reference

C++ standard library (STL)

i REFERENCE

C++ standard library overview

C++ standard library reference by header

C++ standard library containers

Iterators

Algorithms

Allocators
Function objects

iostream programming

Regular expressions

File system navigation


C++ Language Reference
Article • 08/03/2021

This reference explains the C++ programming language as implemented in the


Microsoft C++ compiler. The organization is based on The Annotated C++ Reference
Manual by Margaret Ellis and Bjarne Stroustrup and on the ANSI/ISO C++ International
Standard (ISO/IEC FDIS 14882). Microsoft-specific implementations of C++ language
features are included.

For an overview of Modern C++ programming practices, see Welcome Back to C++.

See the following tables to quickly find a keyword or operator:

C++ Keywords

C++ Operators

In This Section
Lexical Conventions
Fundamental lexical elements of a C++ program: tokens, comments, operators,
keywords, punctuators, literals. Also, file translation, operator precedence/associativity.

Basic Concepts
Scope, linkage, program startup and termination, storage classes, and types.

Built-in types The fundamental types that are built into the C++ compiler and their
value ranges.

Standard Conversions
Type conversions between built-in types. Also, arithmetic conversions and conversions
among pointer, reference, and pointer-to-member types.

Declarations and definitions Declaring and defining variables, types and functions.

Operators, Precedence and Associativity


The operators in C++.

Expressions
Types of expressions, semantics of expressions, reference topics on operators, casting
and casting operators, run-time type information.
Lambda Expressions
A programming technique that implicitly defines a function object class and constructs a
function object of that class type.

Statements
Expression, null, compound, selection, iteration, jump, and declaration statements.

Classes and structs


Introduction to classes, structures, and unions. Also, member functions, special member
functions, data members, bit fields, this pointer, nested classes.

Unions
User-defined types in which all members share the same memory location.

Derived Classes
Single and multiple inheritance, virtual functions, multiple base classes, abstract
classes, scope rules. Also, the __super and __interface keywords.

Member-Access Control
Controlling access to class members: public , private , and protected keywords. Friend
functions and classes.

Overloading
Overloaded operators, rules for operator overloading.

Exception Handling
C++ exception handling, structured exception handling (SEH), keywords used in writing
exception handling statements.

Assertion and User-Supplied Messages


#error directive, the static_assert keyword, the assert macro.

Templates
Template specifications, function templates, class templates, typename keyword,
templates vs. macros, templates and smart pointers.

Event Handling
Declaring events and event handlers.

Microsoft-Specific Modifiers
Modifiers specific to Microsoft C++. Memory addressing, calling conventions, naked
functions, extended storage-class attributes ( __declspec ), __w64 .
Inline Assembler
Using assembly language and C++ in __asm blocks.

Compiler COM Support


A reference to Microsoft-specific classes and global functions used to support COM
types.

Microsoft Extensions
Microsoft extensions to C++.

Nonstandard Behavior
Information about nonstandard behavior of the Microsoft C++ compiler.

Welcome Back to C++


An overview of modern C++ programming practices for writing safe, correct and
efficient programs.

Related Sections
Component Extensions for Runtime Platforms
Reference material on using the Microsoft C++ compiler to target .NET.

C/C++ Building Reference


Compiler options, linker options, and other build tools.

C/C++ Preprocessor Reference


Reference material on pragmas, preprocessor directives, predefined macros, and the
preprocessor.

Visual C++ Libraries


A list of links to the reference start pages for the various Microsoft C++ libraries.

See also
C Language Reference
Welcome back to C++ - Modern C++
Article • 11/07/2022 • 8 minutes to read

Since its creation, C++ has become one of the most widely used programming
languages in the world. Well-written C++ programs are fast and efficient. The language
is more flexible than other languages: It can work at the highest levels of abstraction,
and down at the level of the silicon. C++ supplies highly optimized standard libraries. It
enables access to low-level hardware features, to maximize speed and minimize memory
requirements. C++ can create almost any kind of program: Games, device drivers, HPC,
cloud, desktop, embedded, and mobile apps, and much more. Even libraries and
compilers for other programming languages get written in C++.

One of the original requirements for C++ was backward compatibility with the C
language. As a result, C++ has always permitted C-style programming, with raw
pointers, arrays, null-terminated character strings, and other features. They may enable
great performance, but can also spawn bugs and complexity. The evolution of C++ has
emphasized features that greatly reduce the need to use C-style idioms. The old C-
programming facilities are still there when you need them. However, in modern C++
code you should need them less and less. Modern C++ code is simpler, safer, more
elegant, and still as fast as ever.

The following sections provide an overview of the main features of modern C++. Unless
noted otherwise, the features listed here are available in C++11 and later. In the
Microsoft C++ compiler, you can set the /std compiler option to specify which version
of the standard to use for your project.

Resources and smart pointers


One of the major classes of bugs in C-style programming is the memory leak. Leaks are
often caused by a failure to call delete for memory that was allocated with new .
Modern C++ emphasizes the principle of resource acquisition is initialization (RAII). The
idea is simple. Resources (heap memory, file handles, sockets, and so on) should be
owned by an object. That object creates, or receives, the newly allocated resource in its
constructor, and deletes it in its destructor. The principle of RAII guarantees that all
resources get properly returned to the operating system when the owning object goes
out of scope.

To support easy adoption of RAII principles, the C++ Standard Library provides three
smart pointer types: std::unique_ptr, std::shared_ptr, and std::weak_ptr. A smart pointer
handles the allocation and deletion of the memory it owns. The following example
shows a class with an array member that is allocated on the heap in the call to
make_unique() . The calls to new and delete are encapsulated by the unique_ptr class.
When a widget object goes out of scope, the unique_ptr destructor will be invoked and
it will release the memory that was allocated for the array.

C++

#include <memory>
class widget
{
private:
std::unique_ptr<int[]> data;
public:
widget(const int size) { data = std::make_unique<int[]>(size); }
void do_something() {}
};

void functionUsingWidget() {
widget w(1000000); // lifetime automatically tied to enclosing scope
// constructs w, including the w.data gadget member
// ...
w.do_something();
// ...
} // automatic destruction and deallocation for w and w.data

Whenever possible, use a smart pointer to manage heap memory. If you must use the
new and delete operators explicitly, follow the principle of RAII. For more information,
see Object lifetime and resource management (RAII).

std::string and std::string_view


C-style strings are another major source of bugs. By using std::string and std::wstring,
you can eliminate virtually all the errors associated with C-style strings. You also gain the
benefit of member functions for searching, appending, prepending, and so on. Both are
highly optimized for speed. When passing a string to a function that requires only read-
only access, in C++17 you can use std::string_view for even greater performance benefit.

std::vector and other Standard Library


containers
The standard library containers all follow the principle of RAII. They provide iterators for
safe traversal of elements. And, they're highly optimized for performance and have been
thoroughly tested for correctness. By using these containers, you eliminate the potential
for bugs or inefficiencies that might be introduced in custom data structures. Instead of
raw arrays, use vector as a sequential container in C++.

C++

vector<string> apples;
apples.push_back("Granny Smith");

Use map (not unordered_map ) as the default associative container. Use set, multimap,
and multiset for degenerate and multi cases.

C++

map<string, string> apple_color;


// ...
apple_color["Granny Smith"] = "Green";

When performance optimization is needed, consider using:

The array type when embedding is important, for example, as a class member.

Unordered associative containers such as unordered_map. These have lower per-


element overhead and constant-time lookup, but they can be harder to use
correctly and efficiently.

Sorted vector . For more information, see Algorithms.

Don't use C-style arrays. For older APIs that need direct access to the data, use accessor
methods such as f(vec.data(), vec.size()); instead. For more information about
containers, see C++ Standard Library Containers.

Standard Library algorithms


Before you assume that you need to write a custom algorithm for your program, first
review the C++ Standard Library algorithms. The Standard Library contains an ever-
growing assortment of algorithms for many common operations such as searching,
sorting, filtering, and randomizing. The math library is extensive. In C++17 and later,
parallel versions of many algorithms are provided.

Here are some important examples:

for_each , the default traversal algorithm (along with range-based for loops).

transform , for not-in-place modification of container elements


find_if , the default search algorithm.

sort , lower_bound , and the other default sorting and searching algorithms.

To write a comparator, use strict < and use named lambdas when you can.

C++

auto comp = [](const widget& w1, const widget& w2)


{ return w1.weight() < w2.weight(); }

sort( v.begin(), v.end(), comp );

auto i = lower_bound( v.begin(), v.end(), widget{0}, comp );

auto instead of explicit type names


C++11 introduced the auto keyword for use in variable, function, and template
declarations. auto tells the compiler to deduce the type of the object so that you don't
have to type it explicitly. auto is especially useful when the deduced type is a nested
template:

C++

map<int,list<string>>::iterator i = m.begin(); // C-style


auto i = m.begin(); // modern C++

Range-based for loops


C-style iteration over arrays and containers is prone to indexing errors and is also
tedious to type. To eliminate these errors, and make your code more readable, use
range-based for loops with both Standard Library containers and raw arrays. For more
information, see Range-based for statement.

C++

#include <iostream>
#include <vector>

int main()
{
std::vector<int> v {1,2,3};

// C-style
for(int i = 0; i < v.size(); ++i)
{
std::cout << v[i];
}

// Modern C++:
for(auto& num : v)
{
std::cout << num;
}
}

constexpr expressions instead of macros


Macros in C and C++ are tokens that are processed by the preprocessor before
compilation. Each instance of a macro token is replaced with its defined value or
expression before the file is compiled. Macros are commonly used in C-style
programming to define compile-time constant values. However, macros are error-prone
and difficult to debug. In modern C++, you should prefer constexpr variables for
compile-time constants:

C++

#define SIZE 10 // C-style


constexpr int size = 10; // modern C++

Uniform initialization
In modern C++, you can use brace initialization for any type. This form of initialization is
especially convenient when initializing arrays, vectors, or other containers. In the
following example, v2 is initialized with three instances of S . v3 is initialized with three
instances of S that are themselves initialized using braces. The compiler infers the type
of each element based on the declared type of v3 .

C++

#include <vector>

struct S
{
std::string name;
float num;
S(std::string s, float f) : name(s), num(f) {}
};
int main()
{
// C-style initialization
std::vector<S> v;
S s1("Norah", 2.7);
S s2("Frank", 3.5);
S s3("Jeri", 85.9);

v.push_back(s1);
v.push_back(s2);
v.push_back(s3);

// Modern C++:
std::vector<S> v2 {s1, s2, s3};

// or...
std::vector<S> v3{ {"Norah", 2.7}, {"Frank", 3.5}, {"Jeri", 85.9} };

For more information, see Brace initialization.

Move semantics
Modern C++ provides move semantics, which make it possible to eliminate unnecessary
memory copies. In earlier versions of the language, copies were unavoidable in certain
situations. A move operation transfers ownership of a resource from one object to the
next without making a copy. Some classes own resources such as heap memory, file
handles, and so on. When you implement a resource-owning class, you can define a
move constructor and move assignment operator for it. The compiler chooses these
special members during overload resolution in situations where a copy isn't needed. The
Standard Library container types invoke the move constructor on objects if one is
defined. For more information, see Move Constructors and Move Assignment Operators
(C++).

Lambda expressions
In C-style programming, a function can be passed to another function by using a
function pointer. Function pointers are inconvenient to maintain and understand. The
function they refer to may be defined elsewhere in the source code, far away from the
point at which it's invoked. Also, they're not type-safe. Modern C++ provides function
objects, classes that override the operator() operator, which enables them to be called
like a function. The most convenient way to create function objects is with inline lambda
expressions. The following example shows how to use a lambda expression to pass a
function object, that the find_if function will invoke on each element in the vector:

C++

std::vector<int> v {1,2,3,4,5};
int x = 2;
int y = 4;
auto result = find_if(begin(v), end(v), [=](int i) { return i > x && i <
y; });

The lambda expression [=](int i) { return i > x && i < y; } can be read as "function
that takes a single argument of type int and returns a boolean that indicates whether
the argument is greater than x and less than y ." Notice that the variables x and y
from the surrounding context can be used in the lambda. The [=] specifies that those
variables are captured by value; in other words, the lambda expression has its own
copies of those values.

Exceptions
Modern C++ emphasizes exceptions, not error codes, as the best way to report and
handle error conditions. For more information, see Modern C++ best practices for
exceptions and error handling.

std::atomic
Use the C++ Standard Library std::atomic struct and related types for inter-thread
communication mechanisms.

std::variant (C++17)
Unions are commonly used in C-style programming to conserve memory by enabling
members of different types to occupy the same memory location. However, unions
aren't type-safe and are prone to programming errors. C++17 introduces the
std::variant class as a more robust and safe alternative to unions. The std::visit function
can be used to access the members of a variant type in a type-safe manner.

See also
C++ Language Reference
Lambda Expressions
C++ Standard Library
Microsoft C/C++ language conformance
Lexical conventions
Article • 08/03/2021 • 2 minutes to read

This section introduces the fundamental elements of a C++ program. You use these
elements, called "lexical elements" or "tokens" to construct statements, definitions,
declarations, and so on, which are used to construct complete programs. The following
lexical elements are discussed in this section:

Tokens and character sets


Comments
Identifiers
Keywords
Punctuators
Numeric, boolean, and pointer literals
String and character literals
User-defined literals

For more information about how C++ source files are parsed, see Phases of translation.

See also
C++ Language Reference
Translation units and linkage
Tokens and character sets
Article • 08/03/2021 • 3 minutes to read

The text of a C++ program consists of tokens and white space. A token is the smallest
element of a C++ program that is meaningful to the compiler. The C++ parser
recognizes these kinds of tokens:

Keywords
Identifiers
Numeric, Boolean and Pointer Literals
String and Character Literals
User-Defined Literals
Operators
Punctuators

Tokens are usually separated by white space, which can be one or more:

Blanks
Horizontal or vertical tabs
New lines
Form feeds
Comments

Basic source character set


The C++ standard specifies a basic source character set that may be used in source files.
To represent characters outside of this set, additional characters can be specified by
using a universal character name. The MSVC implementation allows additional
characters. The basic source character set consists of 96 characters that may be used in
source files. This set includes the space character, horizontal tab, vertical tab, form feed
and new-line control characters, and this set of graphical characters:

a b c d e f g h i j k l m n o p q r s t u v w x y z

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

0 1 2 3 4 5 6 7 8 9

_ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '

Microsoft Specific
MSVC includes the $ character as a member of the basic source character set. MSVC
also allows an additional set of characters to be used in source files, based on the file
encoding. By default, Visual Studio stores source files by using the default codepage.
When source files are saved by using a locale-specific codepage or a Unicode codepage,
MSVC allows you to use any of the characters of that code page in your source code,
except for the control codes not explicitly allowed in the basic source character set. For
example, you can put Japanese characters in comments, identifiers, or string literals if
you save the file using a Japanese codepage. MSVC does not allow character sequences
that cannot be translated into valid multibyte characters or Unicode code points.
Depending on compiler options, not all allowed characters may appear in identifiers. For
more information, see Identifiers.

END Microsoft Specific

Universal character names


Because C++ programs can use many more characters than the ones specified in the
basic source character set, you can specify these characters in a portable way by using
universal character names. A universal character name consists of a sequence of
characters that represent a Unicode code point. These take two forms. Use \UNNNNNNNN
to represent a Unicode code point of the form U+NNNNNNNN, where NNNNNNNN is
the eight-digit hexadecimal code point number. Use four-digit \uNNNN to represent a
Unicode code point of the form U+0000NNNN.

Universal character names can be used in identifiers and in string and character literals.
A universal character name cannot be used to represent a surrogate code point in the
range 0xD800-0xDFFF. Instead, use the desired code point; the compiler automatically
generates any required surrogates. Additional restrictions apply to the universal
character names that can be used in identifiers. For more information, see Identifiers
and String and Character Literals.

Microsoft Specific

The Microsoft C++ compiler treats a character in universal character name form and
literal form interchangeably. For example, you can declare an identifier using universal
character name form, and use it in literal form:

C++

auto \u30AD = 42; // \u30AD is 'キ'


if (キ == 42) return true; // \u30AD and キ are the same to the compiler
The format of extended characters on the Windows clipboard is specific to application
locale settings. Cutting and pasting these characters into your code from another
application may introduce unexpected character encodings. This can result in parsing
errors with no visible cause in your code. We recommend that you set your source file
encoding to a Unicode codepage before pasting extended characters. We also
recommend that you use an IME or the Character Map app to generate extended
characters.

END Microsoft Specific

Execution character sets


The execution character sets represent the characters and strings that can appear in a
compiled program. These character sets consist of all the characters permitted in a
source file, and also the control characters that represent alert, backspace, carriage
return, and the null character. The execution character set has a locale-specific
representation.
Comments (C++)
Article • 08/03/2021 • 2 minutes to read

A comment is text that the compiler ignores but that is useful for programmers.
Comments are normally used to annotate code for future reference. The compiler treats
them as white space. You can use comments in testing to make certain lines of code
inactive; however, #if / #endif preprocessor directives work better for this because you
can surround code that contains comments but you cannot nest comments.

A C++ comment is written in one of the following ways:

The /* (slash, asterisk) characters, followed by any sequence of characters


(including new lines), followed by the */ characters. This syntax is the same as
ANSI C.

The // (two slashes) characters, followed by any sequence of characters. A new


line not immediately preceded by a backslash terminates this form of comment.
Therefore, it is commonly called a "single-line comment."

The comment characters ( /* , */ , and // ) have no special meaning within a character


constant, string literal, or comment. Comments using the first syntax, therefore, cannot
be nested.

See also
Lexical Conventions
Identifiers (C++)
Article • 08/03/2021 • 3 minutes to read

An identifier is a sequence of characters used to denote one of the following:

Object or variable name

Class, structure, or union name

Enumerated type name

Member of a class, structure, union, or enumeration

Function or class-member function

typedef name

Label name

Macro name

Macro parameter

The following characters are allowed as any character of an identifier:

_ a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z

Certain ranges of universal character names are also allowed in an identifier. A universal
character name in an identifier cannot designate a control character or a character in the
basic source character set. For more information, see Character Sets. These Unicode
code point number ranges are allowed as universal character names for any character in
an identifier:

00A8, 00AA, 00AD, 00AF, 00B2-00B5, 00B7-00BA, 00BC-00BE, 00C0-00D6, 00D8-


00F6, 00F8-00FF, 0100-02FF, 0370-167F, 1681-180D, 180F-1DBF, 1E00-1FFF, 200B-
200D, 202A-202E, 203F-2040, 2054, 2060-206F, 2070-20CF, 2100-218F, 2460-24FF,
2776-2793, 2C00-2DFF, 2E80-2FFF, 3004-3007, 3021-302F, 3031-303F, 3040-D7FF,
F900-FD3D, FD40-FDCF, FDF0-FE1F, FE30-FE44, FE47-FFFD, 10000-1FFFD, 20000-
2FFFD, 30000-3FFFD, 40000-4FFFD, 50000-5FFFD, 60000-6FFFD, 70000-7FFFD,
80000-8FFFD, 90000-9FFFD, A0000-AFFFD, B0000-BFFFD, C0000-CFFFD, D0000-
DFFFD, E0000-EFFFD

The following characters are allowed as any character in an identifier except the first:

0 1 2 3 4 5 6 7 8 9

These Unicode code point number ranges are also allowed as universal character names
for any character in an identifier except the first:

0300-036F, 1DC0-1DFF, 20D0-20FF, FE20-FE2F

Microsoft Specific

Only the first 2048 characters of Microsoft C++ identifiers are significant. Names for
user-defined types are "decorated" by the compiler to preserve type information. The
resultant name, including the type information, cannot be longer than 2048 characters.
(See Decorated Names for more information.) Factors that can influence the length of a
decorated identifier are:

Whether the identifier denotes an object of user-defined type or a type derived


from a user-defined type.

Whether the identifier denotes a function or a type derived from a function.

The number of arguments to a function.

The dollar sign $ is a valid identifier character in the Microsoft C++ compiler (MSVC).
MSVC also allows you to use the actual characters represented by the allowed ranges of
universal character names in identifiers. To use these characters, you must save the file
by using a file encoding codepage that includes them. This example shows how both
extended characters and universal character names can be used interchangeably in your
code.

C++

// extended_identifier.cpp
// In Visual Studio, use File, Advanced Save Options to set
// the file encoding to Unicode codepage 1200
struct テスト // Japanese 'test'
{
void トスト() {} // Japanese 'toast'
};

int main() {
テスト \u30D1\u30F3; // Japanese パン 'bread' in UCN form
パン.トスト(); // compiler recognizes UCN or literal form
}

The range of characters allowed in an identifier is less restrictive when compiling


C++/CLI code. Identifiers in code compiled by using /clr should follow Standard ECMA-
335: Common Language Infrastructure (CLI) .

END Microsoft Specific

The first character of an identifier must be an alphabetic character, either uppercase or


lowercase, or an underscore ( _ ). Because C++ identifiers are case sensitive, fileName is
different from FileName .

Identifiers cannot be exactly the same spelling and case as keywords. Identifiers that
contain keywords are legal. For example, Pint is a legal identifier, even though it
contains int , which is a keyword.

Use of two sequential underscore characters ( __ ) in an identifier, or a single leading


underscore followed by a capital letter, is reserved for C++ implementations in all
scopes. You should avoid using one leading underscore followed by a lowercase letter
for names with file scope because of possible conflicts with current or future reserved
identifiers.

See also
Lexical Conventions
Keywords (C++)
Article • 09/21/2021 • 3 minutes to read

Keywords are predefined reserved identifiers that have special meanings. They can't be
used as identifiers in your program. The following keywords are reserved for Microsoft
C++. Names with leading underscores and names specified for C++/CX and C++/CLI
are Microsoft extensions.

Standard C++ keywords


alignas
alignof
and b
and_eq b
asm a
auto
bitand b
bitor b
bool
break
case
catch
char
char8_t c
char16_t
char32_t
class
compl b
concept c

const
const_cast
consteval c

constexpr

constinit c

continue
co_await c

co_return c

co_yield c
decltype
default
delete
do
double
dynamic_cast
else
enum
explicit
export c

extern
false
float
for
friend
goto
if
inline

int
long
mutable
namespace
new
noexcept
not b
not_eq b
nullptr
operator
or b
or_eq b
private
protected
public
register reinterpret_cast
requires c

return
short
signed
sizeof
static
static_assert

static_cast
struct
switch
template
this
thread_local
throw
true
try
typedef
typeid
typename
union
unsigned
using declaration
using directive
virtual
void
volatile
wchar_t
while
xor b
xor_eq b

a The Microsoft-specific __asm keyword replaces C++ asm syntax. asm is reserved for
compatibility with other C++ implementations, but not implemented. Use __asm for
inline assembly on x86 targets. Microsoft C++ doesn't support Inline assembly for other
targets.

b
The extended operator synonyms are keywords when /permissive- or /Za (Disable
language extensions) is specified. They aren't keywords when Microsoft extensions are
enabled.

c
Supported when /std:c++20 or later (such as /std:c++latest ) is specified.

Microsoft-specific C++ keywords


In C++, identifiers that contain two consecutive underscores are reserved for compiler
implementations. The Microsoft convention is to precede Microsoft-specific keywords
with double underscores. These words can't be used as identifier names.

Microsoft extensions are enabled by default. To ensure that your programs are fully
portable, you can disable Microsoft extensions by specifying the /permissive- or /Za
(Disable language extensions) option during compilation. These options disable some
Microsoft-specific keywords.

When Microsoft extensions are enabled, you can use the Microsoft-specific keywords in
your programs. For ANSI conformance, these keywords are prefaced by a double
underscore. For backward compatibility, single-underscore versions of many of the
double-underscored keywords are supported. The __cdecl keyword is available with no
leading underscore.

The __asm keyword replaces C++ asm syntax. asm is reserved for compatibility with
other C++ implementations, but not implemented. Use __asm .

The __based keyword has limited uses for 32-bit and 64-bit target compilations.

__alignof e
__asm e
__assume e
__based e
__cdecl e
__declspec e
__event
__except e
__fastcall e
__finally e
__forceinline e

__hook d
__if_exists
__if_not_exists
__inline e
__int16 e
__int32 e
__int64 e
__int8 e
__interface
__leave e
__m128

__m128d
__m128i
__m64
__multiple_inheritance e
__ptr32 e
__ptr64e
__raise
__restrict e
__single_inheritancee
__sptre
__stdcall e

__super
__thiscall
__unaligned e
__unhook d
__uptr e
__uuidof e
__vectorcall e
__virtual_inheritance e
__w64 e
__wchar_t

d Intrinsic function used in event handling.

e For backward compatibility with previous versions, these keywords are available both
with two leading underscores and a single leading underscore when Microsoft
extensions are enabled (the default).

Microsoft keywords in __declspec modifiers


These identifiers are extended attributes for the __declspec modifier. They're
considered keywords within that context.

align
allocate
allocator
appdomain
code_seg
deprecated

dllexport
dllimport
jitintrinsic
naked
noalias
noinline

noreturn
no_sanitize_address
nothrow
novtable
process
property

restrict
safebuffers
selectany
spectre
thread
uuid

C++/CLI and C++/CX keywords


__abstract f
__box f
__delegate f
__gc f
__identifier
__nogc f
__noop
__pin f
__property f

__sealed f

__try_cast f
__value f
abstract g
array g
as_friend
delegate g
enum class
enum struct
event g

finally
for each in
gcnew g
generic g
initonly
interface class g
interface struct g
interior_ptr g
literal g

new g
property g
ref class
ref struct
safecast
sealed g
typeid
value class g
value struct g

f
Applicable to Managed Extensions for C++ only. This syntax is now deprecated. For
more information, see Component Extensions for Runtime Platforms.

g
Applicable to C++/CLI.

See also
Lexical conventions
C++ built-in operators, precedence, and associativity
Punctuators (C++)
Article • 08/03/2021 • 2 minutes to read

Punctuators in C++ have syntactic and semantic meaning to the compiler but do not, of
themselves, specify an operation that yields a value. Some punctuators, either alone or
in combination, can also be C++ operators or be significant to the preprocessor.

Any of the following characters are considered punctuators:

! % ^ & * ( ) - + = { } | ~
[ ] \ ; ' : " < > ? , . / #

The punctuators [ ], ( ), and { } must appear in pairs after translation phase 4.

See also
Lexical Conventions
Numeric, boolean, and pointer literals
Article • 10/26/2022 • 5 minutes to read

A literal is a program element that directly represents a value. This article covers literals
of type integer, floating-point, boolean, and pointer. For information about string and
character literals, see String and Character Literals (C++). You can also define your own
literals based on any of these categories. For more information, see User-defined literals
(C++).

You can use literals in many contexts, but most commonly to initialize named variables
and to pass arguments to functions:

C++

const int answer = 42; // integer literal


double d = sin(108.87); // floating point literal passed to sin function
bool b = true; // boolean literal
MyClass* mc = nullptr; // pointer literal

Sometimes it's important to tell the compiler how to interpret a literal, or what specific
type to give to it. It's done by appending prefixes or suffixes to the literal. For example,
the prefix 0x tells the compiler to interpret the number that follows it as a hexadecimal
value, for example 0x35 . The ULL suffix tells the compiler to treat the value as an
unsigned long long type, as in 5894345ULL . See the following sections for the complete

list of prefixes and suffixes for each literal type.

Integer literals
Integer literals begin with a digit and have no fractional parts or exponents. You can
specify integer literals in decimal, binary, octal, or hexadecimal form. You can optionally
specify an integer literal as unsigned, and as a long or long long type, by using a suffix.

When no prefix or suffix is present, the compiler will give an integral literal value type
int (32 bits), if the value will fit, otherwise it will give it type long long (64 bits).

To specify a decimal integral literal, begin the specification with a nonzero digit. For
example:

C++

int i = 157; // Decimal literal


int j = 0198; // Not a decimal number; erroneous octal literal
int k = 0365; // Leading zero specifies octal literal, not decimal
int m = 36'000'000 // digit separators make large values more readable

To specify an octal integral literal, begin the specification with 0, followed by a sequence
of digits in the range 0 through 7. The digits 8 and 9 are errors in specifying an octal
literal. For example:

C++

int i = 0377; // Octal literal


int j = 0397; // Error: 9 is not an octal digit

To specify a hexadecimal integral literal, begin the specification with 0x or 0X (the case
of the "x" doesn't matter), followed by a sequence of digits in the range 0 through 9
and a (or A ) through f (or F ). Hexadecimal digits a (or A ) through f (or F ) represent
values in the range 10 through 15. For example:

C++

int i = 0x3fff; // Hexadecimal literal


int j = 0X3FFF; // Equal to i

To specify an unsigned type, use either the u or U suffix. To specify a long type, use
either the l or L suffix. To specify a 64-bit integral type, use the LL, or ll suffix. The i64
suffix is still supported, but we don't recommend it. It's specific to Microsoft and isn't
portable. For example:

C++

unsigned val_1 = 328u; // Unsigned value


long val_2 = 0x7FFFFFL; // Long value specified
// as hex literal
unsigned long val_3 = 0776745ul; // Unsigned long value
auto val_4 = 108LL; // signed long long
auto val_4 = 0x8000000000000000ULL << 16; // unsigned long long

Digit separators: You can use the single-quote character (apostrophe) to separate place
values in larger numbers to make them easier for humans to read. Separators have no
effect on compilation.

C++

long long i = 24'847'458'121;


Floating point literals
Floating-point literals specify values that must have a fractional part. These values
contain decimal points ( . ) and can contain exponents.

Floating-point literals have a significand (sometimes called a mantissa), which specifies


the value of the number. They have an exponent, which specifies the magnitude of the
number. And, they have an optional suffix that specifies the literal's type. The significand
is specified as a sequence of digits followed by a period, followed by an optional
sequence of digits representing the fractional part of the number. For example:

C++

18.46
38.

The exponent, if present, specifies the magnitude of the number as a power of 10, as
shown in the following example:

C++

18.46e0 // 18.46
18.46e1 // 184.6

The exponent may be specified using e or E , which have the same meaning, followed
by an optional sign (+ or -) and a sequence of digits. If an exponent is present, the
trailing decimal point is unnecessary in whole numbers such as 18E0 .

Floating-point literals default to type double . By using the suffixes f or l or F or L


(the suffix isn't case sensitive), the literal can be specified as float or long double .

Although long double and double have the same representation, they're not the same
type. For example, you can have overloaded functions such as

C++

void func( double );

and

C++

void func( long double );


Boolean literals
The boolean literals are true and false .

Pointer literal (C++11)


C++ introduces the nullptr literal to specify a zero-initialized pointer. In portable code,
nullptr should be used instead of integral-type zero or macros such as NULL .

Binary literals (C++14)


A binary literal can be specified by the use of the 0B or 0b prefix, followed by a
sequence of 1's and 0's:

C++

auto x = 0B001101 ; // int


auto y = 0b000001 ; // int

Avoid using literals as "magic constants"


You can use literals directly in expressions and statements although it's not always good
programming practice:

C++

if (num < 100)


return "Success";

In the previous example, a better practice is to use a named constant that conveys a
clear meaning, for example "MAXIMUM_ERROR_THRESHOLD". And if the return value
"Success" is seen by end users, then it might be better to use a named string constant.
You can keep string constants in a single location in a file that can be localized into
other languages. Using named constants helps both yourself and others to understand
the intent of the code.

See also
Lexical conventions
C++ string literals
C++ user-defined literals
String and character literals (C++)
Article • 11/02/2022 • 18 minutes to read

C++ supports various string and character types, and provides ways to express literal
values of each of these types. In your source code, you express the content of your
character and string literals using a character set. Universal character names and escape
characters allow you to express any string using only the basic source character set. A
raw string literal enables you to avoid using escape characters, and can be used to
express all types of string literals. You can also create std::string literals without having
to perform extra construction or conversion steps.

C++

#include <string>
using namespace std::string_literals; // enables s-suffix for std::string
literals

int main()
{
// Character literals
auto c0 = 'A'; // char
auto c1 = u8'A'; // char
auto c2 = L'A'; // wchar_t
auto c3 = u'A'; // char16_t
auto c4 = U'A'; // char32_t

// Multicharacter literals
auto m0 = 'abcd'; // int, value 0x61626364

// String literals
auto s0 = "hello"; // const char*
auto s1 = u8"hello"; // const char* before C++20, encoded as UTF-8,
// const char8_t* in C++20
auto s2 = L"hello"; // const wchar_t*
auto s3 = u"hello"; // const char16_t*, encoded as UTF-16
auto s4 = U"hello"; // const char32_t*, encoded as UTF-32

// Raw string literals containing unescaped \ and "


auto R0 = R"("Hello \ world")"; // const char*
auto R1 = u8R"("Hello \ world")"; // const char* before C++20, encoded
as UTF-8,
// const char8_t* in C++20
auto R2 = LR"("Hello \ world")"; // const wchar_t*
auto R3 = uR"("Hello \ world")"; // const char16_t*, encoded as UTF-16
auto R4 = UR"("Hello \ world")"; // const char32_t*, encoded as UTF-32

// Combining string literals with standard s-suffix


auto S0 = "hello"s; // std::string
auto S1 = u8"hello"s; // std::string before C++20, std::u8string in
C++20
auto S2 = L"hello"s; // std::wstring
auto S3 = u"hello"s; // std::u16string
auto S4 = U"hello"s; // std::u32string

// Combining raw string literals with standard s-suffix


auto S5 = R"("Hello \ world")"s; // std::string from a raw const char*
auto S6 = u8R"("Hello \ world")"s; // std::string from a raw const char*
before C++20, encoded as UTF-8,
// std::u8string in C++20
auto S7 = LR"("Hello \ world")"s; // std::wstring from a raw const
wchar_t*
auto S8 = uR"("Hello \ world")"s; // std::u16string from a raw const
char16_t*, encoded as UTF-16
auto S9 = UR"("Hello \ world")"s; // std::u32string from a raw const
char32_t*, encoded as UTF-32
}

String literals can have no prefix, or u8 , L , u , and U prefixes to denote narrow character
(single-byte or multi-byte), UTF-8, wide character (UCS-2 or UTF-16), UTF-16 and UTF-32
encodings, respectively. A raw string literal can have R , u8R , LR , uR , and UR prefixes for
the raw version equivalents of these encodings. To create temporary or static
std::string values, you can use string literals or raw string literals with an s suffix. For

more information, see the String literals section below. For more information on the
basic source character set, universal character names, and using characters from
extended codepages in your source code, see Character sets.

Character literals
A character literal is composed of a constant character. It's represented by the character
surrounded by single quotation marks. There are five kinds of character literals:

Ordinary character literals of type char , for example 'a'

UTF-8 character literals of type char ( char8_t in C++20), for example u8'a'

Wide-character literals of type wchar_t , for example L'a'

UTF-16 character literals of type char16_t , for example u'a'

UTF-32 character literals of type char32_t , for example U'a'

The character used for a character literal may be any character, except for the reserved
characters backslash ( \ ), single quotation mark ( ' ), or newline. Reserved characters can
be specified by using an escape sequence. Characters may be specified by using
universal character names, as long as the type is large enough to hold the character.
Encoding
Character literals are encoded differently based their prefix.

A character literal without a prefix is an ordinary character literal. The value of an


ordinary character literal containing a single character, escape sequence, or
universal character name that can be represented in the execution character set
has a value equal to the numerical value of its encoding in the execution character
set. An ordinary character literal that contains more than one character, escape
sequence, or universal character name is a multicharacter literal. A multicharacter
literal or an ordinary character literal that can't be represented in the execution
character set has type int , and its value is implementation-defined. For MSVC, see
the Microsoft-specific section below.

A character literal that begins with the L prefix is a wide-character literal. The value
of a wide-character literal containing a single character, escape sequence, or
universal character name has a value equal to the numerical value of its encoding
in the execution wide-character set unless the character literal has no
representation in the execution wide-character set, in which case the value is
implementation-defined. The value of a wide-character literal containing multiple
characters, escape sequences, or universal character names is implementation-
defined. For MSVC, see the Microsoft-specific section below.

A character literal that begins with the u8 prefix is a UTF-8 character literal. The
value of a UTF-8 character literal containing a single character, escape sequence, or
universal character name has a value equal to its ISO 10646 code point value if it
can be represented by a single UTF-8 code unit (corresponding to the C0 Controls
and Basic Latin Unicode block). If the value can't be represented by a single UTF-8
code unit, the program is ill-formed. A UTF-8 character literal containing more than
one character, escape sequence, or universal character name is ill-formed.

A character literal that begins with the u prefix is a UTF-16 character literal. The
value of a UTF-16 character literal containing a single character, escape sequence,
or universal character name has a value equal to its ISO 10646 code point value if it
can be represented by a single UTF-16 code unit (corresponding to the basic
multi-lingual plane). If the value can't be represented by a single UTF-16 code unit,
the program is ill-formed. A UTF-16 character literal containing more than one
character, escape sequence, or universal character name is ill-formed.

A character literal that begins with the U prefix is a UTF-32 character literal. The
value of a UTF-32 character literal containing a single character, escape sequence,
or universal character name has a value equal to its ISO 10646 code point value. A
UTF-32 character literal containing more than one character, escape sequence, or
universal character name is ill-formed.

Escape sequences
There are three kinds of escape sequences: simple, octal, and hexadecimal. Escape
sequences may be any of the following values:

Value Escape sequence

newline \n

backslash \\

horizontal tab \t

question mark ? or \?

vertical tab \v

single quote \'

backspace \b

double quote \"

carriage return \r

the null character \0

form feed \f

octal \ooo

alert (bell) \a

hexadecimal \xhhh

An octal escape sequence is a backslash followed by a sequence of one to three octal


digits. An octal escape sequence terminates at the first character that's not an octal
digit, if encountered sooner than the third digit. The highest possible octal value is \377 .

A hexadecimal escape sequence is a backslash followed by the character x , followed by


a sequence of one or more hexadecimal digits. Leading zeroes are ignored. In an
ordinary or u8-prefixed character literal, the highest hexadecimal value is 0xFF. In an L-
prefixed or u-prefixed wide character literal, the highest hexadecimal value is 0xFFFF. In
a U-prefixed wide character literal, the highest hexadecimal value is 0xFFFFFFFF.
This sample code shows some examples of escaped characters using ordinary character
literals. The same escape sequence syntax is valid for the other character literal types.

C++

#include <iostream>
using namespace std;

int main() {
char newline = '\n';
char tab = '\t';
char backspace = '\b';
char backslash = '\\';
char nullChar = '\0';

cout << "Newline character: " << newline << "ending" << endl;
cout << "Tab character: " << tab << "ending" << endl;
cout << "Backspace character: " << backspace << "ending" << endl;
cout << "Backslash character: " << backslash << "ending" << endl;
cout << "Null character: " << nullChar << "ending" << endl;
}
/* Output:
Newline character:
ending
Tab character: ending
Backspace character:ending
Backslash character: \ending
Null character: ending
*/

The backslash character ( \ ) is a line-continuation character when it's placed at the end
of a line. If you want a backslash character to appear as a character literal, you must type
two backslashes in a row ( \\ ). For more information about the line continuation
character, see Phases of Translation.

Microsoft-specific

To create a value from a narrow multicharacter literal, the compiler converts the
character or character sequence between single quotes into 8-bit values within a 32-bit
integer. Multiple characters in the literal fill corresponding bytes as needed from high-
order to low-order. The compiler then converts the integer to the destination type
following the usual rules. For example, to create a char value, the compiler takes the
low-order byte. To create a wchar_t or char16_t value, the compiler takes the low-order
word. The compiler warns that the result is truncated if any bits are set above the
assigned byte or word.

C++
char c0 = 'abcd'; // C4305, C4309, truncates to 'd'
wchar_t w0 = 'abcd'; // C4305, C4309, truncates to '\x6364'
int i0 = 'abcd'; // 0x61626364

An octal escape sequence that appears to contain more than three digits is treated as a
3-digit octal sequence, followed by the subsequent digits as characters in a
multicharacter literal, which can give surprising results. For example:

C++

char c1 = '\100'; // '@'


char c2 = '\1000'; // C4305, C4309, truncates to '0'

Escape sequences that appear to contain non-octal characters are evaluated as an octal
sequence up to the last octal character, followed by the remaining characters as the
subsequent characters in a multicharacter literal. Warning C4125 is generated if the first
non-octal character is a decimal digit. For example:

C++

char c3 = '\009'; // '9'


char c4 = '\089'; // C4305, C4309, truncates to '9'
char c5 = '\qrs'; // C4129, C4305, C4309, truncates to 's'

An octal escape sequence that has a higher value than \377 causes error C2022: 'value-
in-decimal': too big for character.

An escape sequence that appears to have hexadecimal and non-hexadecimal characters


is evaluated as a multicharacter literal that contains a hexadecimal escape sequence up
to the last hexadecimal character, followed by the non-hexadecimal characters. A
hexadecimal escape sequence that contains no hexadecimal digits causes compiler error
C2153: "hex literals must have at least one hex digit".

C++

char c6 = '\x0050'; // 'P'


char c7 = '\x0pqr'; // C4305, C4309, truncates to 'r'

If a wide character literal prefixed with L contains a multicharacter sequence, the value
is taken from the first character, and the compiler raises warning C4066. Subsequent
characters are ignored, unlike the behavior of the equivalent ordinary multicharacter
literal.
C++

wchar_t w1 = L'\100'; // L'@'


wchar_t w2 = L'\1000'; // C4066 L'@', 0 ignored
wchar_t w3 = L'\009'; // C4066 L'\0', 9 ignored
wchar_t w4 = L'\089'; // C4066 L'\0', 89 ignored
wchar_t w5 = L'\qrs'; // C4129, C4066 L'q' escape, rs ignored
wchar_t w6 = L'\x0050'; // L'P'
wchar_t w7 = L'\x0pqr'; // C4066 L'\0', pqr ignored

The Microsoft-specific section ends here.

Universal character names


In character literals and native (non-raw) string literals, any character may be
represented by a universal character name. Universal character names are formed by a
prefix \U followed by an eight-digit Unicode code point, or by a prefix \u followed by a
four-digit Unicode code point. All eight or four digits, respectively, must be present to
make a well-formed universal character name.

C++

char u1 = 'A'; // 'A'


char u2 = '\101'; // octal, 'A'
char u3 = '\x41'; // hexadecimal, 'A'
char u4 = '\u0041'; // \u UCN 'A'
char u5 = '\U00000041'; // \U UCN 'A'

Surrogate Pairs
Universal character names can't encode values in the surrogate code point range D800-
DFFF. For Unicode surrogate pairs, specify the universal character name by using
\UNNNNNNNN , where NNNNNNNN is the eight-digit code point for the character. The

compiler generates a surrogate pair if necessary.

In C++03, the language only allowed a subset of characters to be represented by their


universal character names, and allowed some universal character names that didn't
actually represent any valid Unicode characters. This mistake was fixed in the C++11
standard. In C++11, both character and string literals and identifiers can use universal
character names. For more information on universal character names, see Character
Sets. For more information about Unicode, see Unicode. For more information about
surrogate pairs, see Surrogate Pairs and Supplementary Characters.
String literals
A string literal represents a sequence of characters that together form a null-terminated
string. The characters must be enclosed between double quotation marks. There are the
following kinds of string literals:

Narrow string literals


A narrow string literal is a non-prefixed, double-quote delimited, null-terminated array
of type const char[n] , where n is the length of the array in bytes. A narrow string literal
may contain any graphic character except the double quotation mark ( " ), backslash ( \ ),
or newline character. A narrow string literal may also contain the escape sequences
listed above, and universal character names that fit in a byte.

C++

const char *narrow = "abcd";

// represents the string: yes\no


const char *escaped = "yes\\no";

UTF-8 encoded strings

A UTF-8 encoded string is a u8-prefixed, double-quote delimited, null-terminated array


of type const char[n] , where n is the length of the encoded array in bytes. A u8-
prefixed string literal may contain any graphic character except the double quotation
mark ( " ), backslash ( \ ), or newline character. A u8-prefixed string literal may also
contain the escape sequences listed above, and any universal character name.

C++20 introduces the portable char8_t (UTF-8 encoded 8-bit Unicode) character type.
In C++20, u8 literal prefixes specify characters or strings of char8_t instead of char .

C++

// Before C++20
const char* str1 = u8"Hello World";
const char* str2 = u8"\U0001F607 is O:-)";
// C++20 and later
const char8_t* u8str1 = u8"Hello World";
const char8_t* u8str2 = u8"\U0001F607 is O:-)";

Wide string literals


A wide string literal is a null-terminated array of constant wchar_t that is prefixed by ' L '
and contains any graphic character except the double quotation mark ( " ), backslash ( \ ),
or newline character. A wide string literal may contain the escape sequences listed
above and any universal character name.

C++

const wchar_t* wide = L"zyxw";


const wchar_t* newline = L"hello\ngoodbye";

char16_t and char32_t (C++11)

C++11 introduces the portable char16_t (16-bit Unicode) and char32_t (32-bit
Unicode) character types:

C++

auto s3 = u"hello"; // const char16_t*


auto s4 = U"hello"; // const char32_t*

Raw string literals (C++11)


A raw string literal is a null-terminated array—of any character type—that contains any
graphic character, including the double quotation mark ( " ), backslash ( \ ), or newline
character. Raw string literals are often used in regular expressions that use character
classes, and in HTML strings and XML strings. For examples, see the following article:
Bjarne Stroustrup's FAQ on C++11 .

C++

// represents the string: An unescaped \ character


const char* raw_narrow = R"(An unescaped \ character)";
const wchar_t* raw_wide = LR"(An unescaped \ character)";
const char* raw_utf8a = u8R"(An unescaped \ character)"; // Before C++20
const char8_t* raw_utf8b = u8R"(An unescaped \ character)"; // C++20
const char16_t* raw_utf16 = uR"(An unescaped \ character)";
const char32_t* raw_utf32 = UR"(An unescaped \ character)";

A delimiter is a user-defined sequence of up to 16 characters that immediately precedes


the opening parenthesis of a raw string literal, and immediately follows its closing
parenthesis. For example, in R"abc(Hello"\()abc" the delimiter sequence is abc and the
string content is Hello"\( . You can use a delimiter to disambiguate raw strings that
contain both double quotation marks and parentheses. This string literal causes a
compiler error:

C++

// meant to represent the string: )"


const char* bad_parens = R"()")"; // error C2059

But a delimiter resolves it:

C++

const char* good_parens = R"xyz()")xyz";

You can construct a raw string literal that contains a newline (not the escaped character)
in the source:

C++

// represents the string: hello


//goodbye
const wchar_t* newline = LR"(hello
goodbye)";

std::string literals (C++14)


std::string literals are Standard Library implementations of user-defined literals (see
below) that are represented as "xyz"s (with a s suffix). This kind of string literal
produces a temporary object of type std::string , std::wstring , std::u32string , or
std::u16string , depending on the prefix that is specified. When no prefix is used, as
above, a std::string is produced. L"xyz"s produces a std::wstring . u"xyz"s produces
a std::u16string, and U"xyz"s produces a std::u32string.

C++

//#include <string>
//using namespace std::string_literals;
string str{ "hello"s };
string str2{ u8"Hello World" }; // Before C++20
u8string u8str2{ u8"Hello World" }; // C++20
wstring str3{ L"hello"s };
u16string str4{ u"hello"s };
u32string str5{ U"hello"s };
The s suffix may also be used on raw string literals:

C++

u32string str6{ UR"(She said "hello.")"s };

std::string literals are defined in the namespace std::literals::string_literals in


the <string> header file. Because std::literals::string_literals , and std::literals
are both declared as inline namespaces, std::literals::string_literals is
automatically treated as if it belonged directly in namespace std .

Size of string literals


For ANSI char* strings and other single-byte encodings (but not UTF-8), the size (in
bytes) of a string literal is the number of characters plus 1 for the terminating null
character. For all other string types, the size isn't strictly related to the number of
characters. UTF-8 uses up to four char elements to encode some code units, and
char16_t or wchar_t encoded as UTF-16 may use two elements (for a total of four

bytes) to encode a single code unit. This example shows the size of a wide string literal in
bytes:

C++

const wchar_t* str = L"Hello!";


const size_t byteSize = (wcslen(str) + 1) * sizeof(wchar_t);

Notice that strlen() and wcslen() don't include the size of the terminating null
character, whose size is equal to the element size of the string type: one byte on a char*
or char8_t* string, two bytes on wchar_t* or char16_t* strings, and four bytes on
char32_t* strings.

In versions of Visual Studio before Visual Studio 2022 version 17.0, the maximum length
of a string literal is 65,535 bytes. This limit applies to both narrow string literals and wide
string literals. In Visual Studio 2022 version 17.0 and later, this restriction is lifted and
string length is limited by available resources.

Modifying string literals


Because string literals (not including std::string literals) are constants, trying to modify
them—for example, str[2] = 'A' —causes a compiler error.
Microsoft-specific
In Microsoft C++, you can use a string literal to initialize a pointer to non-const char or
wchar_t . This non-const initialization is allowed in C99 code, but is deprecated in C++98

and removed in C++11. An attempt to modify the string causes an access violation, as in
this example:

C++

wchar_t* str = L"hello";


str[2] = L'a'; // run-time error: access violation

You can cause the compiler to emit an error when a string literal is converted to a non-
const character pointer when you set the /Zc:strictStrings (Disable string literal type
conversion) compiler option. We recommend it for standards-conformant portable
code. It's also a good practice to use the auto keyword to declare string literal-
initialized pointers, because it resolves to the correct (const) type. For example, this code
example catches an attempt to write to a string literal at compile time:

C++

auto str = L"hello";


str[2] = L'a'; // C3892: you cannot assign to a variable that is const.

In some cases, identical string literals may be pooled to save space in the executable file.
In string-literal pooling, the compiler causes all references to a particular string literal to
point to the same location in memory, instead of having each reference point to a
separate instance of the string literal. To enable string pooling, use the /GF compiler
option.

The Microsoft-specific section ends here.

Concatenating adjacent string literals


Adjacent wide or narrow string literals are concatenated. This declaration:

C++

char str[] = "12" "34";

is identical to this declaration:

C++
char atr[] = "1234";

and to this declaration:

C++

char atr[] = "12\


34";

Using embedded hexadecimal escape codes to specify string literals can cause
unexpected results. The following example seeks to create a string literal that contains
the ASCII 5 character, followed by the characters f, i, v, and e:

C++

"\x05five"

The actual result is a hexadecimal 5F, which is the ASCII code for an underscore,
followed by the characters i, v, and e. To get the correct result, you can use one of these
escape sequences:

C++

"\005five" // Use octal literal.


"\x05" "five" // Use string splicing.

std::string literals (and the related std::u8string , std::u16string , and

std::u32string ) can be concatenated with the + operator that's defined for basic_string
types. They can also be concatenated in the same way as adjacent string literals. In both
cases, the string encoding and the suffix must match:

C++

auto x1 = "hello" " " " world"; // OK


auto x2 = U"hello" " " L"world"; // C2308: disagree on prefix
auto x3 = u8"hello" " "s u8"world"z; // C3688, disagree on suffixes

String literals with universal character names


Native (non-raw) string literals may use universal character names to represent any
character, as long as the universal character name can be encoded as one or more
characters in the string type. For example, a universal character name representing an
extended character can't be encoded in a narrow string using the ANSI code page, but it
can be encoded in narrow strings in some multi-byte code pages, or in UTF-8 strings, or
in a wide string. In C++11, Unicode support is extended by the char16_t* and
char32_t* string types, and C++20 extends it to the char8_t type:

C++

// ASCII smiling face


const char* s1 = ":-)";

// UTF-16 (on Windows) encoded WINKING FACE (U+1F609)


const wchar_t* s2 = L"😉 = \U0001F609 is ;-)";

// UTF-8 encoded SMILING FACE WITH HALO (U+1F607)


const char* s3a = u8"😇 = \U0001F607 is O:-)"; // Before C++20
const char8_t* s3b = u8"😇 = \U0001F607 is O:-)"; // C++20

// UTF-16 encoded SMILING FACE WITH OPEN MOUTH (U+1F603)


const char16_t* s4 = u"😃 = \U0001F603 is :-D";

// UTF-32 encoded SMILING FACE WITH SUNGLASSES (U+1F60E)


const char32_t* s5 = U"😎 = \U0001F60E is B-)";

See also
Character sets
Numeric, Boolean, and pointer literals
User-defined literals
User-defined literals
Article • 08/03/2021 • 6 minutes to read

There are six major categories of literals in C++: integer, character, floating-point, string,
boolean, and pointer. Starting in C++ 11, you can define your own literals based on
these categories, to provide syntactic shortcuts for common idioms and increase type
safety. For example, let's say you have a Distance class. You could define a literal for
kilometers and another one for miles, and encourage the user to be explicit about the
units of measure by writing: auto d = 42.0_km or auto d = 42.0_mi . There's no
performance advantage or disadvantage to user-defined literals; they're primarily for
convenience or for compile-time type deduction. The Standard Library has user-defined
literals for std::string , for std::complex , and for units in time and duration operations
in the <chrono> header:

C++

Distance d = 36.0_mi + 42.0_km; // Custom UDL (see below)


std::string str = "hello"s + "World"s; // Standard Library <string> UDL
complex<double> num =
(2.0 + 3.01i) * (5.0 + 4.3i); // Standard Library <complex> UDL
auto duration = 15ms + 42h; // Standard Library <chrono> UDLs

User-defined literal operator signatures


You implement a user-defined literal by defining an operator"" at namespace scope
with one of the following forms:

C++

ReturnType operator "" _a(unsigned long long int); // Literal operator for
user-defined INTEGRAL literal
ReturnType operator "" _b(long double); // Literal operator for
user-defined FLOATING literal
ReturnType operator "" _c(char); // Literal operator for
user-defined CHARACTER literal
ReturnType operator "" _d(wchar_t); // Literal operator for
user-defined CHARACTER literal
ReturnType operator "" _e(char16_t); // Literal operator for
user-defined CHARACTER literal
ReturnType operator "" _f(char32_t); // Literal operator for
user-defined CHARACTER literal
ReturnType operator "" _g(const char*, size_t); // Literal operator for
user-defined STRING literal
ReturnType operator "" _h(const wchar_t*, size_t); // Literal operator for
user-defined STRING literal
ReturnType operator "" _i(const char16_t*, size_t); // Literal operator for
user-defined STRING literal
ReturnType operator "" _g(const char32_t*, size_t); // Literal operator for
user-defined STRING literal
ReturnType operator "" _r(const char*); // Raw literal operator
template<char...> ReturnType operator "" _t(); // Literal operator
template

The operator names in the previous example are placeholders for whatever name you
provide; however, the leading underscore is required. (Only the Standard Library is
allowed to define literals without the underscore.) The return type is where you
customize the conversion or other operations done by the literal. Also, any of these
operators can be defined as constexpr .

Cooked literals
In source code, any literal, whether user-defined or not, is essentially a sequence of
alphanumeric characters, such as 101 , or 54.7 , or "hello" or true . The compiler
interprets the sequence as an integer, float, const char* string, and so on. A user-defined
literal that accepts as input whatever type the compiler assigned to the literal value is
informally known as a cooked literal. All the operators above except _r and _t are
cooked literals. For example, a literal 42.0_km would bind to an operator named _km
that had a signature similar to _b and the literal 42_km would bind to an operator with a
signature similar to _a.

The following example shows how user-defined literals can encourage callers to be
explicit about their input. To construct a Distance , the user must explicitly specify
kilometers or miles by using the appropriate user-defined literal. You can achieve the
same result in other ways, but user-defined literals are less verbose than the alternatives.

C++

// UDL_Distance.cpp

#include <iostream>
#include <string>

struct Distance
{
private:
explicit Distance(long double val) : kilometers(val)
{}

friend Distance operator"" _km(long double val);


friend Distance operator"" _mi(long double val);
long double kilometers{ 0 };
public:
const static long double km_per_mile;
long double get_kilometers() { return kilometers; }

Distance operator+(Distance other)


{
return Distance(get_kilometers() + other.get_kilometers());
}
};

const long double Distance::km_per_mile = 1.609344L;

Distance operator"" _km(long double val)


{
return Distance(val);
}

Distance operator"" _mi(long double val)


{
return Distance(val * Distance::km_per_mile);
}

int main()
{
// Must have a decimal point to bind to the operator we defined!
Distance d{ 402.0_km }; // construct using kilometers
std::cout << "Kilometers in d: " << d.get_kilometers() << std::endl; //
402

Distance d2{ 402.0_mi }; // construct using miles


std::cout << "Kilometers in d2: " << d2.get_kilometers() << std::endl;
//646.956

// add distances constructed with different units


Distance d3 = 36.0_mi + 42.0_km;
std::cout << "d3 value = " << d3.get_kilometers() << std::endl; //
99.9364

// Distance d4(90.0); // error constructor not accessible

std::string s;
std::getline(std::cin, s);
return 0;
}

The literal number must use a decimal. Otherwise, the number would be interpreted as
an integer, and the type wouldn't be compatible with the operator. For floating point
input, the type must be long double , and for integral types it must be long long .

Raw literals
In a raw user-defined literal, the operator that you define accepts the literal as a
sequence of char values. It's up to you to interpret that sequence as a number or string
or other type. In the list of operators shown earlier in this page, _r and _t can be used
to define raw literals:

C++

ReturnType operator "" _r(const char*); // Raw literal operator


template<char...> ReturnType operator "" _t(); // Literal operator
template

You can use raw literals to provide a custom interpretation of an input sequence that's
different than the compiler's normal behavior. For example, you could define a literal
that converts the sequence 4.75987 into a custom Decimal type instead of an IEEE 754
floating point type. Raw literals, like cooked literals, can also be used for compile-time
validation of input sequences.

Example: Limitations of raw literals


The raw literal operator and literal operator template only work for integral and floating-
point user-defined literals, as shown by the following example:

C++

#include <cstddef>
#include <cstdio>

// Literal operator for user-defined INTEGRAL literal


void operator "" _dump(unsigned long long int lit)
{
printf("operator \"\" _dump(unsigned long long int) : ===>%llu<===\n",
lit);
};

// Literal operator for user-defined FLOATING literal


void operator "" _dump(long double lit)
{
printf("operator \"\" _dump(long double) : ===>%Lf<===\n",
lit);
};

// Literal operator for user-defined CHARACTER literal


void operator "" _dump(char lit)
{
printf("operator \"\" _dump(char) : ===>%c<===\n",
lit);
};
void operator "" _dump(wchar_t lit)
{
printf("operator \"\" _dump(wchar_t) : ===>%d<===\n",
lit);
};

void operator "" _dump(char16_t lit)


{
printf("operator \"\" _dump(char16_t) : ===>%d<===\n",
lit);
};

void operator "" _dump(char32_t lit)


{
printf("operator \"\" _dump(char32_t) : ===>%d<===\n",
lit);
};

// Literal operator for user-defined STRING literal


void operator "" _dump(const char* lit, size_t)
{
printf("operator \"\" _dump(const char*, size_t): ===>%s<===\n",
lit);
};

void operator "" _dump(const wchar_t* lit, size_t)


{
printf("operator \"\" _dump(const wchar_t*, size_t): ===>%ls<===\n",
lit);
};

void operator "" _dump(const char16_t* lit, size_t)


{
printf("operator \"\" _dump(const char16_t*, size_t):\n"
);
};

void operator "" _dump(const char32_t* lit, size_t)


{
printf("operator \"\" _dump(const char32_t*, size_t):\n"
);
};

// Raw literal operator


void operator "" _dump_raw(const char* lit)
{
printf("operator \"\" _dump_raw(const char*) : ===>%s<===\n",
lit);
};

template<char...> void operator "" _dump_template(); // Literal


operator template

int main(int argc, const char* argv[])


{
42_dump;
3.1415926_dump;
3.14e+25_dump;
'A'_dump;
L'B'_dump;
u'C'_dump;
U'D'_dump;
"Hello World"_dump;
L"Wide String"_dump;
u8"UTF-8 String"_dump;
u"UTF-16 String"_dump;
U"UTF-32 String"_dump;
42_dump_raw;
3.1415926_dump_raw;
3.14e+25_dump_raw;

// There is no raw literal operator or literal operator template support


on these types:
// 'A'_dump_raw;
// L'B'_dump_raw;
// u'C'_dump_raw;
// U'D'_dump_raw;
// "Hello World"_dump_raw;
// L"Wide String"_dump_raw;
// u8"UTF-8 String"_dump_raw;
// u"UTF-16 String"_dump_raw;
// U"UTF-32 String"_dump_raw;
}

Output

operator "" _dump(unsigned long long int) : ===>42<===


operator "" _dump(long double) : ===>3.141593<===
operator "" _dump(long double) :
===>31399999999999998506827776.000000<===
operator "" _dump(char) : ===>A<===
operator "" _dump(wchar_t) : ===>66<===
operator "" _dump(char16_t) : ===>67<===
operator "" _dump(char32_t) : ===>68<===
operator "" _dump(const char*, size_t): ===>Hello World<===
operator "" _dump(const wchar_t*, size_t): ===>Wide String<===
operator "" _dump(const char*, size_t): ===>UTF-8 String<===
operator "" _dump(const char16_t*, size_t):
operator "" _dump(const char32_t*, size_t):
operator "" _dump_raw(const char*) : ===>42<===
operator "" _dump_raw(const char*) : ===>3.1415926<===
operator "" _dump_raw(const char*) : ===>3.14e+25<===
Basic Concepts (C++)
Article • 08/03/2021 • 2 minutes to read

This section explains concepts that are critical to understanding C++. C programmers
will be familiar with many of these concepts, but there are some subtle differences that
can cause unexpected program results. The following topics are included:

C++ type system


Scope
Translation units and linkage
main function and command-line arguments
Program termination
Lvalues and rvalues
Temporary objects
Alignment
Trivial, standard-layout and POD types

See also
C++ Language Reference
C++ type system
Article • 11/07/2022 • 13 minutes to read

The concept of type is important in C++. Every variable, function argument, and function
return value must have a type in order to be compiled. Also, all expressions (including
literal values) are implicitly given a type by the compiler before they're evaluated. Some
examples of types include built-in types such as int to store integer values, double to
store floating-point values, or Standard Library types such as class std::basic_string to
store text. You can create your own type by defining a class or struct . The type
specifies the amount of memory that's allocated for the variable (or expression result).
The type also specifies the kinds of values that may be stored, how the compiler
interprets the bit patterns in those values, and the operations you can perform on them.
This article contains an informal overview of the major features of the C++ type system.

Terminology
Scalar type: A type that holds a single value of a defined range. Scalars include
arithmetic types (integral or floating-point values), enumeration type members, pointer
types, pointer-to-member types, and std::nullptr_t . Fundamental types are typically
scalar types.

Compound type: A type that isn't a scalar type. Compound types include array types,
function types, class (or struct) types, union types, enumerations, references, and
pointers to non-static class members.

Variable: The symbolic name of a quantity of data. The name can be used to access the
data it refers to throughout the scope of the code where it's defined. In C++, variable is
often used to refer to instances of scalar data types, whereas instances of other types
are typically called objects.

Object: For simplicity and consistency, this article uses the term object to refer to any
instance of a class or structure. When it's used in the general sense, it includes all types,
even scalar variables.

POD type (plain old data): This informal category of data types in C++ refers to types
that are scalar (see the Fundamental types section) or are POD classes. A POD class has
no static data members that aren't also PODs, and has no user-defined constructors,
user-defined destructors, or user-defined assignment operators. Also, a POD class has
no virtual functions, no base class, and no private or protected non-static data members.
POD types are often used for external data interchange, for example with a module
written in the C language (which has POD types only).

Specifying variable and function types


C++ is both a strongly typed language and a statically typed language; every object has
a type and that type never changes. When you declare a variable in your code, you must
either specify its type explicitly, or use the auto keyword to instruct the compiler to
deduce the type from the initializer. When you declare a function in your code, you must
specify the type of its return value and of each argument. Use the return value type
void if no value is returned by the function. The exception is when you're using function
templates, which allow for arguments of arbitrary types.

After you first declare a variable, you can't change its type at some later point. However,
you can copy the variable's value or a function's return value into another variable of a
different type. Such operations are called type conversions, which are sometimes
necessary but are also potential sources of data loss or incorrectness.

When you declare a variable of POD type, we strongly recommend you initialize it,
which means to give it an initial value. Until you initialize a variable, it has a "garbage"
value that consists of whatever bits happened to be in that memory location previously.
It's an important aspect of C++ to remember, especially if you're coming from another
language that handles initialization for you. When you declare a variable of non-POD
class type, the constructor handles initialization.

The following example shows some simple variable declarations with some descriptions
for each. The example also shows how the compiler uses type information to allow or
disallow certain subsequent operations on the variable.

C++

int result = 0; // Declare and initialize an integer.


double coefficient = 10.8; // Declare and initialize a floating
// point value.
auto name = "Lady G."; // Declare a variable and let compiler
// deduce the type.
auto address; // error. Compiler cannot deduce a type
// without an intializing value.
age = 12; // error. Variable declaration must
// specify a type or use auto!
result = "Kenny G."; // error. Can't assign text to an int.
string result = "zero"; // error. Can't redefine a variable with
// new type.
int maxValue; // Not recommended! maxValue contains
// garbage bits until it is initialized.
Fundamental (built-in) types
Unlike some languages, C++ has no universal base type from which all other types are
derived. The language includes many fundamental types, also known as built-in types.
These types include numeric types such as int , double , long , bool , plus the char and
wchar_t types for ASCII and UNICODE characters, respectively. Most integral
fundamental types (except bool , double , wchar_t , and related types) all have unsigned
versions, which modify the range of values that the variable can store. For example, an
int , which stores a 32-bit signed integer, can represent a value from -2,147,483,648 to

2,147,483,647. An unsigned int , which is also stored as 32 bits, can store a value from 0
to 4,294,967,295. The total number of possible values in each case is the same; only the
range is different.

The compiler recognizes these built-in types, and it has built-in rules that govern what
operations you can perform on them, and how they can be converted to other
fundamental types. For a complete list of built-in types and their size and numeric limits,
see Built-in types.

The following illustration shows the relative sizes of the built-in types in the Microsoft
C++ implementation:

The following table lists the most frequently used fundamental types, and their sizes in
the Microsoft C++ implementation:
Type Size Comment

int 4 The default choice for integral values.


bytes

double 8 The default choice for floating point values.


bytes

bool 1 Represents values that can be either true or false.


byte

char 1 Use for ASCII characters in older C-style strings or std::string objects that will
byte never have to be converted to UNICODE.

wchar_t 2 Represents "wide" character values that may be encoded in UNICODE format
bytes (UTF-16 on Windows, other operating systems may differ). wchar_t is the
character type that's used in strings of type std::wstring .

unsigned 1 C++ has no built-in byte type. Use unsigned char to represent a byte value.
char byte

unsigned 4 Default choice for bit flags.


int bytes

long 8 Represents a much larger range of integer values.


long bytes

Other C++ implementations may use different sizes for certain numeric types. For more
information on the sizes and size relationships that the C++ standard requires, see Built-
in types.

The void type


The void type is a special type; you can't declare a variable of type void , but you can
declare a variable of type void * (pointer to void ), which is sometimes necessary when
allocating raw (untyped) memory. However, pointers to void aren't type-safe and their
use is discouraged in modern C++. In a function declaration, a void return value means
that the function doesn't return a value; using it as a return type is a common and
acceptable use of void . While the C language required functions that have zero
parameters to declare void in the parameter list, for example, fn(void) , this practice is
discouraged in modern C++; a parameterless function should be declared fn() . For
more information, see Type conversions and type safety.

const type qualifier


Any built-in or user-defined type may be qualified by the const keyword. Additionally,
member functions may be const -qualified and even const -overloaded. The value of a
const type can't be modified after it's initialized.

C++

const double PI = 3.1415;


PI = .75; //Error. Cannot modify const variable.

The const qualifier is used extensively in function and variable declarations and "const
correctness" is an important concept in C++; essentially it means to use const to
guarantee, at compile time, that values aren't modified unintentionally. For more
information, see const.

A const type is distinct from its non- const version; for example, const int is a distinct
type from int . You can use the C++ const_cast operator on those rare occasions when
you must remove const-ness from a variable. For more information, see Type
conversions and type safety.

String types
Strictly speaking, the C++ language has no built-in string type; char and wchar_t store
single characters - you must declare an array of these types to approximate a string,
adding a terminating null value (for example, ASCII '\0' ) to the array element one past
the last valid character (also called a C-style string). C-style strings required much more
code to be written or the use of external string utility library functions. But in modern
C++, we have the Standard Library types std::string (for 8-bit char -type character
strings) or std::wstring (for 16-bit wchar_t -type character strings). These C++
Standard Library containers can be thought of as native string types because they're
part of the standard libraries that are included in any conformant C++ build
environment. Use the #include <string> directive to make these types available in your
program. (If you're using MFC or ATL, the CString class is also available, but isn't part of
the C++ standard.) The use of null-terminated character arrays (the C-style strings
previously mentioned) is discouraged in modern C++.

User-defined types
When you define a class , struct , union , or enum , that construct is used in the rest of
your code as if it were a fundamental type. It has a known size in memory, and certain
rules about how it can be used apply to it for compile-time checking and, at runtime, for
the life of your program. The primary differences between the fundamental built-in
types and user-defined types are as follows:

The compiler has no built-in knowledge of a user-defined type. It learns of the type
when it first encounters the definition during the compilation process.

You specify what operations can be performed on your type, and how it can be
converted to other types, by defining (through overloading) the appropriate
operators, either as class members or non-member functions. For more
information, see Function overloading

Pointer types
As in the earliest versions of the C language, C++ continues to let you declare a variable
of a pointer type by using the special declarator * (asterisk). A pointer type stores the
address of the location in memory where the actual data value is stored. In modern
C++, these pointer types are referred to as raw pointers, and they're accessed in your
code through special operators: * (asterisk) or -> (dash with greater-than, often called
arrow). This memory access operation is called dereferencing. Which operator you use
depends on whether you're dereferencing a pointer to a scalar, or a pointer to a
member in an object.

Working with pointer types has long been one of the most challenging and confusing
aspects of C and C++ program development. This section outlines some facts and
practices to help use raw pointers if you want to. However, in modern C++, it's no
longer required (or recommended) to use raw pointers for object ownership at all, due
to the evolution of the smart pointer (discussed more at the end of this section). It's still
useful and safe to use raw pointers for observing objects. However, if you must use
them for object ownership, you should do so with caution and with careful
consideration of how the objects owned by them are created and destroyed.

The first thing that you should know is that a raw pointer variable declaration only
allocates enough memory to store an address: the memory location that the pointer
refers to when it's dereferenced. The pointer declaration doesn't allocate the memory
needed to store the data value. (That memory is also called the backing store.) In other
words, by declaring a raw pointer variable, you're creating a memory address variable,
not an actual data variable. If you dereference a pointer variable before you've made
sure that it contains a valid address for a backing store, it causes undefined behavior
(usually a fatal error) in your program. The following example demonstrates this kind of
error:

C++
int* pNumber; // Declare a pointer-to-int variable.
*pNumber = 10; // error. Although this may compile, it is
// a serious error. We are dereferencing an
// uninitialized pointer variable with no
// allocated memory to point to.

The example dereferences a pointer type without having any memory allocated to store
the actual integer data or a valid memory address assigned to it. The following code
corrects these errors:

C++

int number = 10; // Declare and initialize a local integer


// variable for data backing store.
int* pNumber = &number; // Declare and initialize a local integer
// pointer variable to a valid memory
// address to that backing store.
...
*pNumber = 41; // Dereference and store a new value in
// the memory pointed to by
// pNumber, the integer variable called
// "number". Note "number" was changed, not
// "pNumber".

The corrected code example uses local stack memory to create the backing store that
pNumber points to. We use a fundamental type for simplicity. In practice, the backing

stores for pointers are most often user-defined types that are dynamically allocated in
an area of memory called the heap (or free store) by using a new keyword expression (in
C-style programming, the older malloc() C runtime library function was used). Once
allocated, these variables are normally referred to as objects, especially if they're based
on a class definition. Memory that is allocated with new must be deleted by a
corresponding delete statement (or, if you used the malloc() function to allocate it, the
C runtime function free() ).

However, it's easy to forget to delete a dynamically allocated object- especially in


complex code, which causes a resource bug called a memory leak. For this reason, the
use of raw pointers is discouraged in modern C++. It's almost always better to wrap a
raw pointer in a smart pointer, which automatically releases the memory when its
destructor is invoked. (That is, when the code goes out of scope for the smart pointer.)
By using smart pointers, you virtually eliminate a whole class of bugs in your C++
programs. In the following example, assume MyClass is a user-defined type that has a
public method DoSomeWork();

C++
void someFunction() {
unique_ptr<MyClass> pMc(new MyClass);
pMc->DoSomeWork();
}
// No memory leak. Out-of-scope automatically calls the destructor
// for the unique_ptr, freeing the resource.

For more information about smart pointers, see Smart pointers.

For more information about pointer conversions, see Type conversions and type safety.

For more information about pointers in general, see Pointers.

Windows data types


In classic Win32 programming for C and C++, most functions use Windows-specific
typedefs and #define macros (defined in windef.h ) to specify the types of parameters
and return values. These Windows data types are mostly special names (aliases) given to
C/C++ built-in types. For a complete list of these typedefs and preprocessor definitions,
see Windows Data Types. Some of these typedefs, such as HRESULT and LCID , are useful
and descriptive. Others, such as INT , have no special meaning and are just aliases for
fundamental C++ types. Other Windows data types have names that are retained from
the days of C programming and 16-bit processors, and have no purpose or meaning on
modern hardware or operating systems. There are also special data types associated
with the Windows Runtime Library, listed as Windows Runtime base data types. In
modern C++, the general guideline is to prefer the C++ fundamental types unless the
Windows type communicates some extra meaning about how the value is to be
interpreted.

More information
For more information about the C++ type system, see the following articles.

Value types
Describes value types along with issues relating to their use.

Type conversions and type safety


Describes common type conversion issues and shows how to avoid them.

See also
Welcome back to C++
C++ language reference
C++ Standard Library
Scope (C++)
Article • 11/11/2021 • 4 minutes to read

When you declare a program element such as a class, function, or variable, its name can
only be "seen" and used in certain parts of your program. The context in which a name
is visible is called its scope. For example, if you declare a variable x within a function, x
is only visible within that function body. It has local scope. You may have other variables
by the same name in your program; as long as they are in different scopes, they do not
violate the One Definition Rule and no error is raised.

For automatic non-static variables, scope also determines when they are created and
destroyed in program memory.

There are six kinds of scope:

Global scope A global name is one that is declared outside of any class, function,
or namespace. However, in C++ even these names exist with an implicit global
namespace. The scope of global names extends from the point of declaration to
the end of the file in which they are declared. For global names, visibility is also
governed by the rules of linkage which determine whether the name is visible in
other files in the program.

Namespace scope A name that is declared within a namespace, outside of any


class or enum definition or function block, is visible from its point of declaration to
the end of the namespace. A namespace may be defined in multiple blocks across
different files.

Local scope A name declared within a function or lambda, including the parameter
names, have local scope. They are often referred to as "locals". They are only visible
from their point of declaration to the end of the function or lambda body. Local
scope is a kind of block scope, which is discussed later in this article.

Class scope Names of class members have class scope, which extends throughout
the class definition regardless of the point of declaration. Class member
accessibility is further controlled by the public , private , and protected keywords.
Public or protected members can be accessed only by using the member-selection
operators (. or ->) or pointer-to-member operators (.* or ->*).

Statement scope Names declared in a for , if , while , or switch statement are


visible until the end of the statement block.
Function scope A label has function scope, which means it is visible throughout a
function body even before its point of declaration. Function scope makes it
possible to write statements like goto cleanup before the cleanup label is
declared.

Hiding Names
You can hide a name by declaring it in an enclosed block. In the following figure, i is
redeclared within the inner block, thereby hiding the variable associated with i in the
outer block scope.

Block scope and name hiding

The output from the program shown in the figure is:

C++

i = 0
i = 7
j = 9
i = 0

7 Note

The argument szWhat is considered to be in the scope of the function. Therefore, it


is treated as if it had been declared in the outermost block of the function.

Hiding class names


You can hide class names by declaring a function, object or variable, or enumerator in
the same scope. However, the class name can still be accessed when prefixed by the
keyword class .

C++

// hiding_class_names.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

// Declare class Account at global scope.


class Account
{
public:
Account( double InitialBalance )
{ balance = InitialBalance; }
double GetBalance()
{ return balance; }
private:
double balance;
};

double Account = 15.37; // Hides class name Account

int main()
{
class Account Checking( Account ); // Qualifies Account as
// class name

cout << "Opening account with a balance of: "


<< Checking.GetBalance() << "\n";
}
//Output: Opening account with a balance of: 15.37

7 Note

Any place the class name ( Account ) is called for, the keyword class must be used to
differentiate it from the global-scoped variable Account. This rule does not apply
when the class name occurs on the left side of the scope-resolution operator (::).
Names on the left side of the scope-resolution operator are always considered class
names.

The following example demonstrates how to declare a pointer to an object of type


Account using the class keyword:

C++

class Account *Checking = new class Account( Account );


The Account in the initializer (in parentheses) in the preceding statement has global
scope; it is of type double .

7 Note

The reuse of identifier names as shown in this example is considered poor


programming style.

For information about declaration and initialization of class objects, see Classes,
Structures, and Unions. For information about using the new and delete free-store
operators, see new and delete operators.

Hiding names with global scope


You can hide names with global scope by explicitly declaring the same name in block
scope. However, global-scope names can be accessed using the scope-resolution
operator ( :: ).

C++

#include <iostream>

int i = 7; // i has global scope, outside all blocks


using namespace std;

int main( int argc, char *argv[] ) {


int i = 5; // i has block scope, hides i at global scope
cout << "Block-scoped i has the value: " << i << "\n";
cout << "Global-scoped i has the value: " << ::i << "\n";
}

Output

Block-scoped i has the value: 5


Global-scoped i has the value: 7

See also
Basic Concepts
Header files (C++)
Article • 08/03/2021 • 4 minutes to read

The names of program elements such as variables, functions, classes, and so on must be
declared before they can be used. For example, you can't just write x = 42 without first
declaring 'x'.

C++

int x; // declaration
x = 42; // use x

The declaration tells the compiler whether the element is an int , a double , a function, a
class or some other thing. Furthermore, each name must be declared (directly or

indirectly) in every .cpp file in which it is used. When you compile a program, each .cpp
file is compiled independently into a compilation unit. The compiler has no knowledge
of what names are declared in other compilation units. That means that if you define a
class or function or global variable, you must provide a declaration of that thing in each
additional .cpp file that uses it. Each declaration of that thing must be exactly identical in
all files. A slight inconsistency will cause errors, or unintended behavior, when the linker
attempts to merge all the compilation units into a single program.

To minimize the potential for errors, C++ has adopted the convention of using header
files to contain declarations. You make the declarations in a header file, then use the
#include directive in every .cpp file or other header file that requires that declaration.
The #include directive inserts a copy of the header file directly into the .cpp file prior to
compilation.

7 Note

In Visual Studio 2019, the C++20 modules feature is introduced as an improvement


and eventual replacement for header files. For more information, see Overview of
modules in C++.

Example
The following example shows a common way to declare a class and then use it in a
different source file. We'll start with the header file, my_class.h . It contains a class
definition, but note that the definition is incomplete; the member function do_something
is not defined:

C++

// my_class.h
namespace N
{
class my_class
{
public:
void do_something();
};

Next, create an implementation file (typically with a .cpp or similar extension). We'll call
the file my_class.cpp and provide a definition for the member declaration. We add an
#include directive for "my_class.h" file in order to have the my_class declaration inserted

at this point in the .cpp file, and we include <iostream> to pull in the declaration for
std::cout . Note that quotes are used for header files in the same directory as the

source file, and angle brackets are used for standard library headers. Also, many
standard library headers do not have .h or any other file extension.

In the implementation file, we can optionally use a using statement to avoid having to
qualify every mention of "my_class" or "cout" with "N::" or "std::". Don't put using
statements in your header files!

C++

// my_class.cpp
#include "my_class.h" // header in local directory
#include <iostream> // header in standard library

using namespace N;
using namespace std;

void my_class::do_something()
{
cout << "Doing something!" << endl;
}

Now we can use my_class in another .cpp file. We #include the header file so that the
compiler pulls in the declaration. All the compiler needs to know is that my_class is a
class that has a public member function called do_something() .
C++

// my_program.cpp
#include "my_class.h"

using namespace N;

int main()
{
my_class mc;
mc.do_something();
return 0;
}

After the compiler finishes compiling each .cpp file into .obj files, it passes the .obj files
to the linker. When the linker merges the object files it finds exactly one definition for
my_class; it is in the .obj file produced for my_class.cpp, and the build succeeds.

Include guards
Typically, header files have an include guard or a #pragma once directive to ensure that
they are not inserted multiple times into a single .cpp file.

C++

// my_class.h
#ifndef MY_CLASS_H // include guard
#define MY_CLASS_H

namespace N
{
class my_class
{
public:
void do_something();
};
}

#endif /* MY_CLASS_H */

What to put in a header file


Because a header file might potentially be included by multiple files, it cannot contain
definitions that might produce multiple definitions of the same name. The following are
not allowed, or are considered very bad practice:
built-in type definitions at namespace or global scope
non-inline function definitions
non-const variable definitions
aggregate definitions
unnamed namespaces
using directives

Use of the using directive will not necessarily cause an error, but can potentially cause a
problem because it brings the namespace into scope in every .cpp file that directly or
indirectly includes that header.

Sample header file


The following example shows the various kinds of declarations and definitions that are
allowed in a header file:

C++

// sample.h
#pragma once
#include <vector> // #include directive
#include <string>

namespace N // namespace declaration


{
inline namespace P
{
//...
}

enum class colors : short { red, blue, purple, azure };

const double PI = 3.14; // const and constexpr definitions


constexpr int MeaningOfLife{ 42 };
constexpr int get_meaning()
{
static_assert(MeaningOfLife == 42, "unexpected!"); // static_assert
return MeaningOfLife;
}
using vstr = std::vector<int>; // type alias
extern double d; // extern variable

#define LOG // macro definition

#ifdef LOG // conditional compilation directive


void print_to_log();
#endif

class my_class // regular class definition,


{ // but no non-inline function definitions

friend class other_class;


public:
void do_something(); // definition in my_class.cpp
inline void put_value(int i) { vals.push_back(i); } // inline OK

private:
vstr vals;
int i;
};

struct RGB
{
short r{ 0 }; // member initialization
short g{ 0 };
short b{ 0 };
};

template <typename T> // template definition


class value_store
{
public:
value_store<T>() = default;
void write_value(T val)
{
//... function definition OK in template
}
private:
std::vector<T> vals;
};

template <typename T> // template declaration


class value_widget;
}
Translation units and linkage
Article • 04/07/2022 • 3 minutes to read

In a C++ program, a symbol, for example a variable or function name, can be declared
any number of times within its scope. However, it can only be defined once. This rule is
the "One Definition Rule" (ODR). A declaration introduces (or reintroduces) a name into
the program, along with enough information to later associate the name with a
definition. A definition introduces a name and provides all the information needed to
create it. If the name represents a variable, a definition explicitly creates storage and
initializes it. A function definition consists of the signature plus the function body. A class
definition consists of the class name followed by a block that lists all the class members.
(The bodies of member functions may optionally be defined separately in another file.)

The following example shows some declarations:

C++

int i;
int f(int x);
class C;

The following example shows some definitions:

C++

int i{42};
int f(int x){ return x * i; }
class C {
public:
void DoSomething();
};

A program consists of one or more translation units. A translation unit consists of an


implementation file and all the headers that it includes directly or indirectly.
Implementation files typically have a file extension of .cpp or .cxx . Header files
typically have an extension of .h or .hpp . Each translation unit is compiled
independently by the compiler. After the compilation is complete, the linker merges the
compiled translation units into a single program. Violations of the ODR rule typically
show up as linker errors. Linker errors occur when the same name is defined in more
than one translation unit.

In general, the best way to make a variable visible across multiple files is to declare it in
a header file. Then add an #include directive in every .cpp file that requires the
declaration. By adding include guards around the header contents, you ensure that the
names a header declares are only declared once for each translation unit. Define the
name in only one implementation file.

In C++20, modules are introduced as an improved alternative to header files.

In some cases, it may be necessary to declare a global variable or class in a .cpp file. In
those cases, you need a way to tell the compiler and linker what kind of linkage the
name has. The type of linkage specifies whether the name of the object is visible only in
one file, or in all files. The concept of linkage applies only to global names. The concept
of linkage doesn't apply to names that are declared within a scope. A scope is specified
by a set of enclosing braces such as in function or class definitions.

External vs. internal linkage


A free function is a function that is defined at global or namespace scope. Non-const
global variables and free functions by default have external linkage; they're visible from
any translation unit in the program. No other global object can have that name. A
symbol with internal linkage or no linkage is visible only within the translation unit in
which it's declared. When a name has internal linkage, the same name may exist in
another translation unit. Variables declared within class definitions or function bodies
have no linkage.

You can force a global name to have internal linkage by explicitly declaring it as static .
This keyword limits its visibility to the same translation unit in which it's declared. In this
context, static means something different than when applied to local variables.

The following objects have internal linkage by default:

const objects

constexpr objects
typedef objects

static objects in namespace scope

To give a const object external linkage, declare it as extern and assign it a value:

C++

extern const int value = 42;

For more information, see extern.


See also
Basic concepts
main function and command-line
arguments
Article • 02/08/2022 • 8 minutes to read

All C++ programs must have a main function. If you try to compile a C++ program
without a main function, the compiler raises an error. (Dynamic-link libraries and static
libraries don't have a main function.) The main function is where your source code
begins execution, but before a program enters the main function, all static class
members without explicit initializers are set to zero. In Microsoft C++, global static
objects are also initialized before entry to main . Several restrictions apply to the main
function that don't apply to any other C++ functions. The main function:

Can't be overloaded (see Function overloading).


Can't be declared as inline .
Can't be declared as static .
Can't have its address taken.
Can't be called from your program.

The main function signature


The main function doesn't have a declaration, because it's built into the language. If it
did, the declaration syntax for main would look like this:

C++

int main();
int main(int argc, char *argv[]);

If no return value is specified in main , the compiler supplies a return value of zero.

Standard command-line arguments


The arguments for main allow convenient command-line parsing of arguments. The
types for argc and argv are defined by the language. The names argc and argv are
traditional, but you can name them whatever you like.

The argument definitions are as follows:


argc

An integer that contains the count of arguments that follow in argv. The argc parameter
is always greater than or equal to 1.

argv
An array of null-terminated strings representing command-line arguments entered by
the user of the program. By convention, argv[0] is the command with which the
program is invoked. argv[1] is the first command-line argument. The last argument
from the command line is argv[argc - 1] , and argv[argc] is always NULL.

For information on how to suppress command-line processing, see Customize C++


command-line processing.

7 Note

By convention, argv[0] is the filename of the program. However, on Windows it's


possible to spawn a process by using CreateProcess. If you use both the first and
second arguments ( lpApplicationName and lpCommandLine ), argv[0] may not be
the executable name. You can use GetModuleFileName to retrieve the executable
name, and its fully-qualified path.

Microsoft-specific extensions
The following sections describe Microsoft-specific behavior.

The wmain function and _tmain macro


If you design your source code to use Unicode wide characters, you can use the
Microsoft-specific wmain entry point, which is the wide-character version of main . Here's
the effective declaration syntax for wmain :

C++

int wmain();
int wmain(int argc, wchar_t *argv[]);

You can also use the Microsoft-specific _tmain , which is a preprocessor macro defined
in tchar.h . _tmain resolves to main unless _UNICODE is defined. In that case, _tmain
resolves to wmain . The _tmain macro and other macros that begin with _t are useful for
code that must build separate versions for both narrow and wide character sets. For
more information, see Using generic-text mappings.

Returning void from main


As a Microsoft extension, the main and wmain functions can be declared as returning
void (no return value). This extension is also available in some other compilers, but its
use isn't recommended. It's available for symmetry when main doesn't return a value.

If you declare main or wmain as returning void , you can't return an exit code to the
parent process or the operating system by using a return statement. To return an exit
code when main or wmain is declared as void , you must use the exit function.

The envp command-line argument


The main or wmain signatures allow an optional Microsoft-specific extension for access
to environment variables. This extension is also common in other compilers for Windows
and UNIX systems. The name envp is traditional, but you can name the environment
parameter whatever you like. Here are the effective declarations for the argument lists
that include the environment parameter:

C++

int main(int argc, char* argv[], char* envp[]);


int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);

envp

The optional envp parameter is an array of strings representing the variables set in the
user's environment. This array is terminated by a NULL entry. It can be declared as an
array of pointers to char ( char *envp[] ) or as a pointer to pointers to char ( char
**envp ). If your program uses wmain instead of main , use the wchar_t data type instead
of char .

The environment block passed to main and wmain is a "frozen" copy of the current
environment. If you later change the environment by making a call to putenv or
_wputenv , the current environment (as returned by getenv or _wgetenv and the

_environ or _wenviron variable) will change, but the block pointed to by envp won't
change. For more information on how to suppress environment processing, see
Customize C++ command-line processing. The envp argument is compatible with the
C89 standard, but not with C++ standards.
Example arguments to main
The following example shows how to use the argc , argv , and envp arguments to main :

C++

// argument_definitions.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>

using namespace std;


int main( int argc, char *argv[], char *envp[] )
{
bool numberLines = false; // Default is no line numbers.

// If /n is passed to the .exe, display numbered listing


// of environment variables.
if ( (argc == 2) && _stricmp( argv[1], "/n" ) == 0 )
numberLines = true;

// Walk through list of strings until a NULL is encountered.


for ( int i = 0; envp[i] != NULL; ++i )
{
if ( numberLines )
cout << i << ": "; // Prefix with numbers if /n specified
cout << envp[i] << "\n";
}
}

Parsing C++ command-line arguments


The command line parsing rules used by Microsoft C/C++ code are Microsoft-specific.
The runtime startup code uses these rules when interpreting arguments given on the
operating system command line:

Arguments are delimited by white space, which is either a space or a tab.

The first argument ( argv[0] ) is treated specially. It represents the program name.
Because it must be a valid pathname, parts surrounded by double quote marks ( " )
are allowed. The double quote marks aren't included in the argv[0] output. The
parts surrounded by double quote marks prevent interpretation of a space or tab
character as the end of the argument. The later rules in this list don't apply.

A string surrounded by double quote marks is interpreted as a single argument,


which may contain white-space characters. A quoted string can be embedded in
an argument. The caret ( ^ ) isn't recognized as an escape character or delimiter.
Within a quoted string, a pair of double quote marks is interpreted as a single
escaped double quote mark. If the command line ends before a closing double
quote mark is found, then all the characters read so far are output as the last
argument.

A double quote mark preceded by a backslash ( \" ) is interpreted as a literal


double quote mark ( " ).

Backslashes are interpreted literally, unless they immediately precede a double


quote mark.

If an even number of backslashes is followed by a double quote mark, then one


backslash ( \ ) is placed in the argv array for every pair of backslashes ( \\ ), and the
double quote mark ( " ) is interpreted as a string delimiter.

If an odd number of backslashes is followed by a double quote mark, then one


backslash ( \ ) is placed in the argv array for every pair of backslashes ( \\ ). The
double quote mark is interpreted as an escape sequence by the remaining
backslash, causing a literal double quote mark ( " ) to be placed in argv .

Example of command-line argument parsing


The following program demonstrates how command-line arguments are passed:

C++

// command_line_arguments.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;


int main( int argc, // Number of strings in array argv
char *argv[], // Array of command-line argument strings
char *envp[] ) // Array of environment variable strings
{
int count;

// Display each command-line argument.


cout << "\nCommand-line arguments:\n";
for( count = 0; count < argc; count++ )
cout << " argv[" << count << "] "
<< argv[count] << "\n";
}

Results of parsing command lines


The following table shows example input and expected output, demonstrating the rules
in the preceding list.

Command-line input argv[1] argv[2] argv[3]

"abc" d e abc d e

a\\b d"e f"g h a\\b de fg h

a\\\"b c d a\"b c d

a\\\\"b c" d e a\\b c d e

a"b"" c d ab" c d

Wildcard expansion
The Microsoft compiler optionally allows you to use wildcard characters, the question
mark ( ? ) and asterisk ( * ), to specify filename and path arguments on the command line.

Command-line arguments are handled by an internal routine in the runtime startup


code, which by default doesn't expand wildcards into separate strings in the argv string
array. You can enable wildcard expansion by including the setargv.obj file
( wsetargv.obj file for wmain ) in your /link compiler options or your LINK command
line.

For more information on runtime startup linker options, see Link options.

Customize C++ command-line processing


If your program doesn't take command-line arguments, you can suppress the
command-line processing routine to save a small amount of space. To suppress its use,
include the noarg.obj file (for both main and wmain ) in your /link compiler options or
your LINK command line.

Similarly, if you never access the environment table through the envp argument, you
can suppress the internal environment-processing routine. To suppress its use, include
the noenv.obj file (for both main and wmain ) in your /link compiler options or your
LINK command line.

Your program might make calls to the spawn or exec family of routines in the C runtime
library. If it does, you shouldn't suppress the environment-processing routine, since it's
used to pass an environment from the parent process to the child process.
See also
Basic concepts
C++ program termination
Article • 07/07/2022 • 3 minutes to read

In C++, you can exit a program in these ways:

Call the exit function.


Call the abort function.
Execute a return statement from main .

exit function
The exit function, declared in <stdlib.h>, terminates a C++ program. The value supplied
as an argument to exit is returned to the operating system as the program's return
code or exit code. By convention, a return code of zero means that the program
completed successfully. You can use the constants EXIT_FAILURE and EXIT_SUCCESS , also
defined in <stdlib.h>, to indicate success or failure of your program.

abort function
The abort function, also declared in the standard include file <stdlib.h>, terminates a
C++ program. The difference between exit and abort is that exit allows the C++
runtime termination processing to take place (global object destructors get called).
abort terminates the program immediately. The abort function bypasses the normal
destruction process for initialized global static objects. It also bypasses any special
processing that was specified using the atexit function.

Microsoft-specific: For Windows compatibility reasons, the Microsoft implementation of


abort may allow DLL termination code to run in certain circumstances. For more

information, see abort.

atexit function
Use the atexit function to specify actions that execute before the program terminates.
No global static objects initialized before the call to atexit are destroyed before
execution of the exit-processing function.

return statement in main


The return statement allows you to specify a return value from main . A return
statement in main first acts like any other return statement. Any automatic variables are
destroyed. Then, main invokes exit with the return value as a parameter. Consider the
following example:

C++

// return_statement.cpp
#include <stdlib.h>
struct S
{
int value;
};
int main()
{
S s{ 3 };

exit( 3 );
// or
return 3;
}

The exit and return statements in the preceding example have similar behavior. Both
terminate the program and return a value of 3 to the operating system. The difference is
that exit doesn't destroy the automatic variable s , while the return statement does.

Normally, C++ requires that functions that have return types other than void return a
value. The main function is an exception; it can end without a return statement. In that
case, it returns an implementation-specific value to the invoking process. (By default,
MSVC returns 0.)

Destruction of thread and static objects


When you call exit directly (or when it's called after a return statement from main ),
thread objects associated with the current thread are destroyed. Next, static objects are
destroyed in the reverse order of their initialization (after calls to functions specified to
atexit , if any). The following example shows how such initialization and cleanup works.

Example
In the following example, the static objects sd1 and sd2 are created and initialized
before entry to main . After this program terminates using the return statement, first
sd2 is destroyed and then sd1 . The destructor for the ShowData class closes the files

associated with these static objects.

C++

// using_exit_or_return1.cpp
#include <stdio.h>
class ShowData {
public:
// Constructor opens a file.
ShowData( const char *szDev ) {
errno_t err;
err = fopen_s(&OutputDev, szDev, "w" );
}

// Destructor closes the file.


~ShowData() { fclose( OutputDev ); }

// Disp function shows a string on the output device.


void Disp( char *szData ) {
fputs( szData, OutputDev );
}
private:
FILE *OutputDev;
};

// Define a static object of type ShowData. The output device


// selected is "CON" -- the standard output device.
ShowData sd1 = "CON";

// Define another static object of type ShowData. The output


// is directed to a file called "HELLO.DAT"
ShowData sd2 = "hello.dat";

int main() {
sd1.Disp( "hello to default device\n" );
sd2.Disp( "hello to file hello.dat\n" );
}

Another way to write this code is to declare the ShowData objects with block scope,
which implicitly destroys them when they go out of scope:

C++

int main() {
ShowData sd1( "CON" ), sd2( "hello.dat" );

sd1.Disp( "hello to default device\n" );


sd2.Disp( "hello to file hello.dat\n" );
}
See also
main function and command-line arguments
Lvalues and Rvalues (C++)
Article • 04/04/2023 • 2 minutes to read

Every C++ expression has a type, and belongs to a value category. The value categories
are the basis for rules that compilers must follow when creating, copying, and moving
temporary objects during expression evaluation.

The C++17 standard defines expression value categories as follows:

A glvalue is an expression whose evaluation determines the identity of an object,


bit-field, or function.
A prvalue is an expression whose evaluation initializes an object or a bit-field, or
computes the value of the operand of an operator, as specified by the context in
which it appears.
An xvalue is a glvalue that denotes an object or bit-field whose resources can be
reused (usually because it is near the end of its lifetime). Example: Certain kinds of
expressions involving rvalue references (8.3.2) yield xvalues, such as a call to a
function whose return type is an rvalue reference or a cast to an rvalue reference
type.
An lvalue is a glvalue that isn't an xvalue.
An rvalue is a prvalue or an xvalue.

The following diagram illustrates the relationships between the categories:

An lvalue has an address that your program can access. Examples of lvalue expressions
include variable names, including const variables, array elements, function calls that
return an lvalue reference, bit-fields, unions, and class members.

A prvalue expression has no address that is accessible by your program. Examples of


prvalue expressions include literals, function calls that return a nonreference type, and
temporary objects that are created during expression evaluation but accessible only by
the compiler.

An xvalue expression has an address that no longer accessible by your program but can
be used to initialize an rvalue reference, which provides access to the expression.
Examples include function calls that return an rvalue reference, and the array subscript,
member and pointer to member expressions where the array or object is an rvalue
reference.

Example
The following example demonstrates several correct and incorrect usages of lvalues and
rvalues:

C++

// lvalues_and_rvalues2.cpp
int main()
{
int i, j, *p;

// Correct usage: the variable i is an lvalue and the literal 7 is a


prvalue.
i = 7;

// Incorrect usage: The left operand must be an lvalue (C2106).`j * 4`


is a prvalue.
7 = i; // C2106
j * 4 = 7; // C2106

// Correct usage: the dereferenced pointer is an lvalue.


*p = i;

// Correct usage: the conditional operator returns an lvalue.


((i < 3) ? i : j) = 7;

// Incorrect usage: the constant ci is a non-modifiable lvalue (C3892).


const int ci = 7;
ci = 9; // C3892
}

7 Note

The examples in this topic illustrate correct and incorrect usage when operators are
not overloaded. By overloading operators, you can make an expression such as j *
4 an lvalue.

The terms lvalue and rvalue are often used when you refer to object references. For
more information about references, see Lvalue Reference Declarator: & and Rvalue
Reference Declarator: &&.
See also
Basic Concepts
Lvalue Reference Declarator: &
Rvalue Reference Declarator: &&
Temporary objects
Article • 03/22/2022 • 2 minutes to read

A temporary object is an unnamed object created by the compiler to store a temporary


value.

Remarks
In some cases, it's necessary for the compiler to create temporary objects. These
temporary objects can be created for the following reasons:

To initialize a const reference with an initializer of a type different from the


underlying type of the reference being initialized.

To store the return value of a function that returns a user-defined type (UDT).
These temporaries are created only if your program doesn't copy the return value
to an object. For example:

C++

UDT Func1(); // Declare a function that returns a user-defined


// type.

...

Func1(); // Call Func1, but discard return value.


// A temporary object is created to store the return
// value.

Because the return value isn't copied to another object, a temporary object is
created. A more common case where temporaries are created is during the
evaluation of an expression where overloaded operator functions must be called.
These overloaded operator functions return a user-defined type that often isn't
copied to another object.

Consider the expression ComplexResult = Complex1 + Complex2 + Complex3 . The


expression Complex1 + Complex2 is evaluated, and the result is stored in a
temporary object. Next, the expression temporary + Complex3 is evaluated, and the
result is copied to ComplexResult (assuming the assignment operator isn't
overloaded).
To store the result of a cast to a user-defined type. When an object of a given type
is explicitly converted to a user-defined type, that new object is constructed as a
temporary object.

Temporary objects have a lifetime, defined by their point of creation and the point at
which they're destroyed. Any expression that creates more than one temporary object
eventually destroys them in reverse order of creation.

When destruction of a temporary occurs depends on how it's used:

Temporaries used for initializing const references:


If an initializer isn't an l-value of the same type as the reference being initialized, a
temporary of the underlying object type is created. It's initialized by the
initialization expression. This temporary object is destroyed immediately after the
reference object to which it's bound is destroyed. As this destruction can happen
well after the expression that created the temporary, it's sometimes referred to as
lifetime extension.

Temporaries created as an effect of expression evaluation:


All temporaries that don't fit in the first category, and that are created as an effect
of expression evaluation, are destroyed at the end of the expression statement
(that is, at the semicolon), or at the end of the controlling expressions for for , if ,
while , do , and switch statements.

See also
Herb Sutter's blog on References, simply
Alignment
Article • 08/03/2021 • 4 minutes to read

One of the low-level features of C++ is the ability to specify the precise alignment of
objects in memory to take maximum advantage of a specific hardware architecture. By
default, the compiler aligns class and struct members on their size value: bool and char
on 1-byte boundaries, short on 2-byte boundaries, int , long , and float on 4-byte
boundaries, and long long , double , and long double on 8-byte boundaries.

In most scenarios, you never have to be concerned with alignment because the default
alignment is already optimal. In some cases, however, you can achieve significant
performance improvements, or memory savings, by specifying a custom alignment for
your data structures. Before Visual Studio 2015 you could use the Microsoft-specific
keywords __alignof and __declspec(align) to specify an alignment greater than the
default. Starting in Visual Studio 2015 you should use the C++11 standard keywords
alignof and alignas for maximum code portability. The new keywords behave in the

same way under the hood as the Microsoft-specific extensions. The documentation for
those extensions also applies to the new keywords. For more information, see alignof
Operator and align. The C++ standard doesn't specify packing behavior for alignment
on boundaries smaller than the compiler default for the target platform, so you still
need to use the Microsoft #pragma pack in that case.

Use the aligned_storage class for memory allocation of data structures with custom
alignments. The aligned_union class is for specifying alignment for unions with non-
trivial constructors or destructors.

Alignment and memory addresses


Alignment is a property of a memory address, expressed as the numeric address modulo
a power of 2. For example, the address 0x0001103F modulo 4 is 3. That address is said
to be aligned to 4n+3, where 4 indicates the chosen power of 2. The alignment of an
address depends on the chosen power of 2. The same address modulo 8 is 7. An
address is said to be aligned to X if its alignment is Xn+0.

CPUs execute instructions that operate on data stored in memory. The data are
identified by their addresses in memory. A single datum also has a size. We call a datum
naturally aligned if its address is aligned to its size. It's called misaligned otherwise. For
example, an 8-byte floating-point datum is naturally aligned if the address used to
identify it has an 8-byte alignment.
Compiler handling of data alignment
Compilers attempt to make data allocations in a way that prevents data misalignment.

For simple data types, the compiler assigns addresses that are multiples of the size in
bytes of the data type. For example, the compiler assigns addresses to variables of type
long that are multiples of 4, setting the bottom 2 bits of the address to zero.

The compiler also pads structures in a way that naturally aligns each element of the
structure. Consider the structure struct x_ in the following code example:

C++

struct x_
{
char a; // 1 byte
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
} bar[3];

The compiler pads this structure to enforce alignment naturally.

The following code example shows how the compiler places the padded structure in
memory:

C++

// Shows the actual memory layout


struct x_
{
char a; // 1 byte
char _pad0[3]; // padding to put 'b' on 4-byte boundary
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
char _pad1[1]; // padding to make sizeof(x_) multiple of 4
} bar[3];

Both declarations return sizeof(struct x_) as 12 bytes.

The second declaration includes two padding elements:

1. char _pad0[3] to align the int b member on a 4-byte boundary.

2. char _pad1[1] to align the array elements of the structure struct _x bar[3]; on a
four-byte boundary.
The padding aligns the elements of bar[3] in a way that allows natural access.

The following code example shows the bar[3] array layout:

Output

adr offset element


------ -------
0x0000 char a; // bar[0]
0x0001 char pad0[3];
0x0004 int b;
0x0008 short c;
0x000a char d;
0x000b char _pad1[1];

0x000c char a; // bar[1]


0x000d char _pad0[3];
0x0010 int b;
0x0014 short c;
0x0016 char d;
0x0017 char _pad1[1];

0x0018 char a; // bar[2]


0x0019 char _pad0[3];
0x001c int b;
0x0020 short c;
0x0022 char d;
0x0023 char _pad1[1];

alignof and alignas


The alignas type specifier is a portable, C++ standard way to specify custom alignment
of variables and user defined types. The alignof operator is likewise a standard,
portable way to obtain the alignment of a specified type or variable.

Example
You can use alignas on a class, struct or union, or on individual members. When
multiple alignas specifiers are encountered, the compiler will choose the strictest one,
(the one with the largest value).

C++

// alignas_alignof.cpp
// compile with: cl /EHsc alignas_alignof.cpp
#include <iostream>
struct alignas(16) Bar
{
int i; // 4 bytes
int n; // 4 bytes
alignas(4) char arr[3];
short s; // 2 bytes
};

int main()
{
std::cout << alignof(Bar) << std::endl; // output: 16
}

See also
Data structure alignment
Trivial, standard-layout, POD, and literal
types
Article • 01/05/2022 • 5 minutes to read

The term layout refers to how the members of an object of class, struct or union type
are arranged in memory. In some cases, the layout is well-defined by the language
specification. But when a class or struct contains certain C++ language features such as
virtual base classes, virtual functions, members with different access control, then the
compiler is free to choose a layout. That layout may vary depending on what
optimizations are being performed and in many cases the object might not even occupy
a contiguous area of memory. For example, if a class has virtual functions, all the
instances of that class might share a single virtual function table. Such types are very
useful, but they also have limitations. Because the layout is undefined they cannot be
passed to programs written in other languages, such as C, and because they might be
non-contiguous they cannot be reliably copied with fast low-level functions such as
memcopy , or serialized over a network.

To enable compilers as well as C++ programs and metaprograms to reason about the
suitability of any given type for operations that depend on a particular memory layout,
C++14 introduced three categories of simple classes and structs: trivial, standard-layout,
and POD or Plain Old Data. The Standard Library has the function templates
is_trivial<T> , is_standard_layout<T> and is_pod<T> that determine whether a given

type belongs to a given category.

Trivial types
When a class or struct in C++ has compiler-provided or explicitly defaulted special
member functions, then it is a trivial type. It occupies a contiguous memory area. It can
have members with different access specifiers. In C++, the compiler is free to choose
how to order members in this situation. Therefore, you can memcopy such objects but
you cannot reliably consume them from a C program. A trivial type T can be copied into
an array of char or unsigned char, and safely copied back into a T variable. Note that
because of alignment requirements, there might be padding bytes between type
members.

Trivial types have a trivial default constructor, trivial copy constructor, trivial copy
assignment operator and trivial destructor. In each case, trivial means the
constructor/operator/destructor is not user-provided and belongs to a class that has
no virtual functions or virtual base classes,

no base classes with a corresponding non-trivial constructor/operator/destructor

no data members of class type with a corresponding non-trivial


constructor/operator/destructor

The following examples show trivial types. In Trivial2, the presence of the Trivial2(int
a, int b) constructor requires that you provide a default constructor. For the type to

qualify as trivial, you must explicitly default that constructor.

C++

struct Trivial
{
int i;
private:
int j;
};

struct Trivial2
{
int i;
Trivial2(int a, int b) : i(a), j(b) {}
Trivial2() = default;
private:
int j; // Different access control
};

Standard layout types


When a class or struct does not contain certain C++ language features such as virtual
functions which are not found in the C language, and all members have the same access
control, it is a standard-layout type. It is memcopy-able and the layout is sufficiently
defined that it can be consumed by C programs. Standard-layout types can have user-
defined special member functions. In addition, standard layout types have these
characteristics:

no virtual functions or virtual base classes

all non-static data members have the same access control

all non-static members of class type are standard-layout

any base classes are standard-layout

has no base classes of the same type as the first non-static data member.
meets one of these conditions:

no non-static data member in the most-derived class and no more than one
base class with non-static data members, or

has no base classes with non-static data members

The following code shows one example of a standard-layout type:

C++

struct SL
{
// All members have same access:
int i;
int j;
SL(int a, int b) : i(a), j(b) {} // User-defined constructor OK
};

The last two requirements can perhaps be better illustrated with code. In the next
example, even though Base is standard-layout, Derived is not standard layout because
both it (the most derived class) and Base have non-static data members:

C++

struct Base
{
int i;
int j;
};

// std::is_standard_layout<Derived> == false!
struct Derived : public Base
{
int x;
int y;
};

In this example Derived is standard-layout because Base has no non-static data


members:

C++

struct Base
{
void Foo() {}
};

// std::is_standard_layout<Derived> == true
struct Derived : public Base
{
int x;
int y;
};

Derived would also be standard-layout if Base had the data members and Derived had
only member functions.

POD types
When a class or struct is both trivial and standard-layout, it is a POD (Plain Old Data)
type. The memory layout of POD types is therefore contiguous and each member has a
higher address than the member that was declared before it, so that byte for byte
copies and binary I/O can be performed on these types. Scalar types such as int are also
POD types. POD types that are classes can have only POD types as non-static data
members.

Example
The following example shows the distinctions between trivial, standard-layout, and POD
types:

C++

#include <type_traits>
#include <iostream>

using namespace std;

struct B
{
protected:
virtual void Foo() {}
};

// Neither trivial nor standard-layout


struct A : B
{
int a;
int b;
void Foo() override {} // Virtual function
};

// Trivial but not standard-layout


struct C
{
int a;
private:
int b; // Different access control
};

// Standard-layout but not trivial


struct D
{
int a;
int b;
D() {} //User-defined constructor
};

struct POD
{
int a;
int b;
};

int main()
{
cout << boolalpha;
cout << "A is trivial is " << is_trivial<A>() << endl; // false
cout << "A is standard-layout is " << is_standard_layout<A>() << endl;
// false

cout << "C is trivial is " << is_trivial<C>() << endl; // true
cout << "C is standard-layout is " << is_standard_layout<C>() << endl;
// false

cout << "D is trivial is " << is_trivial<D>() << endl; // false
cout << "D is standard-layout is " << is_standard_layout<D>() << endl; //
true

cout << "POD is trivial is " << is_trivial<POD>() << endl; // true
cout << "POD is standard-layout is " << is_standard_layout<POD>() <<
endl; // true

return 0;
}

Literal types
A literal type is one whose layout can be determined at compile time. The following are
the literal types:

void
scalar types
references
Arrays of void, scalar types or references
A class that has a trivial destructor, and one or more constexpr constructors that
are not move or copy constructors. Additionally, all its non-static data members
and base classes must be literal types and not volatile.

See also
Basic Concepts
C++ classes as value types
Article • 10/17/2022 • 3 minutes to read

C++ classes are, by default, value types. They can be specified as reference types, which
enable polymorphic behavior to support object-oriented programming. Value types are
sometimes viewed from the perspective of memory and layout control, whereas
reference types are about base classes and virtual functions for polymorphic purposes.
By default, value types are copyable, which means there's always a copy constructor and
a copy assignment operator. For reference types, you make the class non-copyable
(disable the copy constructor and copy assignment operator) and use a virtual
destructor, which supports their intended polymorphism. Value types are also about the
contents, which, when they're copied, always give you two independent values that can
be modified separately. Reference types are about identity - what kind of object is it?
For this reason, "reference types" are also referred to as "polymorphic types".

If you really want a reference-like type (base class, virtual functions), you need to
explicitly disable copying, as shown in the MyRefType class in the following code.

C++

// cl /EHsc /nologo /W4

class MyRefType {
private:
MyRefType & operator=(const MyRefType &);
MyRefType(const MyRefType &);
public:
MyRefType () {}
};

int main()
{
MyRefType Data1, Data2;
// ...
Data1 = Data2;
}

Compiling the above code will result in the following error:

Output

test.cpp(15) : error C2248: 'MyRefType::operator =' : cannot access private


member declared in class 'MyRefType'
meow.cpp(5) : see declaration of 'MyRefType::operator ='
meow.cpp(3) : see declaration of 'MyRefType'
Value types and move efficiency
Copy allocation overhead is avoided due to new copy optimizations. For example, when
you insert a string in the middle of a vector of strings, there's no copy reallocation
overhead, only a move, even if it results in growth of the vector itself. These
optimizations also apply to other operations: for instance, performing an add operation
on two huge objects. How do you enable these value operation optimizations? The
compiler enables them for you implicitly, much like copy constructors can be
automatically generated by the compiler. However, your class has to "opt-in" to move
assignments and move constructors by declaring them in your class definition. Move
uses the double ampersand (&&) rvalue reference in the appropriate member function
declarations and defining move constructor and move assignment methods. You also
need to insert the correct code to "steal the guts" out of the source object.

How do you decide if you need to enable move operations? If you already know you
need to enable copy construction, you probably want to enable move construction, too,
especially if it's cheaper than a deep copy. However, if you know you need move
support, it doesn't necessarily mean you want to enable copy operations. This latter case
would be called a "move-only type". An example already in the standard library is
unique_ptr . As a side note, the old auto_ptr is deprecated, and was replaced by

unique_ptr precisely due to the lack of move semantics support in the previous version
of C++.

By using move semantics, you can return-by-value or insert-in-middle. Move is an


optimization of copy. There's no need for heap allocation as a workaround. Consider the
following pseudocode:

C++

#include <set>
#include <vector>
#include <string>
using namespace std;

//...
set<widget> LoadHugeData() {
set<widget> ret;
// ... load data from disk and populate ret
return ret;
}
//...
widgets = LoadHugeData(); // efficient, no deep copy

vector<string> v = IfIHadAMillionStrings();
v.insert( begin(v)+v.size()/2, "scott" ); // efficient, no deep copy-
shuffle
v.insert( begin(v)+v.size()/2, "Andrei" ); // (just 1M ptr/len assignments)
//...
HugeMatrix operator+(const HugeMatrix& , const HugeMatrix& );
HugeMatrix operator+(const HugeMatrix& , HugeMatrix&&);
HugeMatrix operator+( HugeMatrix&&, const HugeMatrix& );
HugeMatrix operator+( HugeMatrix&&, HugeMatrix&&);
//...
hm5 = hm1+hm2+hm3+hm4+hm5; // efficient, no extra copies

Enabling move for appropriate value types


For a value-like class where move can be cheaper than a deep copy, enable move
construction and move assignment for efficiency. Consider the following pseudocode:

C++

#include <memory>
#include <stdexcept>
using namespace std;
// ...
class my_class {
unique_ptr<BigHugeData> data;
public:
my_class( my_class&& other ) // move construction
: data( move( other.data ) ) { }
my_class& operator=( my_class&& other ) // move assignment
{ data = move( other.data ); return *this; }
// ...
void method() { // check (if appropriate)
if( !data )
throw std::runtime_error("RUNTIME ERROR: Insufficient
resources!");
}
};

If you enable copy construction/assignment, also enable move construction/assignment


if it can be cheaper than a deep copy.

Some non-value types are move-only, such as when you can't clone a resource, only
transfer ownership. Example: unique_ptr .

See also
C++ type system
Welcome back to C++
C++ Language Reference
C++ Standard Library
Type conversions and type safety
Article • 08/03/2021 • 9 minutes to read

This document identifies common type conversion problems and describes how you can
avoid them in your C++ code.

When you write a C++ program, it's important to ensure that it's type-safe. This means
that every variable, function argument, and function return value is storing an
acceptable kind of data, and that operations that involve values of different types "make
sense" and don't cause data loss, incorrect interpretation of bit patterns, or memory
corruption. A program that never explicitly or implicitly converts values from one type to
another is type-safe by definition. However, type conversions, even unsafe conversions,
are sometimes required. For example, you might have to store the result of a floating
point operation in a variable of type int , or you might have to pass the value in an
unsigned int to a function that takes a signed int . Both examples illustrate unsafe
conversions because they may cause data loss or re-interpretation of a value.

When the compiler detects an unsafe conversion, it issues either an error or a warning.
An error stops compilation; a warning allows compilation to continue but indicates a
possible error in the code. However, even if your program compiles without warnings, it
still may contain code that leads to implicit type conversions that produce incorrect
results. Type errors can also be introduced by explicit conversions, or casts, in the code.

Implicit type conversions


When an expression contains operands of different built-in types, and no explicit casts
are present, the compiler uses built-in standard conversions to convert one of the
operands so that the types match. The compiler tries the conversions in a well-defined
sequence until one succeeds. If the selected conversion is a promotion, the compiler
doesn't issue a warning. If the conversion is a narrowing, the compiler issues a warning
about possible data loss. Whether actual data loss occurs depends on the actual values
involved, but we recommend that you treat this warning as an error. If a user-defined
type is involved, then the compiler tries to use the conversions that you have specified
in the class definition. If it can't find an acceptable conversion, the compiler issues an
error and doesn't compile the program. For more information about the rules that
govern the standard conversions, see Standard Conversions. For more information
about user-defined conversions, see User-Defined Conversions (C++/CLI).

Widening conversions (promotion)


In a widening conversion, a value in a smaller variable is assigned to a larger variable
with no loss of data. Because widening conversions are always safe, the compiler
performs them silently and doesn't issue warnings. The following conversions are
widening conversions.

From To

Any signed or unsigned integral type except long long or __int64 double

bool or char Any other built-in type

short or wchar_t int , long , long long

int , long long long

float double

Narrowing conversions (coercion)


The compiler performs narrowing conversions implicitly, but it warns you about
potential data loss. Take these warnings very seriously. If you are certain that no data
loss will occur because the values in the larger variable will always fit in the smaller
variable, then add an explicit cast so that the compiler will no longer issue a warning. If
you aren't sure that the conversion is safe, add to your code some kind of runtime check
to handle possible data loss so that it doesn't cause your program to produce incorrect
results.

Any conversion from a floating point type to an integral type is a narrowing conversion
because the fractional portion of the floating point value is discarded and lost.

The following code example shows some implicit narrowing conversions, and the
warnings that the compiler issues for them.

C++

int i = INT_MAX + 1; //warning C4307:'+':integral constant overflow


wchar_t wch = 'A'; //OK
char c = wch; // warning C4244:'initializing':conversion from 'wchar_t'
// to 'char', possible loss of data
unsigned char c2 = 0xfffe; //warning C4305:'initializing':truncation from
// 'int' to 'unsigned char'
int j = 1.9f; // warning C4244:'initializing':conversion from 'float' to
// 'int', possible loss of data
int k = 7.7; // warning C4244:'initializing':conversion from 'double' to
// 'int', possible loss of data
Signed - unsigned conversions
A signed integral type and its unsigned counterpart are always the same size, but they
differ in how the bit pattern is interpreted for value transformation. The following code
example demonstrates what happens when the same bit pattern is interpreted as a
signed value and as an unsigned value. The bit pattern stored in both num and num2
never changes from what is shown in the earlier illustration.

C++

using namespace std;


unsigned short num = numeric_limits<unsigned short>::max(); // #include
<limits>
short num2 = num;
cout << "unsigned val = " << num << " signed val = " << num2 << endl;
// Prints: "unsigned val = 65535 signed val = -1"

// Go the other way.


num2 = -1;
num = num2;
cout << "unsigned val = " << num << " signed val = " << num2 << endl;
// Prints: "unsigned val = 65535 signed val = -1"

Notice that values are reinterpreted in both directions. If your program produces odd
results in which the sign of the value seems inverted from what you expect, look for
implicit conversions between signed and unsigned integral types. In the following
example, the result of the expression ( 0 - 1) is implicitly converted from int to unsigned
int when it's stored in num . This causes the bit pattern to be reinterpreted.

C++

unsigned int u3 = 0 - 1;
cout << u3 << endl; // prints 4294967295

The compiler doesn't warn about implicit conversions between signed and unsigned
integral types. So, we recommend that you avoid signed-to-unsigned conversions
altogether. If you can't avoid them, then add a runtime check to detect whether the
value being converted is greater than or equal to zero and less than or equal to the
maximum value of the signed type. Values in this range will transfer from signed to
unsigned or from unsigned to signed without being reinterpreted.

Pointer conversions
In many expressions, a C-style array is implicitly converted to a pointer to the first
element in the array, and constant conversions can happen silently. Although this is
convenient, it's also potentially error-prone. For example, the following badly designed
code example seems nonsensical, and yet it will compile and produces a result of 'p'.
First, the "Help" string constant literal is converted to a char* that points to the first
element of the array; that pointer is then incremented by three elements so that it now
points to the last element 'p'.

C++

char* s = "Help" + 3;

Explicit conversions (casts)


By using a cast operation, you can instruct the compiler to convert a value of one type
to another type. The compiler will raise an error in some cases if the two types are
completely unrelated, but in other cases it won't raise an error even if the operation isn't
type-safe. Use casts sparingly because any conversion from one type to another is a
potential source of program error. However, casts are sometimes required, and not all
casts are equally dangerous. One effective use of a cast is when your code performs a
narrowing conversion and you know that the conversion doesn't cause your program to
produce incorrect results. In effect, this tells the compiler that you know what you are
doing and to stop bothering you with warnings about it. Another use is to cast from a
pointer-to-derived class to a pointer-to-base class. Another use is to cast away the
constness of a variable to pass it to a function that requires a non-const argument. Most
of these cast operations involve some risk.

In C-style programming, the same C-style cast operator is used for all kinds of casts.

C++

(int) x; // old-style cast, old-style syntax


int(x); // old-style cast, functional syntax

The C-style cast operator is identical to the call operator () and is therefore
inconspicuous in code and easy to overlook. Both are bad because they're difficult to
recognize at a glance or search for, and they're disparate enough to invoke any
combination of static , const , and reinterpret_cast . Figuring out what an old-style
cast actually does can be difficult and error-prone. For all these reasons, when a cast is
required, we recommend that you use one of the following C++ cast operators, which in
some cases are significantly more type-safe, and which express much more explicitly the
programming intent:

static_cast , for casts that are checked at compile time only. static_cast returns

an error if the compiler detects that you are trying to cast between types that are
completely incompatible. You can also use it to cast between pointer-to-base and
pointer-to-derived, but the compiler can't always tell whether such conversions will
be safe at runtime.

C++

double d = 1.58947;
int i = d; // warning C4244 possible loss of data
int j = static_cast<int>(d); // No warning.
string s = static_cast<string>(d); // Error C2440:cannot convert from
// double to std:string

// No error but not necessarily safe.


Base* b = new Base();
Derived* d2 = static_cast<Derived*>(b);

For more information, see static_cast.

dynamic_cast , for safe, runtime-checked casts of pointer-to-base to pointer-to-


derived. A dynamic_cast is safer than a static_cast for downcasts, but the runtime
check incurs some overhead.

C++

Base* b = new Base();

// Run-time check to determine whether b is actually a Derived*


Derived* d3 = dynamic_cast<Derived*>(b);

// If b was originally a Derived*, then d3 is a valid pointer.


if(d3)
{
// Safe to call Derived method.
cout << d3->DoSomethingMore() << endl;
}
else
{
// Run-time check failed.
cout << "d3 is null" << endl;
}

//Output: d3 is null;
For more information, see dynamic_cast.

const_cast , for casting away the const -ness of a variable, or converting a non-
const variable to be const . Casting away const -ness by using this operator is just

as error-prone as is using a C-style cast, except that with const_cast you are less
likely to perform the cast accidentally. Sometimes you have to cast away the
const -ness of a variable, for example, to pass a const variable to a function that

takes a non- const parameter. The following example shows how to do this.

C++

void Func(double& d) { ... }


void ConstCast()
{
const double pi = 3.14;
Func(const_cast<double&>(pi)); //No error.
}

For more information, see const_cast.

reinterpret_cast , for casts between unrelated types such as a pointer type and an
int .

7 Note

This cast operator isn't used as often as the others, and it's not guaranteed to
be portable to other compilers.

The following example illustrates how reinterpret_cast differs from static_cast .

C++

const char* str = "hello";


int i = static_cast<int>(str);//error C2440: 'static_cast' : cannot
// convert from 'const char *' to 'int'
int j = (int)str; // C-style cast. Did the programmer really intend
// to do this?
int k = reinterpret_cast<int>(str);// Programming intent is clear.
// However, it is not 64-bit safe.

For more information, see reinterpret_cast Operator.

See also
C++ type system
Welcome back to C++
C++ Language Reference
C++ Standard Library
Standard conversions
Article • 11/11/2021 • 12 minutes to read

The C++ language defines conversions between its fundamental types. It also defines
conversions for pointer, reference, and pointer-to-member derived types. These
conversions are called standard conversions.

This section discusses the following standard conversions:

Integral promotions

Integral conversions

Floating conversions

Floating and integral conversions

Arithmetic conversions

Pointer conversions

Reference conversions

Pointer-to-member conversions

7 Note

User-defined types can specify their own conversions. Conversion of user-


defined types is covered in Constructors and Conversions.

The following code causes conversions (in this example, integral promotions):

C++

long long_num1, long_num2;


int int_num;

// int_num promoted to type long prior to assignment.


long_num1 = int_num;

// int_num promoted to type long prior to multiplication.


long_num2 = int_num * long_num2;

The result of a conversion is an l-value only if it produces a reference type. For example,
a user-defined conversion declared as operator int&() returns a reference and is an l-
value. However, a conversion declared as operator int() returns an object and isn't an
l-value.

Integral promotions
Objects of an integral type can be converted to another wider integral type, that is, a
type that can represent a larger set of values. This widening type of conversion is called
integral promotion. With integral promotion, you can use the following types in an
expression wherever another integral type can be used:

Objects, literals, and constants of type char and short int

Enumeration types

int bit fields

Enumerators

C++ promotions are "value-preserving," as the value after the promotion is guaranteed
to be the same as the value before the promotion. In value-preserving promotions,
objects of shorter integral types (such as bit fields or objects of type char ) are
promoted to type int if int can represent the full range of the original type. If int
can't represent the full range of values, then the object is promoted to type unsigned
int . Although this strategy is the same as the one used by Standard C, value-preserving

conversions don't preserve the "signedness" of the object.

Value-preserving promotions and promotions that preserve signedness normally


produce the same results. However, they can produce different results if the promoted
object appears as:

An operand of / , % , /= , %= , < , <= , > , or >=

These operators rely on sign for determining the result. Value-preserving and sign-
preserving promotions produce different results when applied to these operands.

The left operand of >> or >>=

These operators treat signed and unsigned quantities differently in a shift


operation. For signed quantities, a right shift operation propagates the sign bit into
the vacated bit positions, while the vacated bit positions are zero-filled in unsigned
quantities.

An argument to an overloaded function, or the operand of an overloaded


operator, that depends on the signedness of the operand type for argument
matching. For more information about defining overloaded operators, see
Overloaded operators.

Integral conversions
Integral conversions are conversions between integral types. The integral types are char ,
short (or short int ), int , long , and long long . These types may be qualified with

signed or unsigned , and unsigned can be used as shorthand for unsigned int .

Signed to unsigned
Objects of signed integral types can be converted to corresponding unsigned types.
When these conversions occur, the actual bit pattern doesn't change. However, the
interpretation of the data changes. Consider this code:

C++

#include <iostream>

using namespace std;


int main()
{
short i = -3;
unsigned short u;

cout << (u = i) << "\n";


}
// Output: 65533

In the preceding example, a signed short , i , is defined and initialized to a negative


number. The expression (u = i) causes i to be converted to an unsigned short before
the assignment to u .

Unsigned to signed
Objects of unsigned integral types can be converted to corresponding signed types.
However, if the unsigned value is outside the representable range of the signed type,
the result won't have the correct value, as demonstrated in the following example:

C++

#include <iostream>

using namespace std;


int main()
{
short i;
unsigned short u = 65533;

cout << (i = u) << "\n";


}
//Output: -3

In the preceding example, u is an unsigned short integral object that must be


converted to a signed quantity to evaluate the expression (i = u) . Because its value
can't be properly represented in a signed short , the data is misinterpreted as shown.

Floating point conversions


An object of a floating type can be safely converted to a more precise floating type —
that is, the conversion causes no loss of significance. For example, conversions from
float to double or from double to long double are safe, and the value is unchanged.

An object of a floating type can also be converted to a less precise type, if it's in a range
representable by that type. (See Floating Limits for the ranges of floating types.) If the
original value isn't representable precisely, it can be converted to either the next higher
or the next lower representable value. The result is undefined if no such value exists.
Consider the following example:

C++

cout << (float)1E300 << endl;

The maximum value representable by type float is 3.402823466E38 — a much smaller


number than 1E300. Therefore, the number is converted to infinity, and the result is
"inf".

Conversions between integral and floating


point types
Certain expressions can cause objects of floating type to be converted to integral types,
or vice versa. When an object of integral type is converted to a floating type, and the
original value isn't representable exactly, the result is either the next higher or the next
lower representable value.
When an object of floating type is converted to an integral type, the fractional part is
truncated, or rounded toward zero. A number like 1.3 is converted to 1, and -1.3 is
converted to -1. If the truncated value is higher than the highest representable value, or
lower than the lowest representable value, the result is undefined.

Arithmetic conversions
Many binary operators (discussed in Expressions with binary operators) cause
conversions of operands, and yield results the same way. The conversions these
operators cause are called usual arithmetic conversions. Arithmetic conversions of
operands that have different native types are done as shown in the following table.
Typedef types behave according to their underlying native types.

Conditions for type conversion

Conditions Met Conversion

Either operand is of type Other operand is converted to type long double .


long double .

Preceding condition not met Other operand is converted to type double .


and either operand is of type
double .

Preceding conditions not met Other operand is converted to type float .


and either operand is of type
float .

Preceding conditions not met Operands get integral promotions as follows:


(none of the operands are of
floating types). - If either operand is of type unsigned long , the other operand is
converted to type unsigned long .
- If preceding condition not met, and if either operand is of type
long and the other of type unsigned int , both operands are
converted to type unsigned long .
- If the preceding two conditions aren't met, and if either operand
is of type long , the other operand is converted to type long .
- If the preceding three conditions aren't met, and if either
operand is of type unsigned int , the other operand is converted
to type unsigned int .
- If none of the preceding conditions are met, both operands are
converted to type int .

The following code illustrates the conversion rules described in the table:
C++

double dVal;
float fVal;
int iVal;
unsigned long ulVal;

int main() {
// iVal converted to unsigned long
// result of multiplication converted to double
dVal = iVal * ulVal;

// ulVal converted to float


// result of addition converted to double
dVal = ulVal + fVal;
}

The first statement in the preceding example shows multiplication of two integral types,
iVal and ulVal . The condition met is that neither operand is of floating type, and one

operand is of type unsigned int . So, the other operand, iVal , is converted to type
unsigned int . The result is then assigned to dVal . The condition met here is that one

operand is of type double , so the unsigned int result of the multiplication is converted
to type double .

The second statement in the preceding example shows addition of a float and an
integral type: fVal and ulVal . The ulVal variable is converted to type float (third
condition in the table). The result of the addition is converted to type double (second
condition in the table) and assigned to dVal .

Pointer conversions
Pointers can be converted during assignment, initialization, comparison, and other
expressions.

Pointer to classes
There are two cases in which a pointer to a class can be converted to a pointer to a base
class.

The first case is when the specified base class is accessible and the conversion is
unambiguous. For more information about ambiguous base-class references, see
Multiple base classes.
Whether a base class is accessible depends on the kind of inheritance used in derivation.
Consider the inheritance illustrated in the following figure.

Inheritance Graph for Illustration of Base-Class Accessibility

The following table shows the base-class accessibility for the situation illustrated in the
figure.

Type of Function Derivation Conversion from

B* to A* Legal?

External (not class-scoped) function Private No

Protected No

Public Yes

B member function (in B scope) Private Yes

Protected Yes

Public Yes

C member function (in C scope) Private No

Protected Yes

Public Yes

The second case in which a pointer to a class can be converted to a pointer to a base
class is when you use an explicit type conversion. For more information about explicit
type conversions, see Explicit type conversion operator.

The result of such a conversion is a pointer to the subobject, the portion of the object
that is completely described by the base class.

The following code defines two classes, A and B , where B is derived from A . (For more
information on inheritance, see Derived Classes.) It then defines bObject , an object of
type B , and two pointers ( pA and pB ) that point to the object.

C++
// C2039 expected
class A
{
public:
int AComponent;
int AMemberFunc();
};

class B : public A
{
public:
int BComponent;
int BMemberFunc();
};
int main()
{
B bObject;
A *pA = &bObject;
B *pB = &bObject;

pA->AMemberFunc(); // OK in class A
pB->AMemberFunc(); // OK: inherited from class A
pA->BMemberFunc(); // Error: not in class A
}

The pointer pA is of type A * , which can be interpreted as meaning "pointer to an


object of type A ." Members of bObject (such as BComponent and BMemberFunc ) are
unique to type B and are therefore inaccessible through pA . The pA pointer allows
access only to those characteristics (member functions and data) of the object that are
defined in class A .

Pointer to function
A pointer to a function can be converted to type void * , if type void * is large enough
to hold that pointer.

Pointer to void
Pointers to type void can be converted to pointers to any other type, but only with an
explicit type cast (unlike in C). A pointer to any type can be converted implicitly to a
pointer to type void . A pointer to an incomplete object of a type can be converted to a
pointer to void (implicitly) and back (explicitly). The result of such a conversion is equal
to the value of the original pointer. An object is considered incomplete if it's declared,
but there's insufficient information available to determine its size or base class.
A pointer to any object that is not const or volatile can be implicitly converted to a
pointer of type void * .

const and volatile pointers


C++ doesn't supply a standard conversion from a const or volatile type to a type
that's not const or volatile . However, any sort of conversion can be specified using
explicit type casts (including conversions that are unsafe).

7 Note

C++ pointers to members, except pointers to static members, are different from
normal pointers and don't have the same standard conversions. Pointers to static
members are normal pointers and have the same conversions as normal pointers.

null pointer conversions


An integral constant expression that evaluates to zero, or such an expression cast to a
pointer type, is converted to a pointer called the null pointer. This pointer always
compares unequal to a pointer to any valid object or function. An exception is pointers
to based objects, which can have the same offset and still point to different objects.

In C++11, the nullptr type should be preferred to the C-style null pointer.

Pointer expression conversions


Any expression with an array type can be converted to a pointer of the same type. The
result of the conversion is a pointer to the first array element. The following example
demonstrates such a conversion:

C++

char szPath[_MAX_PATH]; // Array of type char.


char *pszPath = szPath; // Equals &szPath[0].

An expression that results in a function returning a particular type is converted to a


pointer to a function returning that type, except when:

The expression is used as an operand to the address-of operator (&).

The expression is used as an operand to the function-call operator.


Reference conversions
A reference to a class can be converted to a reference to a base class in these cases:

The specified base class is accessible.

The conversion is unambiguous. (For more information about ambiguous base-


class references, see Multiple base classes.)

The result of the conversion is a pointer to the subobject that represents the base class.

Pointer to member
Pointers to class members can be converted during assignment, initialization,
comparison, and other expressions. This section describes the following pointer-to-
member conversions:

Pointer to base class member


A pointer to a member of a base class can be converted to a pointer to a member of a
class derived from it, when the following conditions are met:

The inverse conversion, from pointer to derived class to base-class pointer, is


accessible.

The derived class does not inherit virtually from the base class.

When the left operand is a pointer to member, the right operand must be of pointer-to-
member type or be a constant expression that evaluates to 0. This assignment is valid
only in the following cases:

The right operand is a pointer to a member of the same class as the left operand.

The left operand is a pointer to a member of a class derived publicly and


unambiguously from the class of the right operand.

null pointer to member conversions


An integral constant expression that evaluates to zero is converted to a null pointer. This
pointer always compares unequal to a pointer to any valid object or function. An
exception is pointers to based objects, which can have the same offset and still point to
different objects.
The following code illustrates the definition of a pointer to member i in class A . The
pointer, pai , is initialized to 0, which is the null pointer.

C++

class A
{
public:
int i;
};

int A::*pai = 0;

int main()
{
}

See also
C++ language reference
Built-in types (C++)
Article • 08/17/2021 • 5 minutes to read

Built-in types (also called fundamental types) are specified by the C++ language
standard and are built into the compiler. Built-in types aren't defined in any header file.
Built-in types are divided into three main categories: integral, floating-point, and void.
Integral types represent whole numbers. Floating-point types can specify values that
may have fractional parts. Most built-in types are treated as distinct types by the
compiler. However, some types are synonyms, or treated as equivalent types by the
compiler.

Void type
The void type describes an empty set of values. No variable of type void can be
specified. The void type is used primarily to declare functions that return no values or to
declare generic pointers to untyped or arbitrarily typed data. Any expression can be
explicitly converted or cast to type void . However, such expressions are restricted to the
following uses:

An expression statement. (For more information, see Expressions.)

The left operand of the comma operator. (For more information, see Comma
Operator.)

The second or third operand of the conditional operator ( ? : ). (For more


information, see Expressions with the Conditional Operator.)

std::nullptr_t
The keyword nullptr is a null-pointer constant of type std::nullptr_t , which is
convertible to any raw pointer type. For more information, see nullptr.

Boolean type
The bool type can have values true and false. The size of the bool type is
implementation-specific. See Sizes of built-in types for Microsoft-specific
implementation details.
Character types
The char type is a character representation type that efficiently encodes members of
the basic execution character set. The C++ compiler treats variables of type char ,
signed char , and unsigned char as having different types.

Microsoft-specific: Variables of type char are promoted to int as if from type signed
char by default, unless the /J compilation option is used. In this case, they're treated as
type unsigned char and are promoted to int without sign extension.

A variable of type wchar_t is a wide-character or multibyte character type. Use the L


prefix before a character or string literal to specify the wide-character type.

Microsoft-specific: By default, wchar_t is a native type, but you can use /Zc:wchar_t- to
make wchar_t a typedef for unsigned short . The __wchar_t type is a Microsoft-specific
synonym for the native wchar_t type.

The char8_t type is used for UTF-8 character representation. It has the same
representation as unsigned char , but is treated as a distinct type by the compiler. The
char8_t type is new in C++20. Microsoft-specific: use of char8_t requires the

/std:c++20 compiler option or later (such as /std:c++latest ).

The char16_t type is used for UTF-16 character representation. It must be large enough
to represent any UTF-16 code unit. It's treated as a distinct type by the compiler.

The char32_t type is used for UTF-32 character representation. It must be large enough
to represent any UTF-32 code unit. It's treated as a distinct type by the compiler.

Floating-point types
Floating-point types use an IEEE-754 representation to provide an approximation of
fractional values over a wide range of magnitudes. The following table lists the floating-
point types in C++ and the comparative restrictions on floating-point type sizes. These
restrictions are mandated by the C++ standard and are independent of the Microsoft
implementation. The absolute size of built-in floating-point types isn't specified in the
standard.

Type Contents

float Type float is the smallest floating point type in C++.


Type Contents

double Type double is a floating point type that is larger than or equal to type float , but
shorter than or equal to the size of type long double .

long Type long double is a floating point type that is larger than or equal to type double .
double

Microsoft-specific: The representation of long double and double is identical. However,


long double and double are treated as distinct types by the compiler. The Microsoft

C++ compiler uses the 4- and 8-byte IEEE-754 floating-point representations. For more
information, see IEEE floating-point representation.

Integer types
The int type is the default basic integer type. It can represent all of the whole numbers
over an implementation-specific range.

A signed integer representation is one that can hold both positive and negative values.
It's used by default, or when the signed modifier keyword is present. The unsigned
modifier keyword specifies an unsigned representation that can only hold non-negative
values.

A size modifier specifies the width in bits of the integer representation used. The
language supports short , long , and long long modifiers. A short type must be at least
16 bits wide. A long type must be at least 32 bits wide. A long long type must be at
least 64 bits wide. The standard specifies a size relationship between the integral types:

1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long


long)

An implementation must maintain both the minimum size requirements and the size
relationship for each type. However, the actual sizes can and do vary between
implementations. See Sizes of built-in types for Microsoft-specific implementation
details.

The int keyword may be omitted when signed , unsigned , or size modifiers are
specified. The modifiers and int type, if present, may appear in any order. For example,
short unsigned and unsigned int short refer to the same type.

Integer type synonyms


The following groups of types are considered synonyms by the compiler:

short , short int , signed short , signed short int

unsigned short , unsigned short int

int , signed , signed int

unsigned , unsigned int

long , long int , signed long , signed long int

unsigned long , unsigned long int

long long , long long int , signed long long , signed long long int

unsigned long long , unsigned long long int

Microsoft-specific integer types include the specific-width __int8 , __int16 , __int32 ,


and __int64 types. These types may use the signed and unsigned modifiers. The
__int8 data type is synonymous with type char , __int16 is synonymous with type
short , __int32 is synonymous with type int , and __int64 is synonymous with type

long long .

Sizes of built-in types


Most built-in types have implementation-defined sizes. The following table lists the
amount of storage required for built-in types in Microsoft C++. In particular, long is 4
bytes even on 64-bit operating systems.

Type Size

bool , char , char8_t , unsigned char , signed char , __int8 1 byte

char16_t , __int16 , short , unsigned short , wchar_t , __wchar_t 2 bytes

char32_t , float , __int32 , int , unsigned int , long , unsigned long 4 bytes

double , __int64 , long double , long long , unsigned long long 8 bytes

See Data type ranges for a summary of the range of values of each type.

For more information about type conversion, see Standard conversions.


See also
Data type ranges
Data Type Ranges
Article • 08/03/2021 • 2 minutes to read

The Microsoft C++ 32-bit and 64-bit compilers recognize the types in the table later in
this article.

int ( unsigned int )

__int8 ( unsigned __int8 )

__int16 ( unsigned __int16 )

__int32 ( unsigned __int32 )

__int64 ( unsigned __int64 )

short ( unsigned short )

long ( unsigned long )

long long ( unsigned long long )

If its name begins with two underscores ( __ ), a data type is non-standard.

The ranges that are specified in the following table are inclusive-inclusive.

Type Name Bytes Other Names Range of Values

int 4 signed -2,147,483,648 to 2,147,483,647

unsigned 4 unsigned 0 to 4,294,967,295


int

__int8 1 char -128 to 127

unsigned 1 unsigned char 0 to 255


__int8

__int16 2 short , short int , signed -32,768 to 32,767


short int

unsigned 2 unsigned short , unsigned 0 to 65,535


__int16 short int

__int32 4 signed , signed int , int -2,147,483,648 to 2,147,483,647


Type Name Bytes Other Names Range of Values

unsigned 4 unsigned , unsigned int 0 to 4,294,967,295


__int32

__int64 8 long long , signed long -9,223,372,036,854,775,808 to


long 9,223,372,036,854,775,807

unsigned 8 unsigned long long 0 to 18,446,744,073,709,551,615


__int64

bool 1 none false or true

char 1 none -128 to 127 by default

0 to 255 when compiled by using /J

signed char 1 none -128 to 127

unsigned 1 none 0 to 255


char

short 2 short int , signed short -32,768 to 32,767


int

unsigned 2 unsigned short int 0 to 65,535


short

long 4 long int , signed long int -2,147,483,648 to 2,147,483,647

unsigned 4 unsigned long int 0 to 4,294,967,295


long

long long 8 none (but equivalent to -9,223,372,036,854,775,808 to


__int64 ) 9,223,372,036,854,775,807

unsigned 8 none (but equivalent to 0 to 18,446,744,073,709,551,615


long long unsigned __int64 )

enum varies none

float 4 none 3.4E +/- 38 (7 digits)

double 8 none 1.7E +/- 308 (15 digits)

long double same as none Same as double


double

wchar_t 2 __wchar_t 0 to 65,535


Depending on how it's used, a variable of __wchar_t designates either a wide-character
type or multibyte-character type. Use the L prefix before a character or string constant
to designate the wide-character-type constant.

signed and unsigned are modifiers that you can use with any integral type except bool .
Note that char , signed char , and unsigned char are three distinct types for the
purposes of mechanisms like overloading and templates.

The int and unsigned int types have a size of four bytes. However, portable code
should not depend on the size of int because the language standard allows this to be
implementation-specific.

C/C++ in Visual Studio also supports sized integer types. For more information, see
__int8, __int16, __int32, __int64 and Integer Limits.

For more information about the restrictions of the sizes of each type, see Built-in types.

The range of enumerated types varies depending on the language context and specified
compiler flags. For more information, see C Enumeration Declarations and
Enumerations.

See also
Keywords
Built-in types
nullptr
Article • 08/03/2021 • 2 minutes to read

The nullptr keyword specifies a null pointer constant of type std::nullptr_t , which is
convertible to any raw pointer type. Although you can use the keyword nullptr without
including any headers, if your code uses the type std::nullptr_t , then you must define
it by including the header <cstddef> .

7 Note

The nullptr keyword is also defined in C++/CLI for managed code applications
and is not interchangeable with the ISO Standard C++ keyword. If your code might
be compiled by using the /clr compiler option, which targets managed code, then
use __nullptr in any line of code where you must guarantee that the compiler uses
the native C++ interpretation. For more information, see nullptr (C++/CLI and
C++/CX).

Remarks
Avoid using NULL or zero ( 0 ) as a null pointer constant; nullptr is less vulnerable to
misuse and works better in most situations. For example, given func(std::pair<const
char *, double>) , then calling func(std::make_pair(NULL, 3.14)) causes a compiler

error. The macro NULL expands to 0 , so that the call std::make_pair(0, 3.14) returns
std::pair<int, double> , which isn't convertible to the std::pair<const char *, double>

parameter type in func . Calling func(std::make_pair(nullptr, 3.14)) successfully


compiles because std::make_pair(nullptr, 3.14) returns std::pair<std::nullptr_t,
double> , which is convertible to std::pair<const char *, double> .

See also
Keywords
nullptr (C++/CLI and C++/CX)
void (C++)
Article • 12/14/2022 • 2 minutes to read

When used as a function return type, the void keyword specifies that the function
doesn't return a value. When used for a function's parameter list, void specifies that the
function takes no parameters. When used in the declaration of a pointer, void specifies
that the pointer is "universal."

If a pointer's type is void* , the pointer can point to any variable that's not declared with
the const or volatile keyword. A void* pointer can't be dereferenced unless it's cast
to another type. A void* pointer can be converted into any other type of data pointer.

In C++, a void pointer can point to a free function (a function that's not a member of a
class), or to a static member function, but not to a non-static member function.

You can't declare a variable of type void .

As a matter of style, the C++ Core Guidelines recommend you don't use void to specify
an empty formal parameter list. For more information, see C++ Core Guidelines NL.25:
Don't use void as an argument type .

Example
C++

// void.cpp

void return_nothing()
{
// A void function can have a return with no argument,
// or no return statement.
}

void vobject; // C2182


void *pv; // okay
int *pint; int i;
int main()
{
pv = &i;
// Cast is optional in C, required in C++
pint = (int *)pv;
}
See also
Keywords
Built-in types
bool (C++)
Article • 08/17/2021 • 2 minutes to read

This keyword is a built-in type. A variable of this type can have values true and false.
Conditional expressions have the type bool and so have values of type bool . For
example, i != 0 now has true or false depending on the value of i .

Visual Studio 2017 version 15.3 and later (Available with /std:c++17 and later): The
operand of a postfix or prefix increment or decrement operator may not be of type
bool . In other words, given a variable b of type bool , these expressions are no longer
allowed:

C++

b++;
++b;
b--;
--b;

The values true and false have the following relationship:

C++

!false == true
!true == false

In the following statement:

C++

if (condexpr1) statement1;

If condexpr1 is true , statement1 is always executed; if condexpr1 is false , statement1 is


never executed.

When a postfix or prefix ++ operator is applied to a variable of type bool , the variable is
set to true .

Visual Studio 2017 version 15.3 and later: operator++ for bool was removed from the
language and is no longer supported.

The postfix or prefix -- operator can't be applied to a variable of this type.


The bool type participates in default integral promotions. An r-value of type bool can
be converted to an r-value of type int , with false becoming zero and true becoming
one. As a distinct type, bool participates in overload resolution.

See also
Keywords
Built-in types
false (C++)
Article • 08/03/2021 • 2 minutes to read

The keyword is one of the two values for a variable of type bool or a conditional
expression (a conditional expression is now a true Boolean expression). For example, if
i is a variable of type bool , the i = false; statement assigns false to i .

Example
C++

// bool_false.cpp
#include <stdio.h>

int main()
{
bool bb = true;
printf_s("%d\n", bb);
bb = false;
printf_s("%d\n", bb);
}

Output

1
0

See also
Keywords
true (C++)
Article • 08/03/2021 • 2 minutes to read

Syntax

bool-identifier = true ;
bool-expression logical-operator true ;

Remarks
This keyword is one of the two values for a variable of type bool or a conditional
expression (a conditional expression is now a true boolean expression). If i is of type
bool , then the statement i = true; assigns true to i .

Example
C++

// bool_true.cpp
#include <stdio.h>
int main()
{
bool bb = true;
printf_s("%d\n", bb);
bb = false;
printf_s("%d\n", bb);
}

Output

1
0

See also
Keywords
char, wchar_t, char8_t, char16_t, char32_t
Article • 08/17/2021 • 2 minutes to read

The types char , wchar_t , char8_t , char16_t , and char32_t are built-in types that
represent alphanumeric characters, non-alphanumeric glyphs, and non-printing
characters.

Syntax
C++

char ch1{ 'a' }; // or { u8'a' }


wchar_t ch2{ L'a' };
char16_t ch3{ u'a' };
char32_t ch4{ U'a' };

Remarks
The char type was the original character type in C and C++. The char type can be used
to store characters from the ASCII character set or any of the ISO-8859 character sets,
and individual bytes of multi-byte characters such as Shift-JIS or the UTF-8 encoding of
the Unicode character set. In the Microsoft compiler, char is an 8-bit type. It's a distinct
type from both signed char and unsigned char . By default, variables of type char get
promoted to int as if from type signed char unless the /J compiler option is used.
Under /J , they're treated as type unsigned char and get promoted to int without sign
extension.

The type unsigned char is often used to represent a byte, which isn't a built-in type in
C++.

The wchar_t type is an implementation-defined wide character type. In the Microsoft


compiler, it represents a 16-bit wide character used to store Unicode encoded as UTF-
16LE, the native character type on Windows operating systems. The wide character
versions of the Universal C Runtime (UCRT) library functions use wchar_t and its pointer
and array types as parameters and return values, as do the wide character versions of
the native Windows API.

The char8_t , char16_t , and char32_t types represent 8-bit, 16-bit, and 32-bit wide
characters, respectively. ( char8_t is new in C++20 and requires the /std:c++20 or
/std:c++latest compiler option.) Unicode encoded as UTF-8 can be stored in the

char8_t type. Strings of char8_t and char type are referred to as narrow strings, even
when used to encode Unicode or multi-byte characters. Unicode encoded as UTF-16 can
be stored in the char16_t type, and Unicode encoded as UTF-32 can be stored in the
char32_t type. Strings of these types and wchar_t are all referred to as wide strings,

though the term often refers specifically to strings of wchar_t type.

In the C++ standard library, the basic_string type is specialized for both narrow and
wide strings. Use std::string when the characters are of type char , std::u8string
when the characters are of type char8_t , std::u16string when the characters are of
type char16_t , std::u32string when the characters are of type char32_t , and
std::wstring when the characters are of type wchar_t . Other types that represent text,

including std::stringstream and std::cout have specializations for narrow and wide
strings.
__int8, __int16, __int32, __int64
Article • 08/03/2021 • 2 minutes to read

Microsoft-specific

Microsoft C/C++ features support for sized integer types. You can declare 8-, 16-, 32-,
or 64-bit integer variables by using the __intN type specifier, where N is 8, 16, 32, or 64.

The following example declares one variable for each of these types of sized integers:

C++

__int8 nSmall; // Declares 8-bit integer


__int16 nMedium; // Declares 16-bit integer
__int32 nLarge; // Declares 32-bit integer
__int64 nHuge; // Declares 64-bit integer

The types __int8 , __int16 , and __int32 are synonyms for the ANSI types that have the
same size, and are useful for writing portable code that behaves identically across
multiple platforms. The __int8 data type is synonymous with type char , __int16 is
synonymous with type short , and __int32 is synonymous with type int . The __int64
type is synonymous with type long long .

For compatibility with previous versions, _int8 , _int16 , _int32 , and _int64 are
synonyms for __int8 , __int16 , __int32 , and __int64 unless compiler option /Za
(Disable language extensions) is specified.

Example
The following sample shows that an __intN parameter will be promoted to int :

C++

// sized_int_types.cpp

#include <stdio.h>

void func(int i) {
printf_s("%s\n", __FUNCTION__);
}

int main()
{
__int8 i8 = 100;
func(i8); // no void func(__int8 i8) function
// __int8 will be promoted to int
}

Output

func

See also
Keywords
Built-in types
Data Type Ranges
__m64
Article • 08/03/2021 • 2 minutes to read

Microsoft Specific

The __m64 data type is for use with the MMX and 3DNow! intrinsics, and is defined in
<xmmintrin.h>.

C++

// data_types__m64.cpp
#include <xmmintrin.h>
int main()
{
__m64 x;
}

Remarks
You should not access the __m64 fields directly. You can, however, see these types in the
debugger. A variable of type __m64 maps to the MM[0-7] registers.

Variables of type _m64 are automatically aligned on 8-byte boundaries.

The __m64 data type is not supported on x64 processors. Applications that use __m64 as
part of MMX intrinsics must be rewritten to use equivalent SSE and SSE2 intrinsics.

END Microsoft Specific

See also
Keywords
Built-in types
Data Type Ranges
__m128
Article • 08/03/2021 • 2 minutes to read

Microsoft Specific

The __m128 data type, for use with the Streaming SIMD Extensions and Streaming SIMD
Extensions 2 instructions intrinsics, is defined in <xmmintrin.h>.

C++

// data_types__m128.cpp
#include <xmmintrin.h>
int main() {
__m128 x;
}

Remarks
You should not access the __m128 fields directly. You can, however, see these types in
the debugger. A variable of type __m128 maps to the XMM[0-7] registers.

Variables of type __m128 are automatically aligned on 16-byte boundaries.

The __m128 data type is not supported on ARM processors.

END Microsoft Specific

See also
Keywords
Built-in types
Data Type Ranges
__m128d
Article • 08/03/2021 • 2 minutes to read

Microsoft Specific

The __m128d data type, for use with the Streaming SIMD Extensions 2 instructions
intrinsics, is defined in <emmintrin.h>.

C++

// data_types__m128d.cpp
#include <emmintrin.h>
int main() {
__m128d x;
}

Remarks
You should not access the __m128d fields directly. You can, however, see these types in
the debugger. A variable of type __m128 maps to the XMM[0-7] registers.

Variables of type _m128d are automatically aligned on 16-byte boundaries.

The __m128d data type is not supported on ARM processors.

END Microsoft Specific

See also
Keywords
Built-in types
Data Type Ranges
__m128i
Article • 08/03/2021 • 2 minutes to read

Microsoft Specific

The __m128i data type, for use with the Streaming SIMD Extensions 2 (SSE2) instructions
intrinsics, is defined in <emmintrin.h>.

C++

// data_types__m128i.cpp
#include <emmintrin.h>
int main() {
__m128i x;
}

Remarks
You should not access the __m128i fields directly. You can, however, see these types in
the debugger. A variable of type __m128i maps to the XMM[0-7] registers.

Variables of type __m128i are automatically aligned on 16-byte boundaries.

7 Note

Using variables of type __m128i will cause the compiler to generate the SSE2
movdqa instruction. This instruction does not cause a fault on Pentium III processors
but will result in silent failure, with possible side effects caused by whatever
instructions movdqa translates into on Pentium III processors.

The __m128i data type is not supported on ARM processors.

END Microsoft Specific

See also
Keywords
Built-in types
Data Type Ranges
__ptr32, __ptr64
Article • 08/03/2021 • 2 minutes to read

Microsoft Specific

__ptr32 represents a native pointer on a 32-bit system, while __ptr64 represents a

native pointer on a 64-bit system.

The following example shows how to declare each of these pointer types:

C++

int * __ptr32 p32;


int * __ptr64 p64;

On a 32-bit system, a pointer declared with __ptr64 is truncated to a 32-bit pointer. On


a 64-bit system, a pointer declared with __ptr32 is coerced to a 64-bit pointer.

7 Note

You cannot use __ptr32 or __ptr64 when compiling with /clr:pure. Otherwise,
Compiler Error C2472 will be generated. The /clr:pure and /clr:safe compiler
options are deprecated in Visual Studio 2015 and unsupported in Visual Studio
2017.

For compatibility with previous versions, _ptr32 and _ptr64 are synonyms for __ptr32
and __ptr64 unless compiler option /Za (Disable language extensions) is specified.

Example
The following example shows how to declare and allocate pointers with the __ptr32 and
__ptr64 keywords.

C++

#include <cstdlib>
#include <iostream>

int main()
{
using namespace std;
int * __ptr32 p32;
int * __ptr64 p64;

p32 = (int * __ptr32)malloc(4);


*p32 = 32;
cout << *p32 << endl;

p64 = (int * __ptr64)malloc(4);


*p64 = 64;
cout << *p64 << endl;
}

Output

32
64

END Microsoft Specific

See also
Built-in types
Numerical Limits (C++)
Article • 08/03/2021 • 2 minutes to read

The two standard include files, <limits.h> and <float.h>, define the numerical limits, or
minimum and maximum values that a variable of a given type can hold. These
minimums and maximums are guaranteed to be portable to any C++ compiler that uses
the same data representation as ANSI C. The <limits.h> include file defines the
numerical limits for integral types, and <float.h> defines the numerical limits for floating
types.

See also
Basic Concepts
Integer Limits
Article • 08/03/2021 • 2 minutes to read

Microsoft-specific

The limits for integer types are listed in the following table. Preprocessor macros for
these limits are also defined when you include the standard header file <climits>.

Limits on Integer Constants


Constant Meaning Value

CHAR_BIT Number of bits in the smallest variable that is 8


not a bit field.

SCHAR_MIN Minimum value for a variable of type signed -128


char .

SCHAR_MAX Maximum value for a variable of type signed 127


char .

UCHAR_MAX Maximum value for a variable of type unsigned 255 (0xff)


char .

CHAR_MIN Minimum value for a variable of type char . -128; 0 if /J option used

CHAR_MAX Maximum value for a variable of type char . 127; 255 if /J option used

MB_LEN_MAX Maximum number of bytes in a multicharacter 5


constant.

SHRT_MIN Minimum value for a variable of type short . -32768

SHRT_MAX Maximum value for a variable of type short . 32767

USHRT_MAX Maximum value for a variable of type unsigned 65535 (0xffff)


short .

INT_MIN Minimum value for a variable of type int . -2147483648

INT_MAX Maximum value for a variable of type int . 2147483647

UINT_MAX Maximum value for a variable of type unsigned 4294967295 (0xffffffff)


int .

LONG_MIN Minimum value for a variable of type long . -2147483648


Constant Meaning Value

LONG_MAX Maximum value for a variable of type long . 2147483647

ULONG_MAX Maximum value for a variable of type unsigned 4294967295 (0xffffffff)


long .

LLONG_MIN Minimum value for a variable of type long long -9223372036854775808

LLONG_MAX Maximum value for a variable of type long long 9223372036854775807

ULLONG_MAX Maximum value for a variable of type unsigned 18446744073709551615


long long (0xffffffffffffffff)

If a value exceeds the largest integer representation, the Microsoft compiler generates
an error.

See also
Floating Limits
Floating Limits
Article • 08/03/2021 • 2 minutes to read

Microsoft Specific

The following table lists the limits on the values of floating-point constants. These limits
are also defined in the standard header file <float.h>.

Limits on Floating-Point Constants


Constant Meaning Value

FLT_DIG Number of digits, q, such that a floating-point 6


DBL_DIG number with q decimal digits can be rounded 15
LDBL_DIG into a floating-point representation and back 15
without loss of precision.

FLT_EPSILON Smallest positive number x, such that x + 1.0 is 1.192092896e-07F


DBL_EPSILON not equal to 1.0. 2.2204460492503131e-016
LDBL_EPSILON 2.2204460492503131e-016

FLT_GUARD 0

FLT_MANT_DIG Number of digits in the radix specified by 24


DBL_MANT_DIG FLT_RADIX in the floating-point significand. The 53
LDBL_MANT_DIG radix is 2; hence these values specify bits. 53

FLT_MAX Maximum representable floating-point number. 3.402823466e+38F


DBL_MAX 1.7976931348623158e+308
LDBL_MAX 1.7976931348623158e+308

FLT_MAX_10_EXP Maximum integer such that 10 raised to that 38


DBL_MAX_10_EXP number is a representable floating-point 308
LDBL_MAX_10_EXP number. 308

FLT_MAX_EXP Maximum integer such that FLT_RADIX raised to 128


DBL_MAX_EXP that number is a representable floating- point 1024
LDBL_MAX_EXP number. 1024

FLT_MIN Minimum positive value. 1.175494351e-38F


DBL_MIN 2.2250738585072014e-308
LDBL_MIN 2.2250738585072014e-308

FLT_MIN_10_EXP Minimum negative integer such that 10 raised -37


DBL_MIN_10_EXP to that number is a representable floating- point -307
LDBL_MIN_10_EXP number. -307
Constant Meaning Value

FLT_MIN_EXP Minimum negative integer such that FLT_RADIX -125


DBL_MIN_EXP raised to that number is a representable -1021
LDBL_MIN_EXP floating-point number. -1021

FLT_NORMALIZE 0

FLT_RADIX Radix of exponent representation. 2


_DBL_RADIX 2
_LDBL_RADIX 2

FLT_ROUNDS Rounding mode for floating-point addition. 1 (near)


_DBL_ROUNDS 1 (near)
_LDBL_ROUNDS 1 (near)

7 Note

The information in the table may differ in future versions of the product.

END Microsoft Specific

See also
Integer Limits
Declarations and definitions (C++)
Article • 02/23/2022 • 4 minutes to read

A C++ program consists of various entities such as variables, functions, types, and
namespaces. Each of these entities must be declared before they can be used. A
declaration specifies a unique name for the entity, along with information about its type
and other characteristics. In C++ the point at which a name is declared is the point at
which it becomes visible to the compiler. You can't refer to a function or class that is
declared at some later point in the compilation unit. Variables should be declared as
close as possible before the point at which they're used.

The following example shows some declarations:

C++

#include <string>

int f(int i); // forward declaration

int main()
{
const double pi = 3.14; //OK
int i = f(2); //OK. f is forward-declared
C obj; // error! C not yet declared.
std::string str; // OK std::string is declared in <string> header
j = 0; // error! No type specified.
auto k = 0; // OK. type inferred as int by compiler.
}

int f(int i)
{
return i + 42;
}

namespace N {
class C{/*...*/};
}

On line 5, the main function is declared. On line 7, a const variable named pi is


declared and initialized. On line 8, an integer i is declared and initialized with the value
produced by the function f . The name f is visible to the compiler because of the
forward declaration on line 3.

In line 9, a variable named obj of type C is declared. However, this declaration raises an
error because C isn't declared until later in the program, and isn't forward-declared. To
fix the error, you can either move the entire definition of C before main or else add a
forward-declaration for it. This behavior is different from other languages such as C#. In
those languages, functions and classes can be used before their point of declaration in a
source file.

In line 10, a variable named str of type std::string is declared. The name std::string
is visible because it's introduced in the string header file, which is merged into the
source file in line 1. std is the namespace in which the string class is declared.

In line 11, an error is raised because the name j hasn't been declared. A declaration
must provide a type, unlike other languages such as JavaScript. In line 12, the auto
keyword is used, which tells the compiler to infer the type of k based on the value that
it's initialized with. The compiler in this case chooses int for the type.

Declaration scope
The name that is introduced by a declaration is valid within the scope where the
declaration occurs. In the previous example, the variables that are declared inside the
main function are local variables. You could declare another variable named i outside
of main, at global scope, and it would be a separate entity. However, such duplication of
names can lead to programmer confusion and errors, and should be avoided. In line 21,
the class C is declared in the scope of the namespace N . The use of namespaces helps
to avoid name collisions. Most C++ Standard Library names are declared within the std
namespace. For more information about how scope rules interact with declarations, see
Scope.

Definitions
Some entities, including functions, classes, enums, and constant variables, must be
defined as well as declared. A definition provides the compiler with all the information it
needs to generate machine code when the entity is used later in the program. In the
previous example, line 3 contains a declaration for the function f but the definition for
the function is provided in lines 15 through 18. On line 21, the class C is both declared
and defined (although as defined the class doesn't do anything). A constant variable
must be defined, in other words assigned a value, in the same statement in which it's
declared. A declaration of a built-in type such as int is automatically a definition
because the compiler knows how much space to allocate for it.

The following example shows declarations that are also definitions:

C++
// Declare and define int variables i and j.
int i;
int j = 10;

// Declare enumeration suits.


enum suits { Spades = 1, Clubs, Hearts, Diamonds };

// Declare class CheckBox.


class CheckBox : public Control
{
public:
Boolean IsChecked();
virtual int ChangeState() = 0;
};

Here are some declarations that aren't definitions:

C++

extern int i;
char *strchr( const char *Str, const char Target );

Typedefs and using statements


In older versions of C++, the typedef keyword is used to declare a new name that is an
alias for another name. For example, the type std::string is another name for
std::basic_string<char> . It should be obvious why programmers use the typedef name

and not the actual name. In modern C++, the using keyword is preferred over typedef ,
but the idea is the same: a new name is declared for an entity, which is already declared
and defined.

Static class members


Static class data members are discrete variables that are shared by all objects of the
class. Because they're shared, they must be defined and initialized outside the class
definition. For more information, see Classes.

extern declarations
A C++ program might contain more than one compilation unit. To declare an entity
that's defined in a separate compilation unit, use the extern keyword. The information in
the declaration is sufficient for the compiler. However, if the definition of the entity can't
be found in the linking step, then the linker will raise an error.
In this section
Storage classes
const
constexpr
extern
Initializers
Aliases and typedefs
using declaration
volatile
decltype
Attributes in C++

See also
Basic Concepts
Storage classes
Article • 02/15/2022 • 8 minutes to read

A storage class in the context of C++ variable declarations is a type specifier that
governs the lifetime, linkage, and memory location of objects. A given object can have
only one storage class. Variables defined within a block have automatic storage unless
otherwise specified using the extern , static , or thread_local specifiers. Automatic
objects and variables have no linkage; they aren't visible to code outside the block.
Memory is allocated for them automatically when execution enters the block, and it's
de-allocated when the block is exited.

Notes
The mutable keyword may be considered a storage class specifier. However, it's
only available in the member list of a class definition.

Visual Studio 2010 and later: The auto keyword is no longer a C++ storage-class
specifier, and the register keyword is deprecated. Visual Studio 2017 version 15.7
and later: (available in /std:c++17 mode and later): The register keyword is
removed from the C++ language. Its use causes a diagnostic message:

C++

// c5033.cpp
// compile by using: cl /c /std:c++17 c5033.cpp
register int value; // warning C5033: 'register' is no longer a
supported storage class

static
The static keyword can be used to declare variables and functions at global scope,
namespace scope, and class scope. Static variables can also be declared at local scope.

Static duration means that the object or variable is allocated when the program starts
and is deallocated when the program ends. External linkage means that the name of the
variable is visible from outside the file where the variable is declared. Conversely,
internal linkage means that the name isn't visible outside the file where the variable is
declared. By default, an object or variable that is defined in the global namespace has
static duration and external linkage. The static keyword can be used in the following
situations.
1. When you declare a variable or function at file scope (global and/or namespace
scope), the static keyword specifies that the variable or function has internal
linkage. When you declare a variable, the variable has static duration and the
compiler initializes it to 0 unless you specify another value.

2. When you declare a variable in a function, the static keyword specifies that the
variable retains its state between calls to that function.

3. When you declare a data member in a class declaration, the static keyword
specifies that one copy of the member is shared by all instances of the class. A
static data member must be defined at file scope. An integral data member that
you declare as const static can have an initializer.

4. When you declare a member function in a class declaration, the static keyword
specifies that the function is shared by all instances of the class. A static member
function can't access an instance member because the function doesn't have an
implicit this pointer. To access an instance member, declare the function with a
parameter that's an instance pointer or reference.

5. You can't declare the members of a union as static . However, a globally declared
anonymous union must be explicitly declared static .

This example shows how a variable declared static in a function retains its state
between calls to that function.

C++

// static1.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;


void showstat( int curr ) {
static int nStatic; // Value of nStatic is retained
// between each function call
nStatic += curr;
cout << "nStatic is " << nStatic << endl;
}

int main() {
for ( int i = 0; i < 5; i++ )
showstat( i );
}

Output
nStatic is 0
nStatic is 1
nStatic is 3
nStatic is 6
nStatic is 10

This example shows the use of static in a class.

C++

// static2.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;


class CMyClass {
public:
static int m_i;
};

int CMyClass::m_i = 0;
CMyClass myObject1;
CMyClass myObject2;

int main() {
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;

myObject1.m_i = 1;
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;

myObject2.m_i = 2;
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;

CMyClass::m_i = 3;
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;
}

Output

0
0
1
1
2
2
3
3
The following example shows a local variable declared static in a member function.
The static variable is available to the whole program; all instances of the type share the
same copy of the static variable.

C++

// static3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
struct C {
void Test(int value) {
static int var = 0;
if (var == value)
cout << "var == value" << endl;
else
cout << "var != value" << endl;

var = value;
}
};

int main() {
C c1;
C c2;
c1.Test(100);
c2.Test(100);
}

Output

var != value
var == value

Starting in C++11, a static local variable initialization is guaranteed to be thread-safe.


This feature is sometimes called magic statics. However, in a multithreaded application
all subsequent assignments must be synchronized. The thread-safe static initialization
feature can be disabled by using the /Zc:threadSafeInit- flag to avoid taking a
dependency on the CRT.

extern
Objects and variables declared as extern declare an object that is defined in another
translation unit or in an enclosing scope as having external linkage. For more
information, see extern and Translation units and linkage.
thread_local (C++11)
A variable declared with the thread_local specifier is accessible only on the thread on
which it's created. The variable is created when the thread is created, and it's destroyed
when the thread is destroyed. Each thread has its own copy of the variable. On
Windows, thread_local is functionally equivalent to the Microsoft-specific __declspec(
thread ) attribute.

C++

thread_local float f = 42.0; // Global namespace. Not implicitly static.

struct S // cannot be applied to type definition


{
thread_local int i; // Illegal. The member must be static.
thread_local static char buf[10]; // OK
};

void DoSomething()
{
// Apply thread_local to a local variable.
// Implicitly "thread_local static S my_struct".
thread_local S my_struct;
}

Things to note about the thread_local specifier:

Dynamically initialized thread-local variables in DLLs may not be correctly


initialized on all calling threads. For more information, see thread.

The thread_local specifier may be combined with static or extern .

You can apply thread_local only to data declarations and definitions;


thread_local can't be used on function declarations or definitions.

You can specify thread_local only on data items with static storage duration,
which includes global data objects (both static and extern ), local static objects,
and static data members of classes. Any local variable declared thread_local is
implicitly static if no other storage class is provided; in other words, at block scope
thread_local is equivalent to thread_local static .

You must specify thread_local for both the declaration and the definition of a
thread local object, whether the declaration and definition occur in the same file or
separate files.
We don't recommend you use thread_local variables with std::launch::async .
For more information, see <future> functions.

On Windows, thread_local is functionally equivalent to __declspec(thread) except that


*__declspec(thread) * can be applied to a type definition and is valid in C code.
Whenever possible, use thread_local because it's part of the C++ standard and is
therefore more portable.

register
Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): The
register keyword is no longer a supported storage class. Its use causes a diagnostic.
The keyword is still reserved in the standard for future use.

C++

register int val; // warning C5033: 'register' is no longer a supported


storage class

Example: automatic vs. static initialization


A local automatic object or variable is initialized every time the flow of control reaches
its definition. A local static object or variable is initialized the first time the flow of
control reaches its definition.

Consider the following example, which defines a class that logs initialization and
destruction of objects and then defines three objects, I1 , I2 , and I3 :

C++

// initialization_of_objects.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>
using namespace std;

// Define a class that logs initializations and destructions.


class InitDemo {
public:
InitDemo( const char *szWhat );
~InitDemo();

private:
char *szObjName;
size_t sizeofObjName;
};

// Constructor for class InitDemo


InitDemo::InitDemo( const char *szWhat ) :
szObjName(NULL), sizeofObjName(0) {
if ( szWhat != 0 && strlen( szWhat ) > 0 ) {
// Allocate storage for szObjName, then copy
// initializer szWhat into szObjName, using
// secured CRT functions.
sizeofObjName = strlen( szWhat ) + 1;

szObjName = new char[ sizeofObjName ];


strcpy_s( szObjName, sizeofObjName, szWhat );

cout << "Initializing: " << szObjName << "\n";


}
else {
szObjName = 0;
}
}

// Destructor for InitDemo


InitDemo::~InitDemo() {
if( szObjName != 0 ) {
cout << "Destroying: " << szObjName << "\n";
delete szObjName;
}
}

// Enter main function


int main() {
InitDemo I1( "Auto I1" ); {
cout << "In block.\n";
InitDemo I2( "Auto I2" );
static InitDemo I3( "Static I3" );
}
cout << "Exited block.\n";
}

Output

Initializing: Auto I1
In block.
Initializing: Auto I2
Initializing: Static I3
Destroying: Auto I2
Exited block.
Destroying: Auto I1
Destroying: Static I3

This example demonstrates how and when the objects I1 , I2 , and I3 are initialized and
when they're destroyed.
There are several points to note about the program:

First, I1 and I2 are automatically destroyed when the flow of control exits the
block in which they're defined.

Second, in C++, it isn't necessary to declare objects or variables at the beginning


of a block. Furthermore, these objects are initialized only when the flow of control
reaches their definitions. ( I2 and I3 are examples of such definitions.) The output
shows exactly when they're initialized.

Finally, static local variables such as I3 retain their values while the program runs,
but are destroyed as the program terminates.

See also
Declarations and Definitions
auto (C++)
Article • 11/30/2022 • 6 minutes to read

Deduces the type of a declared variable from its initialization expression.

7 Note

The C++ standard defines an original and a revised meaning for this keyword.
Before Visual Studio 2010, the auto keyword declares a variable in the automatic
storage class; that is, a variable that has a local lifetime. Starting with Visual Studio
2010, the auto keyword declares a variable whose type is deduced from the
initialization expression in its declaration. The /Zc:auto[-] compiler option controls
the meaning of the auto keyword.

Syntax
auto declarator initializer ;

[](auto param1 , auto param2 ) {};

Remarks
The auto keyword directs the compiler to use the initialization expression of a declared
variable, or lambda expression parameter, to deduce its type.

We recommend that you use the auto keyword for most situations—unless you really
want a conversion—because it provides these benefits:

Robustness: If the expression's type is changed—including when a function return


type is changed—it just works.

Performance: You're guaranteed that there's no conversion.

Usability: You don't have to worry about type name spelling difficulties and typos.

Efficiency: Your coding can be more efficient.

Conversion cases in which you might not want to use auto :

You want a specific type and nothing else will do.


In expression template helper types—for example, (valarray+valarray) .

To use the auto keyword, use it instead of a type to declare a variable, and specify an
initialization expression. In addition, you can modify the auto keyword by using
specifiers and declarators such as const , volatile , pointer ( * ), reference ( & ), and rvalue
reference ( && ). The compiler evaluates the initialization expression and then uses that
information to deduce the type of the variable.

The auto initialization expression can take several forms:

Universal initialization syntax, such as auto a { 42 }; .


Assignment syntax, such as auto b = 0; .
Universal assignment syntax, which combines the two previous forms, such as auto
c = { 3.14159 }; .

Direct initialization, or constructor-style syntax, such as auto d( 1.41421f ); .

For more information, see Initializers and the code examples later in this document.

When auto is used to declare the loop parameter in a range-based for statement, it
uses a different initialization syntax, for example for (auto& i : iterable)
do_action(i); . For more information, see Range-based for Statement (C++).

The auto keyword is a placeholder for a type, but it isn't itself a type. Therefore, the
auto keyword can't be used in casts or operators such as sizeof and (for C++/CLI)

typeid.

Usefulness
The auto keyword is a simple way to declare a variable that has a complicated type. For
example, you can use auto to declare a variable where the initialization expression
involves templates, pointers to functions, or pointers to members.

You can also use auto to declare and initialize a variable to a lambda expression. You
can't declare the type of the variable yourself because the type of a lambda expression
is known only to the compiler. For more information, see Examples of Lambda
Expressions.

Trailing Return Types


You can use auto , together with the decltype type specifier, to help write template
libraries. Use auto and decltype to declare a function template whose return type
depends on the types of its template arguments. Or, use auto and decltype to declare
a function template that wraps a call to another function, and then returns whatever is
the return type of that other function. For more information, see decltype.

References and cv-qualifiers


Using auto drops references, const qualifiers, and volatile qualifiers. Consider the
following example:

C++

// cl.exe /analyze /EHsc /W4


#include <iostream>

using namespace std;

int main( )
{
int count = 10;
int& countRef = count;
auto myAuto = countRef;

countRef = 11;
cout << count << " ";

myAuto = 12;
cout << count << endl;
}

In the previous example, myAuto is an int , not an int reference, so the output is 11
11 , not 11 12 as would be the case if the reference qualifier hadn't been dropped by
auto .

Type deduction with braced initializers (C++14)


The following code example shows how to initialize an auto variable using braces. Note
the difference between B and C and between A and E.

C++

#include <initializer_list>

int main()
{
// std::initializer_list<int>
auto A = { 1, 2 };
// std::initializer_list<int>
auto B = { 3 };

// int
auto C{ 4 };

// C3535: cannot deduce type for 'auto' from initializer list'


auto D = { 5, 6.7 };

// C3518 in a direct-list-initialization context the type for 'auto'


// can only be deduced from a single initializer expression
auto E{ 8, 9 };

return 0;
}

Restrictions and error messages


The following table lists the restrictions on the use of the auto keyword, and the
corresponding diagnostic error message that the compiler emits.

Error Description
number

C3530 The auto keyword can't be combined with any other type-specifier.

C3531 A symbol that is declared with the auto keyword must have an initializer.

C3532 You incorrectly used the auto keyword to declare a type. For example, you declared a
method return type or an array.

C3533, A parameter or template argument can't be declared with the auto keyword.
C3539

C3535 A method or template parameter can't be declared with the auto keyword.

C3536 A symbol can't be used before it's initialized. In practice, it means that a variable can't
be used to initialize itself.

C3537 You can't cast to a type that is declared with the auto keyword.

C3538 All the symbols in a declarator list that is declared with the auto keyword must resolve
to the same type. For more information, see Declarations and Definitions.

C3540, The sizeof and typeid operators can't be applied to a symbol that is declared with the
C3541 auto keyword.
Examples
These code fragments illustrate some of the ways in which the auto keyword can be
used.

The following declarations are equivalent. In the first statement, variable j is declared to
be type int . In the second statement, variable k is deduced to be type int because the
initialization expression (0) is an integer.

C++

int j = 0; // Variable j is explicitly type int.


auto k = 0; // Variable k is implicitly type int because 0 is an integer.

The following declarations are equivalent, but the second declaration is simpler than the
first. One of the most compelling reasons to use the auto keyword is simplicity.

C++

map<int,list<string>>::iterator i = m.begin();
auto i = m.begin();

The following code fragment declares the type of variables iter and elem when the
for and range for loops start.

C++

// cl /EHsc /nologo /W4


#include <deque>
using namespace std;

int main()
{
deque<double> dqDoubleData(10, 0.1);

for (auto iter = dqDoubleData.begin(); iter != dqDoubleData.end();


++iter)
{ /* ... */ }

// prefer range-for loops with the following information in mind


// (this applies to any range-for with auto, not just deque)

for (auto elem : dqDoubleData) // COPIES elements, not much better than
the previous examples
{ /* ... */ }

for (auto& elem : dqDoubleData) // observes and/or modifies elements IN-


PLACE
{ /* ... */ }

for (const auto& elem : dqDoubleData) // observes elements IN-PLACE


{ /* ... */ }
}

The following code fragment uses the new operator and pointer declaration to declare
pointers.

C++

double x = 12.34;
auto *y = new auto(x), **z = new auto(&x);

The next code fragment declares multiple symbols in each declaration statement. Notice
that all of the symbols in each statement resolve to the same type.

C++

auto x = 1, *y = &x, **z = &y; // Resolves to int.


auto a(2.01), *b (&a); // Resolves to double.
auto c = 'a', *d(&c); // Resolves to char.
auto m = 1, &n = m; // Resolves to int.

This code fragment uses the conditional operator ( ?: ) to declare variable x as an


integer that has a value of 200:

C++

int v1 = 100, v2 = 200;


auto x = v1 > v2 ? v1 : v2;

The following code fragment initializes variable x to type int , variable y to a reference
to type const int , and variable fp to a pointer to a function that returns type int .

C++

int f(int x) { return x; }


int main()
{
auto x = f(0);
const auto& y = f(1);
int (*p)(int x);
p = f;
auto fp = p;
//...
}

See also
Keywords
/Zc:auto (Deduce variable type)
sizeof operator
typeid
operator new
Declarations and definitions
Examples of lambda expressions
Initializers
decltype
const (C++)
Article • 03/13/2023 • 3 minutes to read

When it modifies a data declaration, the const keyword specifies that the object or
variable isn't modifiable.

Syntax
declarator :

ptr-declarator
noptr-declarator parameters-and-qualifiers trailing-return-type

ptr-declarator :
noptr-declarator

ptr-operator ptr-declarator

noptr-declarator :
declarator-id attribute-specifier-seq opt

noptr-declarator parameters-and-qualifiers
noptr-declarator [ constant-expression opt ] attribute-specifier-seq opt

( ptr-declarator )
parameters-and-qualifiers :

( parameter-declaration-clause ) cv-qualifier-seq opt

ref-qualifier opt noexcept-specifier opt attribute-specifier-seq opt


trailing-return-type :

-> type-id
ptr-operator :

* attribute-specifier-seq opt cv-qualifier-seq opt

& attribute-specifier-seq opt


&& attribute-specifier-seq opt

nested-name-specifier * attribute-specifier-seq opt cv-qualifier-seq opt


cv-qualifier-seq :

cv-qualifier cv-qualifier-seq opt

cv-qualifier :
const

volatile
ref-qualifier :

&

&&
declarator-id :

... opt id-expression

const values
The const keyword specifies that a variable's value is constant and tells the compiler to
prevent the programmer from modifying it.

C++

// constant_values1.cpp
int main() {
const int i = 5;
i = 10; // C3892
i++; // C2105
}

In C++, you can use the const keyword instead of the #define preprocessor directive to
define constant values. Values defined with const are subject to type checking, and can
be used in place of constant expressions. In C++, you can specify the size of an array
with a const variable as follows:

C++

// constant_values2.cpp
// compile with: /c
const int maxarray = 255;
char store_char[maxarray]; // allowed in C++; not allowed in C

In C, constant values default to external linkage, so they can appear only in source files.
In C++, constant values default to internal linkage, which allows them to appear in
header files.

The const keyword can also be used in pointer declarations.

C++

// constant_values3.cpp
int main() {
char this_char{'a'}, that_char{'b'};
char *mybuf = &this_char, *yourbuf = &that_char;
char *const aptr = mybuf;
*aptr = 'c'; // OK
aptr = yourbuf; // C3892
}
A pointer to a variable declared as const can be assigned only to a pointer that is also
declared as const .

C++

// constant_values4.cpp
#include <stdio.h>
int main() {
const char *mybuf = "test";
char *yourbuf = "test2";
printf_s("%s\n", mybuf);

const char *bptr = mybuf; // Pointer to constant data


printf_s("%s\n", bptr);

// *bptr = 'a'; // Error


}

You can use pointers to constant data as function parameters to prevent the function
from modifying a parameter passed through a pointer.

For objects that are declared as const , you can only call constant member functions.
The compiler ensures that the constant object is never modified.

C++

birthday.getMonth(); // Okay
birthday.setMonth( 4 ); // Error

You can call either constant or non-constant member functions for a non-constant
object. You can also overload a member function using the const keyword; this feature
allows a different version of the function to be called for constant and non-constant
objects.

You can't declare constructors or destructors with the const keyword.

const member functions


Declaring a member function with the const keyword specifies that the function is a
"read-only" function that doesn't modify the object for which it's called. A constant
member function can't modify any non-static data members or call any member
functions that aren't constant. To declare a constant member function, place the const
keyword after the closing parenthesis of the argument list. The const keyword is
required in both the declaration and the definition.
C++

// constant_member_function.cpp
class Date
{
public:
Date( int mn, int dy, int yr );
int getMonth() const; // A read-only function
void setMonth( int mn ); // A write function; can't be const
private:
int month;
};

int Date::getMonth() const


{
return month; // Doesn't modify anything
}
void Date::setMonth( int mn )
{
month = mn; // Modifies data member
}
int main()
{
Date MyDate( 7, 4, 1998 );
const Date BirthDate( 1, 18, 1953 );
MyDate.setMonth( 4 ); // Okay
BirthDate.getMonth(); // Okay
BirthDate.setMonth( 4 ); // C2662 Error
}

C and C++ const differences


When you define a const variable in a C source code file, you do so as:

const int i = 2;

You can then use this variable in another module as follows:

extern const int i;

But to get the same behavior in C++, you must define your const variable as:

C++
extern const int i = 2;

Similar to C, you can then use this variable in another module as follows:

C++

extern const int i;

If you wish to define an extern variable in a C++ source code file for use in a C source
code file, use:

C++

extern "C" const int x=10;

to prevent name mangling by the C++ compiler.

Remarks
When following a member function's parameter list, the const keyword specifies that
the function doesn't modify the object for which it's invoked.

For more information on const , see the following articles:

const and volatile pointers

Type qualifiers (C language reference)

volatile

#define

See also
Keywords
constexpr (C++)
Article • 02/22/2023 • 5 minutes to read

The keyword constexpr was introduced in C++11 and improved in C++14. It means
constant expression. Like const , it can be applied to variables: A compiler error is raised
when any code attempts to modify the value. Unlike const , constexpr can also be
applied to functions and class constructors. constexpr indicates that the value, or return
value, is constant and, where possible, is computed at compile time.

A constexpr integral value can be used wherever a const integer is required, such as in
template arguments and array declarations. And when a value is computed at compile
time instead of run time, it helps your program run faster and use less memory.

To limit the complexity of compile-time constant computations, and their potential


impacts on compilation time, the C++14 standard requires the types in constant
expressions to be literal types.

Syntax
constexpr literal-type identifier = constant-expression ;

constexpr literal-type identifier { constant-expression } ;


constexpr literal-type identifier ( params ) ;

constexpr ctor ( params ) ;

Parameters
params
One or more parameters, each of which must be a literal type and must itself be a
constant expression.

Return value
A constexpr variable or function must return a literal type.

constexpr variables
The primary difference between const and constexpr variables is that the initialization
of a const variable can be deferred until run time. A constexpr variable must be
initialized at compile time. All constexpr variables are const .

A variable can be declared with constexpr , when it has a literal type and is
initialized. If the initialization is performed by a constructor, the constructor must
be declared as constexpr .

A reference may be declared as constexpr when both these conditions are met:
The referenced object is initialized by a constant expression, and any implicit
conversions invoked during initialization are also constant expressions.

All declarations of a constexpr variable or function must have the constexpr


specifier.

C++

constexpr float x = 42.0;


constexpr float y{108};
constexpr float z = exp(5, 3);
constexpr int i; // Error! Not initialized
int j = 0;
constexpr int k = j + 1; //Error! j not a constant expression

constexpr functions
A constexpr function is one whose return value is computable at compile time when
consuming code requires it. Consuming code requires the return value at compile time
to initialize a constexpr variable, or to provide a non-type template argument. When its
arguments are constexpr values, a constexpr function produces a compile-time
constant. When called with non- constexpr arguments, or when its value isn't required at
compile time, it produces a value at run time like a regular function. (This dual behavior
saves you from having to write constexpr and non- constexpr versions of the same
function.)

A constexpr function or constructor is implicitly inline .

The following rules apply to constexpr functions:

A constexpr function must accept and return only literal types.

A constexpr function can be recursive.

Before C++20, a constexpr function can't be virtual, and a constructor can't be


defined as constexpr when the enclosing class has any virtual base classes. In
C++20 and later, a constexpr function can be virtual. Visual Studio 2019 version
16.10 and later versions support constexpr virtual functions when you specify the
/std:c++20 or later compiler option.

The body can be defined as = default or = delete .

The body can contain no goto statements or try blocks.

An explicit specialization of a non- constexpr template can be declared as


constexpr :

An explicit specialization of a constexpr template doesn't also have to be


constexpr :

The following rules apply to constexpr functions in Visual Studio 2017 and later:

It may contain if and switch statements, and all looping statements including
for , range-based for , while , and do-while.

It may contain local variable declarations, but the variable must be initialized. It
must be a literal type, and can't be static or thread-local. The locally declared
variable isn't required to be const , and may mutate.

A constexpr non- static member function isn't required to be implicitly const .

C++

constexpr float exp(float x, int n)


{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
}

 Tip

In the Visual Studio debugger, when debugging a non-optimised Debug build, you
can tell whether a constexpr function is being evaluated at compile time by putting
a breakpoint inside it. If the breakpoint is hit, the function was called at run-time. If
not, then the function was called at compile time.

extern constexpr
The /Zc:externConstexpr compiler option causes the compiler to apply external linkage
to variables declared by using extern constexpr. In earlier versions of Visual Studio,
either by default or when /Zc:externConstexpr- is specified, Visual Studio applies
internal linkage to constexpr variables even when the extern keyword is used. The
/Zc:externConstexpr option is available starting in Visual Studio 2017 Update 15.6, and
is off by default. The /permissive- option doesn't enable /Zc:externConstexpr.

Example
The following example shows constexpr variables, functions, and a user-defined type. In
the last statement in main() , the constexpr member function GetValue() is a run-time
call because the value isn't required to be known at compile time.

C++

// constexpr.cpp
// Compile with: cl /EHsc /W4 constexpr.cpp
#include <iostream>

using namespace std;

// Pass by value
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
}

// Pass by reference
constexpr float exp2(const float& x, const int& n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp2(x * x, n / 2) :
exp2(x * x, (n - 1) / 2) * x;
}

// Compile-time computation of array length


template<typename T, int N>
constexpr int length(const T(&)[N])
{
return N;
}

// Recursive constexpr function


constexpr int fac(int n)
{
return n == 1 ? 1 : n * fac(n - 1);
}
// User-defined type
class Foo
{
public:
constexpr explicit Foo(int i) : _i(i) {}
constexpr int GetValue() const
{
return _i;
}
private:
int _i;
};

int main()
{
// foo is const:
constexpr Foo foo(5);
// foo = Foo(6); //Error!

// Compile time:
constexpr float x = exp(5, 3);
constexpr float y { exp(2, 5) };
constexpr int val = foo.GetValue();
constexpr int f5 = fac(5);
const int nums[] { 1, 2, 3, 4 };
const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };

// Run time:
cout << "The value of foo is " << foo.GetValue() << endl;
}

Requirements
Visual Studio 2015 or later.

See also
Declarations and definitions
const
extern (C++)
Article • 12/03/2021 • 4 minutes to read

The extern keyword may be applied to a global variable, function, or template


declaration. It specifies that the symbol has external linkage. For background
information on linkage and why the use of global variables is discouraged, see
Translation units and linkage.

The extern keyword has four meanings depending on the context:

In a non- const global variable declaration, extern specifies that the variable or
function is defined in another translation unit. The extern must be applied in all
files except the one where the variable is defined.

In a const variable declaration, it specifies that the variable has external linkage.
The extern must be applied to all declarations in all files. (Global const variables
have internal linkage by default.)

extern "C" specifies that the function is defined elsewhere and uses the C-
language calling convention. The extern "C" modifier may also be applied to
multiple function declarations in a block.

In a template declaration, extern specifies that the template has already been
instantiated elsewhere. extern tells the compiler it can reuse the other
instantiation, rather than create a new one at the current location. For more
information about this use of extern , see Explicit instantiation.

extern linkage for non- const globals


When the linker sees extern before a global variable declaration, it looks for the
definition in another translation unit. Declarations of non- const variables at global
scope are external by default. Only apply extern to the declarations that don't provide
the definition.

C++

//fileA.cpp
int i = 42; // declaration and definition

//fileB.cpp
extern int i; // declaration only. same as i in FileA
//fileC.cpp
extern int i; // declaration only. same as i in FileA

//fileD.cpp
int i = 43; // LNK2005! 'i' already has a definition.
extern int i = 43; // same error (extern is ignored on definitions)

extern linkage for const globals


A const global variable has internal linkage by default. If you want the variable to have
external linkage, apply the extern keyword to the definition, and to all other
declarations in other files:

C++

//fileA.cpp
extern const int i = 42; // extern const definition

//fileB.cpp
extern const int i; // declaration only. same as i in FileA

extern constexpr linkage


In Visual Studio 2017 version 15.3 and earlier, the compiler always gave a constexpr
variable internal linkage, even when the variable was marked extern . In Visual Studio
2017 version 15.5 and later, the /Zc:externConstexpr compiler switch enables correct
standards-conforming behavior. Eventually the option will become the default. The
/permissive- option doesn't enable /Zc:externConstexpr .

C++

extern constexpr int x = 10; //error LNK2005: "int const x" already defined

If a header file contains a variable declared extern constexpr , it must be marked


__declspec(selectany) to correctly have its duplicate declarations combined:

C++

extern constexpr __declspec(selectany) int x = 10;


extern "C" and extern "C++" function
declarations
In C++, when used with a string, extern specifies that the linkage conventions of
another language are being used for the declarator(s). C functions and data can be
accessed only if they're previously declared as having C linkage. However, they must be
defined in a separately compiled translation unit.

Microsoft C++ supports the strings "C" and "C++" in the string-literal field. All of the
standard include files use the extern "C" syntax to allow the run-time library functions
to be used in C++ programs.

Example
The following example shows how to declare names that have C linkage:

C++

// Declare printf with C linkage.


extern "C" int printf(const char *fmt, ...);

// Cause everything in the specified


// header files to have C linkage.
extern "C" {
// add your #include statements here
#include <stdio.h>
}

// Declare the two functions ShowChar


// and GetChar with C linkage.
extern "C" {
char ShowChar(char ch);
char GetChar(void);
}

// Define the two functions


// ShowChar and GetChar with C linkage.
extern "C" char ShowChar(char ch) {
putchar(ch);
return ch;
}

extern "C" char GetChar(void) {


char ch;
ch = getchar();
return ch;
}
// Declare a global variable, errno, with C linkage.
extern "C" int errno;

If a function has more than one linkage specification, they must agree. It's an error to
declare functions as having both C and C++ linkage. Furthermore, if two declarations for
a function occur in a program, one with a linkage specification and one without, the
declaration with the linkage specification must be first. Any redundant declarations of
functions that already have linkage specification are given the linkage specified in the
first declaration. For example:

C++

extern "C" int CFunc1();


...
int CFunc1(); // Redeclaration is benign; C linkage is
// retained.

int CFunc2();
...
extern "C" int CFunc2(); // Error: not the first declaration of
// CFunc2; cannot contain linkage
// specifier.

Starting in Visual Studio 2019, when /permissive- is specified, the compiler checks that
the declarations of extern "C" function parameters also match. You can't overload a
function declared as extern "C" . Starting in Visual Studio 2019 version 16.3, you can
override this check by using the /Zc:externC- compiler option after the /permissive-
option.

See also
Keywords
Translation units and linkage
extern Storage-Class Specifier in C
Behavior of Identifiers in C
Linkage in C
Initializers
Article • 04/04/2023 • 12 minutes to read

An initializer specifies the initial value of a variable. You can initialize variables in these
contexts:

In the definition of a variable:

C++

int i = 3;
Point p1{ 1, 2 };

As one of the parameters of a function:

C++

set_point(Point{ 5, 6 });

As the return value of a function:

C++

Point get_new_point(int x, int y) { return { x, y }; }


Point get_new_point(int x, int y) { return Point{ x, y }; }

Initializers may take these forms:

An expression (or a comma-separated list of expressions) in parentheses:

C++

Point p1(1, 2);

An equals sign followed by an expression:

C++

string s = "hello";

A braced initializer list. The list may be empty or may consist of a set of lists, as in
the following example:
C++

struct Point{
int x;
int y;
};
class PointConsumer{
public:
void set_point(Point p){};
void set_points(initializer_list<Point> my_list){};
};
int main() {
PointConsumer pc{};
pc.set_point({});
pc.set_point({ 3, 4 });
pc.set_points({ { 3, 4 }, { 5, 6 } });
}

Kinds of initialization
There are several kinds of initialization, which may occur at different points in program
execution. Different kinds of initialization aren't mutually exclusive—for example, list
initialization can trigger value initialization and in other circumstances, it can trigger
aggregate initialization.

Zero initialization
Zero initialization is the setting of a variable to a zero value implicitly converted to the
type:

Numeric variables are initialized to 0 (or 0.0, or 0.0000000000, etc.).

Char variables are initialized to '\0' .

Pointers are initialized to nullptr .

Arrays, POD classes, structs, and unions have their members initialized to a zero
value.

Zero initialization is performed at different times:

At program startup, for all named variables that have static duration. These
variables may later be initialized again.

During value initialization, for scalar types and POD class types that are initialized
by using empty braces.
For arrays that have only a subset of their members initialized.

Here are some examples of zero initialization:

C++

struct my_struct{
int i;
char c;
};

int i0; // zero-initialized to 0


int main() {
static float f1; // zero-initialized to 0.000000000
double d{}; // zero-initialized to 0.00000000000000000
int* ptr{}; // initialized to nullptr
char s_array[3]{'a', 'b'}; // the third char is initialized to '\0'
int int_array[5] = { 8, 9, 10 }; // the fourth and fifth ints are
initialized to 0
my_struct a_struct{}; // i = 0, c = '\0'
}

Default initialization
Default initialization for classes, structs, and unions is initialization with a default
constructor. The default constructor can be called with no initialization expression or
with the new keyword:

C++

MyClass mc1;
MyClass* mc3 = new MyClass;

If the class, struct, or union doesn't have a default constructor, the compiler emits an
error.

Scalar variables are default initialized when they're defined with no initialization
expression. They have indeterminate values.

C++

int i1;
float f;
char c;
Arrays are default initialized when they're defined with no initialization expression. When
an array is default-initialized, its members are default initialized and have indeterminate
values, as in the following example:

C++

int int_arr[3];

If the array members don't have a default constructor, the compiler emits an error.

Default initialization of constant variables

Constant variables must be declared together with an initializer. If they're scalar types
they cause a compiler error, and if they're class types that have a default constructor
they cause a warning:

C++

class MyClass{};
int main() {
//const int i2; // compiler error C2734: const object must be
initialized if not extern
//const char c2; // same error
const MyClass mc1; // compiler error C4269: 'const automatic data
initialized with compiler generated default constructor produces unreliable
results
}

Default initialization of static variables

Static variables that are declared with no initializer are initialized to 0 (implicitly
converted to the type).

C++

class MyClass {
private:
int m_int;
char m_char;
};

int main() {
static int int1; // 0
static char char1; // '\0'
static bool bool1; // false
static MyClass mc1; // {0, '\0'}
}

For more information about initialization of global static objects, see main function and
command-line arguments.

Value initialization
Value initialization occurs in the following cases:

a named value is initialized using empty brace initialization

an anonymous temporary object is initialized using empty parentheses or braces

an object is initialized with the new keyword plus empty parentheses or braces

Value initialization does the following:

for classes with at least one public constructor, the default constructor is called

for nonunion classes with no declared constructors, the object is zero-initialized


and the default constructor is called

for arrays, every element is value-initialized

in all other cases, the variable is zero initialized

C++

class BaseClass {
private:
int m_int;
};

int main() {
BaseClass bc{}; // class is initialized
BaseClass* bc2 = new BaseClass(); // class is initialized, m_int value
is 0
int int_arr[3]{}; // value of all members is 0
int a{}; // value of a is 0
double b{}; // value of b is 0.00000000000000000
}

Copy initialization
Copy initialization is the initialization of one object using a different object. It occurs in
the following cases:
a variable is initialized using an equals sign

an argument is passed to a function

an object is returned from a function

an exception is thrown or caught

a non-static data member is initialized using an equals sign

class, struct, and union members are initialized by copy initialization during
aggregate initialization. See Aggregate initialization for examples.

The following code shows several examples of copy initialization:

C++

#include <iostream>
using namespace std;

class MyClass{
public:
MyClass(int myInt) {}
void set_int(int myInt) { m_int = myInt; }
int get_int() const { return m_int; }
private:
int m_int = 7; // copy initialization of m_int

};
class MyException : public exception{};
int main() {
int i = 5; // copy initialization of i
MyClass mc1{ i };
MyClass mc2 = mc1; // copy initialization of mc2 from mc1
MyClass mc1.set_int(i); // copy initialization of parameter from i
int i2 = mc2.get_int(); // copy initialization of i2 from return value
of get_int()

try{
throw MyException();
}
catch (MyException ex){ // copy initialization of ex
cout << ex.what();
}
}

Copy initialization can't invoke explicit constructors.

C++
vector<int> v = 10; // the constructor is explicit; compiler error C2440:
can't convert from 'int' to 'std::vector<int,std::allocator<_Ty>>'
regex r = "a.*b"; // the constructor is explicit; same error
shared_ptr<int> sp = new int(1729); // the constructor is explicit; same
error

In some cases, if the copy constructor of the class is deleted or inaccessible, copy
initialization causes a compiler error.

Direct initialization
Direct initialization is initialization using (non-empty) braces or parentheses. Unlike copy
initialization, it can invoke explicit constructors. It occurs in the following cases:

a variable is initialized with non-empty braces or parentheses

a variable is initialized with the new keyword plus non-empty braces or


parentheses

a variable is initialized with static_cast

in a constructor, base classes and non-static members are initialized with an


initializer list

in the copy of a captured variable inside a lambda expression

The following code shows some examples of direct initialization:

C++

class BaseClass{
public:
BaseClass(int n) :m_int(n){} // m_int is direct initialized
private:
int m_int;
};

class DerivedClass : public BaseClass{


public:
// BaseClass and m_char are direct initialized
DerivedClass(int n, char c) : BaseClass(n), m_char(c) {}
private:
char m_char;
};
int main(){
BaseClass bc1(5);
DerivedClass dc1{ 1, 'c' };
BaseClass* bc2 = new BaseClass(7);
BaseClass bc3 = static_cast<BaseClass>(dc1);

int a = 1;
function<int()> func = [a](){ return a + 1; }; // a is direct
initialized
int n = func();
}

List initialization
List initialization occurs when a variable is initialized using a braced initializer list. Braced
initializer lists can be used in the following cases:

a variable is initialized

a class is initialized with the new keyword

an object is returned from a function

an argument passed to a function

one of the arguments in a direct initialization

in a non-static data member initializer

in a constructor initializer list

The following code shows some examples of list initialization:

C++

class MyClass {
public:
MyClass(int myInt, char myChar) {}
private:
int m_int[]{ 3 };
char m_char;
};
class MyClassConsumer{
public:
void set_class(MyClass c) {}
MyClass get_class() { return MyClass{ 0, '\0' }; }
};
struct MyStruct{
int my_int;
char my_char;
MyClass my_class;
};
int main() {
MyClass mc1{ 1, 'a' };
MyClass* mc2 = new MyClass{ 2, 'b' };
MyClass mc3 = { 3, 'c' };

MyClassConsumer mcc;
mcc.set_class(MyClass{ 3, 'c' });
mcc.set_class({ 4, 'd' });

MyStruct ms1{ 1, 'a', { 2, 'b' } };


}

Aggregate initialization
Aggregate initialization is a form of list initialization for arrays or class types (often
structs or unions) that have:

no private or protected members

no user-provided constructors, except for explicitly defaulted or deleted


constructors

no base classes

no virtual member functions

7 Note
In Visual Studio 2015 and earlier, an aggregate is not allowed to have brace-or-
equal initializers for non-static members. This restriction was removed in the
C++14 standard and implemented in Visual Studio 2017.

Aggregate initializers consist of a braced initialization list, with or without an equals sign,
as in the following example:

C++

#include <iostream>
using namespace std;

struct MyAggregate{
int myInt;
char myChar;
};

struct MyAggregate2{
int myInt;
char myChar = 'Z'; // member-initializer OK in C++14
};
int main() {
MyAggregate agg1{ 1, 'c' };
MyAggregate2 agg2{2};
cout << "agg1: " << agg1.myChar << ": " << agg1.myInt << endl;
cout << "agg2: " << agg2.myChar << ": " << agg2.myInt << endl;

int myArr1[]{ 1, 2, 3, 4 };
int myArr2[3] = { 5, 6, 7 };
int myArr3[5] = { 8, 9, 10 };

cout << "myArr1: ";


for (int i : myArr1){
cout << i << " ";
}
cout << endl;

cout << "myArr3: ";


for (auto const &i : myArr3) {
cout << i << " ";
}
cout << endl;
}

You should see the following output:

Output

agg1: c: 1
agg2: Z: 2
myArr1: 1 2 3 4
myArr3: 8 9 10 0 0

) Important

Array members that are declared but not explicitly initialized during aggregate
initialization are zero-initialized, as in myArr3 above.

Initializing unions and structs


If a union doesn't have a constructor, you can initialize it with a single value (or with
another instance of a union). The value is used to initialize the first non-static field. This
is different from struct initialization, in which the first value in the initializer is used to
initialize the first field, the second to initialize the second field, and so on. Compare the
initialization of unions and structs in the following example:

C++
struct MyStruct {
int myInt;
char myChar;
};
union MyUnion {
int my_int;
char my_char;
bool my_bool;
MyStruct my_struct;
};

int main() {
MyUnion mu1{ 'a' }; // my_int = 97, my_char = 'a', my_bool = true,
{myInt = 97, myChar = '\0'}
MyUnion mu2{ 1 }; // my_int = 1, my_char = 'x1', my_bool = true,
{myInt = 1, myChar = '\0'}
MyUnion mu3{}; // my_int = 0, my_char = '\0', my_bool = false,
{myInt = 0, myChar = '\0'}
MyUnion mu4 = mu3; // my_int = 0, my_char = '\0', my_bool = false,
{myInt = 0, myChar = '\0'}
//MyUnion mu5{ 1, 'a', true }; // compiler error: C2078: too many
initializers
//MyUnion mu6 = 'a'; // compiler error: C2440: cannot convert
from 'char' to 'MyUnion'
//MyUnion mu7 = 1; // compiler error: C2440: cannot convert
from 'int' to 'MyUnion'

MyStruct ms1{ 'a' }; // myInt = 97, myChar = '\0'


MyStruct ms2{ 1 }; // myInt = 1, myChar = '\0'
MyStruct ms3{}; // myInt = 0, myChar = '\0'
MyStruct ms4{1, 'a'}; // myInt = 1, myChar = 'a'
MyStruct ms5 = { 2, 'b' }; // myInt = 2, myChar = 'b'
}

Initializing aggregates that contain aggregates


Aggregate types can contain other aggregate types, for example arrays of arrays, arrays
of structs, and so on. These types are initialized by using nested sets of braces, for
example:

C++

struct MyStruct {
int myInt;
char myChar;
};
int main() {
int intArr1[2][2]{{ 1, 2 }, { 3, 4 }};
int intArr3[2][2] = {1, 2, 3, 4};
MyStruct structArr[]{ { 1, 'a' }, { 2, 'b' }, {3, 'c'} };
}
Reference initialization
Variables of reference type must be initialized with an object of the type from which the
reference type is derived, or with an object of a type that can be converted to the type
from which the reference type is derived. For example:

C++

// initializing_references.cpp
int iVar;
long lVar;
int main()
{
long& LongRef1 = lVar; // No conversion required.
long& LongRef2 = iVar; // Error C2440
const long& LongRef3 = iVar; // OK
LongRef1 = 23L; // Change lVar through a reference.
LongRef2 = 11L; // Change iVar through a reference.
LongRef3 = 11L; // Error C3892
}

The only way to initialize a reference with a temporary object is to initialize a constant
temporary object. Once initialized, a reference-type variable always points to the same
object; it can't be modified to point to another object.

Although the syntax can be the same, initialization of reference-type variables and
assignment to reference-type variables are semantically different. In the preceding
example, the assignments that change iVar and lVar look similar to the initializations,
but have different effects. The initialization specifies the object to which the reference-
type variable points; the assignment assigns to the referred-to object through the
reference.

Because both passing an argument of reference type to a function and returning a value
of reference type from a function are initializations, the formal arguments to a function
are initialized correctly, as are the references returned.

Reference-type variables can be declared without initializers only in the following:

Function declarations (prototypes). For example:

C++

int func( int& );


Function-return type declarations. For example:

C++

int& func( int& );

Declaration of a reference-type class member. For example:

C++

class c {public: int& i;};

Declaration of a variable explicitly specified as extern . For example:

C++

extern int& iVal;

When initializing a reference-type variable, the compiler uses the decision graph shown
in the following figure to select between creating a reference to an object or creating a
temporary object to which the reference points:

Decision graph for initialization of reference types

References to volatile types (declared as volatile typename& identifier) can be


initialized with volatile objects of the same type or with objects that haven't been
declared as volatile . They can't, however, be initialized with const objects of that type.
Similarly, references to const types (declared as const typename& identifier) can be
initialized with const objects of the same type (or anything that has a conversion to that
type or with objects that haven't been declared as const ). They can't, however, be
initialized with volatile objects of that type.
References that aren't qualified with either the const or volatile keyword can be
initialized only with objects declared as neither const nor volatile .

Initialization of external variables


Declarations of automatic, static, and external variables can contain initializers. However,
declarations of external variables can contain initializers only if the variables aren't
declared as extern .
Aliases and typedefs (C++)
Article • 07/01/2022 • 6 minutes to read

You can use an alias declaration to declare a name to use as a synonym for a previously
declared type. (This mechanism is also referred to informally as a type alias). You can
also use this mechanism to create an alias template, which can be useful for custom
allocators.

Syntax
C++

using identifier = type;

Remarks
identifier
The name of the alias.

type
The type identifier you're creating an alias for.

An alias doesn't introduce a new type and can't change the meaning of an existing type
name.

The simplest form of an alias is equivalent to the typedef mechanism from C++03:

C++

// C++11
using counter = long;

// C++03 equivalent:
// typedef long counter;

Both of these forms enable the creation of variables of type counter . Something more
useful would be a type alias like this one for std::ios_base::fmtflags :

C++

// C++11
using fmtfl = std::ios_base::fmtflags;
// C++03 equivalent:
// typedef std::ios_base::fmtflags fmtfl;

fmtfl fl_orig = std::cout.flags();


fmtfl fl_hex = (fl_orig & ~std::cout.basefield) | std::cout.showbase |
std::cout.hex;
// ...
std::cout.flags(fl_hex);

Aliases also work with function pointers, but are much more readable than the
equivalent typedef:

C++

// C++11
using func = void(*)(int);

// C++03 equivalent:
// typedef void (*func)(int);

// func can be assigned to a function pointer value


void actual_function(int arg) { /* some code */ }
func fptr = &actual_function;

A limitation of the typedef mechanism is that it doesn't work with templates. However,
the type alias syntax in C++11 enables the creation of alias templates:

C++

template<typename T> using ptr = T*;

// the name 'ptr<T>' is now an alias for pointer to T


ptr<int> ptr_int;

Example
The following example demonstrates how to use an alias template with a custom
allocator—in this case, an integer vector type. You can substitute any type for int to
create a convenient alias to hide the complex parameter lists in your main functional
code. By using the custom allocator throughout your code, you can improve readability
and reduce the risk of introducing bugs caused by typos.

C++
#include <stdlib.h>
#include <new>

template <typename T> struct MyAlloc {


typedef T value_type;

MyAlloc() { }
template <typename U> MyAlloc(const MyAlloc<U>&) { }

bool operator==(const MyAlloc&) const { return true; }


bool operator!=(const MyAlloc&) const { return false; }

T * allocate(const size_t n) const {


if (n == 0) {
return nullptr;
}

if (n > static_cast<size_t>(-1) / sizeof(T)) {


throw std::bad_array_new_length();
}

void * const pv = malloc(n * sizeof(T));

if (!pv) {
throw std::bad_alloc();
}

return static_cast<T *>(pv);


}

void deallocate(T * const p, size_t) const {


free(p);
}
};

#include <vector>
using MyIntVector = std::vector<int, MyAlloc<int>>;

#include <iostream>

int main ()
{
MyIntVector foov = { 1701, 1764, 1664 };

for (auto a: foov) std::cout << a << " ";


std::cout << "\n";

return 0;
}

Output
1701 1764 1664

Typedefs
A typedef declaration introduces a name that, within its scope, becomes a synonym for
the type given by the type-declaration portion of the declaration.

You can use typedef declarations to construct shorter or more meaningful names for
types already defined by the language or for types that you've declared. Typedef names
allow you to encapsulate implementation details that may change.

In contrast to the class , struct , union , and enum declarations, typedef declarations
don't introduce new types; they introduce new names for existing types.

Names declared using typedef occupy the same namespace as other identifiers (except
statement labels). Therefore, they can't use the same identifier as a previously declared
name, except in a class-type declaration. Consider the following example:

C++

// typedef_names1.cpp
// C2377 expected
typedef unsigned long UL; // Declare a typedef name, UL.
int UL; // C2377: redefined.

The name-hiding rules that pertain to other identifiers also govern the visibility of
names declared using typedef . Therefore, the following example is legal in C++:

C++

// typedef_names2.cpp
typedef unsigned long UL; // Declare a typedef name, UL
int main()
{
unsigned int UL; // Redeclaration hides typedef name
}

// typedef UL back in scope

Another instance of name hiding:

C++
// typedef_specifier1.cpp
typedef char FlagType;

int main()
{
}

void myproc( int )


{
int FlagType;
}

When you declare a local-scope identifier by the same name as a typedef , or when you
declare a member of a structure or union in the same scope or in an inner scope, the
type specifier must be specified. For example:

C++

typedef char FlagType;


const FlagType x;

To reuse the FlagType name for an identifier, a structure member, or a union member,
the type must be provided:

C++

const int FlagType; // Type specifier required

It isn't sufficient to say

C++

const FlagType; // Incomplete specification

because the FlagType is taken to be part of the type, not an identifier that's being
redeclared. This declaration is taken to be an illegal declaration, similar to:

C++

int; // Illegal declaration

You can declare any type with typedef , including pointer, function, and array types. You
can declare a typedef name for a pointer to a structure or union type before you define
the structure or union type, as long as the definition has the same visibility as the
declaration.

Examples
One use of typedef declarations is to make declarations more uniform and compact. For
example:

C++

typedef char CHAR; // Character type.


typedef CHAR * PSTR; // Pointer to a string (char *).
PSTR strchr( PSTR source, CHAR target );
typedef unsigned long ulong;
ulong ul; // Equivalent to "unsigned long ul;"

To use typedef to specify fundamental and derived types in the same declaration, you
can separate declarators with commas. For example:

C++

typedef char CHAR, *PSTR;

The following example provides the type DRAWF for a function returning no value and
taking two int arguments:

C++

typedef void DRAWF( int, int );

After the above typedef statement, the declaration

C++

DRAWF box;

would be equivalent to the declaration

C++

void box( int, int );

typedef is often combined with struct to declare and name user-defined types:
C++

// typedef_specifier2.cpp
#include <stdio.h>

typedef struct mystructtag


{
int i;
double f;
} mystruct;

int main()
{
mystruct ms;
ms.i = 10;
ms.f = 0.99;
printf_s("%d %f\n", ms.i, ms.f);
}

Output

10 0.990000

Redeclaration of typedefs
The typedef declaration can be used to redeclare the same name to refer to the same
type. For example:

Source file file1.h :

C++

// file1.h
typedef char CHAR;

Source file file2.h :

C++

// file2.h
typedef char CHAR;

Source file prog.cpp :

C++
// prog.cpp
#include "file1.h"
#include "file2.h" // OK

The file prog.cpp includes two header files, both of which contain typedef declarations
for the name CHAR . As long as both declarations refer to the same type, such
redeclaration is acceptable.

A typedef can't redefine a name that was previously declared as a different type.
Consider this alternative file2.h :

C++

// file2.h
typedef int CHAR; // Error

The compiler issues an error in prog.cpp because of the attempt to redeclare the name
CHAR to refer to a different type. This policy extends to constructs such as:

C++

typedef char CHAR;


typedef CHAR CHAR; // OK: redeclared as same type

typedef union REGS // OK: name REGS redeclared


{ // by typedef name with the
struct wordregs x; // same meaning.
struct byteregs h;
} REGS;

typedefs in C++ vs. C


Use of the typedef specifier with class types is supported largely because of the ANSI C
practice of declaring unnamed structures in typedef declarations. For example, many C
programmers use the following idiom:

C++

// typedef_with_class_types1.cpp
// compile with: /c
typedef struct { // Declare an unnamed structure and give it the
// typedef name POINT.
unsigned x;
unsigned y;
} POINT;
The advantage of such a declaration is that it enables declarations like:

C++

POINT ptOrigin;

instead of:

C++

struct point_t ptOrigin;

In C++, the difference between typedef names and real types (declared with the class ,
struct , union , and enum keywords) is more distinct. Although the C practice of

declaring a nameless structure in a typedef statement still works, it provides no


notational benefits as it does in C.

C++

// typedef_with_class_types2.cpp
// compile with: /c /W1
typedef struct {
int POINT();
unsigned x;
unsigned y;
} POINT;

The preceding example declares a class named POINT using the unnamed class typedef
syntax. POINT is treated as a class name; however, the following restrictions apply to
names introduced this way:

The name (the synonym) can't appear after a class , struct , or union prefix.

The name can't be used as a constructor or destructor name within a class


declaration.

In summary, this syntax doesn't provide any mechanism for inheritance, construction, or
destruction.
using declaration
Article • 08/03/2021 • 5 minutes to read

The using declaration introduces a name into the declarative region in which the using
declaration appears.

Syntax

using [typename] nested-name-specifier unqualified-id ;


using declarator-list ;

Parameters
nested-name-specifier A sequence of namespace, class, or enumeration names and
scope resolution operators (::), terminated by a scope resolution operator. A single
scope resolution operator may be used to introduce a name from the global
namespace. The keyword typename is optional and may be used to resolve dependent
names when introduced into a class template from a base class.

unqualified-id An unqualified id-expression, which may be an identifier, an overloaded


operator name, a user-defined literal operator or conversion function name, a class
destructor name, or a template name and argument list.

declarator-list A comma-separated list of [ typename ] nested-name-specifier unqualified-


id declarators, followed optionally by an ellipsis.

Remarks
A using declaration introduces an unqualified name as a synonym for an entity declared
elsewhere. It allows a single name from a specific namespace to be used without explicit
qualification in the declaration region in which it appears. This is in contrast to the using
directive, which allows all the names in a namespace to be used without qualification.
The using keyword is also used for type aliases.

Example: using declaration in class field


A using declaration can be used in a class definition.
C++

// using_declaration1.cpp
#include <stdio.h>
class B {
public:
void f(char) {
printf_s("In B::f()\n");
}

void g(char) {
printf_s("In B::g()\n");
}
};

class D : B {
public:
using B::f; // B::f(char) is now visible as D::f(char)
using B::g; // B::g(char) is now visible as D::g(char)
void f(int) {
printf_s("In D::f()\n");
f('c'); // Invokes B::f(char) instead of recursing
}

void g(int) {
printf_s("In D::g()\n");
g('c'); // Invokes B::g(char) instead of recursing
}
};

int main() {
D myD;
myD.f(1);
myD.g('a');
}

Output

In D::f()
In B::f()
In B::g()

Example: using declaration to declare a


member
When used to declare a member, a using declaration must refer to a member of a base
class.
C++

// using_declaration2.cpp
#include <stdio.h>

class B {
public:
void f(char) {
printf_s("In B::f()\n");
}

void g(char) {
printf_s("In B::g()\n");
}
};

class C {
public:
int g();
};

class D2 : public B {
public:
using B::f; // ok: B is a base of D2
// using C::g; // error: C isn't a base of D2
};

int main() {
D2 MyD2;
MyD2.f('a');
}

Output

In B::f()

Example: using declaration with explicit


qualification
Members declared by using a using declaration can be referenced by using explicit
qualification. The :: prefix refers to the global namespace.

C++

// using_declaration3.cpp
#include <stdio.h>

void f() {
printf_s("In f\n");
}

namespace A {
void g() {
printf_s("In A::g\n");
}
}

namespace X {
using ::f; // global f is also visible as X::f
using A::g; // A's g is now visible as X::g
}

void h() {
printf_s("In h\n");
X::f(); // calls ::f
X::g(); // calls A::g
}

int main() {
h();
}

Output

In h
In f
In A::g

Example: using declaration synonyms and


aliases
When a using declaration is made, the synonym created by the declaration refers only to
definitions that are valid at the point of the using declaration. Definitions added to a
namespace after the using declaration are not valid synonyms.

A name defined by a using declaration is an alias for its original name. It does not affect
the type, linkage or other attributes of the original declaration.

C++

// post_declaration_namespace_additions.cpp
// compile with: /c
namespace A {
void f(int) {}
}
using A::f; // f is a synonym for A::f(int) only

namespace A {
void f(char) {}
}

void f() {
f('a'); // refers to A::f(int), even though A::f(char) exists
}

void b() {
using A::f; // refers to A::f(int) AND A::f(char)
f('a'); // calls A::f(char);
}

Example: Local declarations and using


declarations
With respect to functions in namespaces, if a set of local declarations and using
declarations for a single name are given in a declarative region, they must all refer to the
same entity, or they must all refer to functions.

C++

// functions_in_namespaces1.cpp
// C2874 expected
namespace B {
int i;
void f(int);
void f(double);
}

void g() {
int i;
using B::i; // error: i declared twice
void f(char);
using B::f; // ok: each f is a function
}

In the example above, the using B::i statement causes a second int i to be declared
in the g() function. The using B::f statement does not conflict with the f(char)
function because the function names introduced by B::f have different parameter
types.
Example: Local function declarations and using
declarations
A local function declaration cannot have the same name and type as a function
introduced by using declaration. For example:

C++

// functions_in_namespaces2.cpp
// C2668 expected
namespace B {
void f(int);
void f(double);
}

namespace C {
void f(int);
void f(double);
void f(char);
}

void h() {
using B::f; // introduces B::f(int) and B::f(double)
using C::f; // C::f(int), C::f(double), and C::f(char)
f('h'); // calls C::f(char)
f(1); // C2668 ambiguous: B::f(int) or C::f(int)?
void f(int); // C2883 conflicts with B::f(int) and C::f(int)
}

Example: using declaration and inheritance


With respect to inheritance, when a using declaration introduces a name from a base
class into a derived class scope, member functions in the derived class override virtual
member functions with the same name and argument types in the base class.

C++

// using_declaration_inheritance1.cpp
#include <stdio.h>
struct B {
virtual void f(int) {
printf_s("In B::f(int)\n");
}

virtual void f(char) {


printf_s("In B::f(char)\n");
}
void g(int) {
printf_s("In B::g\n");
}

void h(int);
};

struct D : B {
using B::f;
void f(int) { // ok: D::f(int) overrides B::f(int)
printf_s("In D::f(int)\n");
}

using B::g;
void g(char) { // ok: there is no B::g(char)
printf_s("In D::g(char)\n");
}

using B::h;
void h(int) {} // Note: D::h(int) hides non-virtual B::h(int)
};

void f(D* pd) {


pd->f(1); // calls D::f(int)
pd->f('a'); // calls B::f(char)
pd->g(1); // calls B::g(int)
pd->g('a'); // calls D::g(char)
}

int main() {
D * myd = new D();
f(myd);
}

Output

In D::f(int)
In B::f(char)
In B::g
In D::g(char)

Example: using declaration accessibility


All instances of a name mentioned in a using declaration must be accessible. In
particular, if a derived class uses a using declaration to access a member of a base class,
the member name must be accessible. If the name is that of an overloaded member
function, then all functions named must be accessible.

For more information on accessibility of members, see Member-Access Control.


C++

// using_declaration_inheritance2.cpp
// C2876 expected
class A {
private:
void f(char);
public:
void f(int);
protected:
void g();
};

class B : public A {
using A::f; // C2876: A::f(char) is inaccessible
public:
using A::g; // B::g is a public synonym for A::g
};

See also
Namespaces
Keywords
volatile (C++)
Article • 09/21/2021 • 3 minutes to read

A type qualifier that you can use to declare that an object can be modified in the
program by the hardware.

Syntax

volatile declarator ;

Remarks
You can use the /volatile compiler switch to modify how the compiler interprets this
keyword.

Visual Studio interprets the volatile keyword differently depending on the target
architecture. For ARM, if no /volatile compiler option is specified, the compiler performs
as if /volatile:iso were specified. For architectures other than ARM, if no /volatile
compiler option is specified, the compiler performs as if /volatile:ms were specified;
therefore, for architectures other than ARM we strongly recommend that you specify
/volatile:iso, and use explicit synchronization primitives and compiler intrinsics when
you are dealing with memory that is shared across threads.

You can use the volatile qualifier to provide access to memory locations that are used
by asynchronous processes such as interrupt handlers.

When volatile is used on a variable that also has the __restrict keyword, volatile
takes precedence.

If a struct member is marked as volatile , then volatile is propagated to the whole


structure. If a structure does not have a length that can be copied on the current
architecture by using one instruction, volatile may be completely lost on that
structure.

The volatile keyword may have no effect on a field if one of the following conditions is
true:
The length of the volatile field exceeds the maximum size that can be copied on
the current architecture by using one instruction.

The length of the outermost containing struct —or if it's a member of a possibly
nested struct —exceeds the maximum size that can be copied on the current
architecture by using one instruction.

Although the processor does not reorder un-cacheable memory accesses, un-cacheable
variables must be marked as volatile to guarantee that the compiler does not reorder
the memory accesses.

Objects that are declared as volatile are not used in certain optimizations because
their values can change at any time. The system always reads the current value of a
volatile object when it is requested, even if a previous instruction asked for a value from
the same object. Also, the value of the object is written immediately on assignment.

ISO conformant
If you are familiar with the C# volatile keyword, or familiar with the behavior of volatile
in earlier versions of the Microsoft C++ compiler (MSVC), be aware that the C++11 ISO
Standard volatile keyword is different and is supported in MSVC when the /volatile:iso
compiler option is specified. (For ARM, it's specified by default). The volatile keyword
in C++11 ISO Standard code is to be used only for hardware access; do not use it for
inter-thread communication. For inter-thread communication, use mechanisms such as
std::atomic<T> from the C++ Standard Library.

End of ISO conformant


Microsoft Specific

When the /volatile:ms compiler option is used—by default when architectures other
than ARM are targeted—the compiler generates extra code to maintain ordering among
references to volatile objects in addition to maintaining ordering to references to other
global objects. In particular:

A write to a volatile object (also known as volatile write) has Release semantics;
that is, a reference to a global or static object that occurs before a write to a
volatile object in the instruction sequence will occur before that volatile write in
the compiled binary.

A read of a volatile object (also known as volatile read) has Acquire semantics; that
is, a reference to a global or static object that occurs after a read of volatile
memory in the instruction sequence will occur after that volatile read in the
compiled binary.

This enables volatile objects to be used for memory locks and releases in multithreaded
applications.

7 Note

When it relies on the enhanced guarantee that's provided when the /volatile:ms
compiler option is used, the code is non-portable.

END Microsoft Specific

See also
Keywords
const
const and volatile Pointers
decltype (C++)
Article • 09/28/2022 • 5 minutes to read

The decltype type specifier yields the type of a specified expression. The decltype type
specifier, together with the auto keyword, is useful primarily to developers who write
template libraries. Use auto and decltype to declare a function template whose return
type depends on the types of its template arguments. Or, use auto and decltype to
declare a function template that wraps a call to another function, and then returns the
return type of the wrapped function.

Syntax
decltype( expression )

Parameters
expression
An expression. For more information, see Expressions.

Return value
The type of the expression parameter.

Remarks
The decltype type specifier is supported in Visual Studio 2010 or later versions, and can
be used with native or managed code. decltype(auto) (C++14) is supported in Visual
Studio 2015 and later.

The compiler uses the following rules to determine the type of the expression
parameter.

If the expression parameter is an identifier or a class member access,


decltype(expression) is the type of the entity named by expression . If there's no

such entity or the expression parameter names a set of overloaded functions, the
compiler yields an error message.
If the expression parameter is a call to a function or an overloaded operator
function, decltype(expression) is the return type of the function. Parentheses
around an overloaded operator are ignored.

If the expression parameter is an rvalue, decltype(expression) is the type of


expression . If the expression parameter is an lvalue, decltype(expression) is an

lvalue reference to the type of expression .

The following code example demonstrates some uses of the decltype type specifier.
First, assume that you've coded the following statements.

C++

int var;
const int&& fx();
struct A { double x; }
const A* a = new A();

Next, examine the types that are returned by the four decltype statements in the
following table.

Statement Type Notes

decltype(fx()); const An rvalue reference to a const int .


int&&

decltype(var); int The type of variable var .

decltype(a->x); double The type of the member access.

decltype((a- const The inner parentheses cause the statement to be evaluated as an


>x)); double& expression instead of a member access. And because a is declared
as a const pointer, the type is a reference to const double .

decltype and auto


In C++14, you can use decltype(auto) with no trailing return type to declare a function
template whose return type depends on the types of its template arguments.

In C++11, you can use the decltype type specifier on a trailing return type, together
with the auto keyword, to declare a function template whose return type depends on
the types of its template arguments. For example, consider the following code example
in which the return type of the function template depends on the types of the template
arguments. In the code example, the UNKNOWN placeholder indicates that the return type
can't be specified.

C++

template<typename T, typename U>


UNKNOWN func(T&& t, U&& u){ return t + u; };

The introduction of the decltype type specifier enables a developer to obtain the type
of the expression that the function template returns. Use the alternative function
declaration syntax that is shown later, the auto keyword, and the decltype type specifier
to declare a late-specified return type. The late-specified return type is determined when
the declaration is compiled, instead of when it's coded.

The following prototype illustrates the syntax of an alternative function declaration. The
const and volatile qualifiers, and the throw exception specification are optional. The
function_body placeholder represents a compound statement that specifies what the

function does. As a best coding practice, the expression placeholder in the decltype
statement should match the expression specified by the return statement, if any, in the
function_body .

auto function_name ( parameters opt ) const opt volatile opt -> decltype( expression
) noexcept opt { function_body };

In the following code example, the late-specified return type of the myFunc function
template is determined by the types of the t and u template arguments. As a best
coding practice, the code example also uses rvalue references and the forward function
template, which support perfect forwarding. For more information, see Rvalue reference
declarator: &&.

C++

//C++11
template<typename T, typename U>
auto myFunc(T&& t, U&& u) -> decltype (forward<T>(t) + forward<U>(u))
{ return forward<T>(t) + forward<U>(u); };

//C++14
template<typename T, typename U>
decltype(auto) myFunc(T&& t, U&& u)
{ return forward<T>(t) + forward<U>(u); };

decltype and forwarding functions (C++11)


Forwarding functions wrap calls to other functions. Consider a function template that
forwards its arguments, or the results of an expression that involves those arguments, to
another function. Furthermore, the forwarding function returns the result of calling the
other function. In this scenario, the return type of the forwarding function should be the
same as the return type of the wrapped function.

In this scenario, you can't write an appropriate type expression without the decltype
type specifier. The decltype type specifier enables generic forwarding functions because
it doesn't lose required information about whether a function returns a reference type.
For a code example of a forwarding function, see the previous myFunc function template
example.

Examples
The following code example declares the late-specified return type of function template
Plus() . The Plus function processes its two operands with the operator+ overload. So,

the interpretation of the plus operator ( + ) and the return type of the Plus function
depends on the types of the function arguments.

C++

// decltype_1.cpp
// compile with: cl /EHsc decltype_1.cpp

#include <iostream>
#include <string>
#include <utility>
#include <iomanip>

using namespace std;

template<typename T1, typename T2>


auto Plus(T1&& t1, T2&& t2) ->
decltype(forward<T1>(t1) + forward<T2>(t2))
{
return forward<T1>(t1) + forward<T2>(t2);
}

class X
{
friend X operator+(const X& x1, const X& x2)
{
return X(x1.m_data + x2.m_data);
}

public:
X(int data) : m_data(data) {}
int Dump() const { return m_data;}
private:
int m_data;
};

int main()
{
// Integer
int i = 4;
cout <<
"Plus(i, 9) = " <<
Plus(i, 9) << endl;

// Floating point
float dx = 4.0;
float dy = 9.5;
cout <<
setprecision(3) <<
"Plus(dx, dy) = " <<
Plus(dx, dy) << endl;

// String
string hello = "Hello, ";
string world = "world!";
cout << Plus(hello, world) << endl;

// Custom type
X x1(20);
X x2(22);
X x3 = Plus(x1, x2);
cout <<
"x3.Dump() = " <<
x3.Dump() << endl;
}

Output

Plus(i, 9) = 13
Plus(dx, dy) = 13.5
Hello, world!
x3.Dump() = 42

Visual Studio 2017 and later: The compiler parses decltype arguments when the
templates are declared rather than instantiated. So, if a non-dependent specialization is
found in the decltype argument, it won't be deferred to instantiation-time; it's
processed immediately and any resulting errors are diagnosed at that time.

The following example shows such a compiler error that is raised at the point of
declaration:

C++
#include <utility>
template <class T, class ReturnT, class... ArgsT> class IsCallable
{
public:
struct BadType {};
template <class U>
static decltype(std::declval<T>()(std::declval<ArgsT>()...)) Test(int);
//C2064. Should be declval<U>
template <class U>
static BadType Test(...);
static constexpr bool value = std::is_convertible<decltype(Test<T>(0)),
ReturnT>::value;
};

constexpr bool test1 = IsCallable<int(), int>::value;


static_assert(test1, "PASS1");
constexpr bool test2 = !IsCallable<int*, int>::value;
static_assert(test2, "PASS2");

Requirements
Visual Studio 2010 or later versions.

decltype(auto) requires Visual Studio 2015 or later.


Attributes in C++
Article • 05/10/2023

The C++ Standard defines a common set of attributes. It also allows compiler vendors to
define their own attributes within a vendor-specific namespace. However, compilers are
only required to recognize the attributes defined in the standard.

In some cases, standard attributes overlap with compiler-specific __declspec


parameters. In Microsoft C++, you can use the [[deprecated]] attribute instead of using
__declspec(deprecated) . The [[deprecated]] attribute is recognized by any conforming
compiler. For all other __declspec parameters such as dllimport and dllexport , so far
there's no attribute equivalent, so you must continue to use __declspec syntax.
Attributes don't affect the type system, and they don't change the meaning of a
program. Compilers ignore attribute values they don't recognize.

Visual Studio 2017 version 15.3 and later (Available with /std:c++17 and later): In the
scope of an attribute list, you can specify the namespace for all names with a single
using introducer:

C++

void g() {
[[using rpr: kernel, target(cpu,gpu)]] // equivalent to [[ rpr::kernel,
rpr::target(cpu,gpu) ]]
do task();
}

C++ standard attributes


In C++11, attributes provide a standardized way to annotate C++ constructs (including
but not limited to classes, functions, variables, and blocks) with additional information.
Attributes may or may not be vendor-specific. A compiler can use this information to
generate informational messages, or to apply special logic when compiling the
attributed code. The compiler ignores any attributes that it doesn't recognize, which
means you can't define your own custom attributes using this syntax. Attributes are
enclosed by double square brackets:

C++

[[deprecated]]
void Foo(int);
Attributes represent a standardized alternative to vendor-specific extensions such as
#pragma directives, __declspec() (Visual C++), or __attribute__ (GNU). However, you'll
still need to use the vendor-specific constructs for most purposes. The standard
currently specifies the following attributes that a conforming compiler should recognize.

[[carries_dependency]]

The [[carries_dependency]] attribute specifies that the function propagates data


dependency ordering for thread synchronization. The attribute can be applied to one or
more parameters, to specify that the passed-in argument carries a dependency into the
function body. The attribute can be applied to the function itself, to specify that the
return value carries a dependency out of the function. The compiler can use this
information to generate more efficient code.

[[deprecated]]

Visual Studio 2015 and later: The [[deprecated]] attribute specifies that a function isn't
intended for use. Or, that it might not exist in future versions of a library interface. The
[[deprecated]] attribute can be applied to declaration of a class, a typedef-name, a
variable, a nonstatic data member, a function, a namespace, an enumeration, an
enumerator, or a template specialization. The compiler can use this attribute to generate
an informational message when client code attempts to call the function. When the
Microsoft C++ compiler detects the use of a [[deprecated]] item, it raises compiler
warning C4996.

[[fallthrough]]

Visual Studio 2017 and later: (Available with /std:c++17 and later.) The [[fallthrough]]
attribute can be used in the context of switch statements as a hint to the compiler (or
anyone reading the code) that the fallthrough behavior is intended. The Microsoft C++
compiler currently doesn't warn on fallthrough behavior, so this attribute has no effect
on compiler behavior.

[[likely]]

Visual Studio 2019 version 16.6 and later: (Available with /std:c++20 and later.) The
[[likely]] attribute specifies a hint to the compiler that the code path for the

attributed label or statement is more likely to execute than alternatives. In the Microsoft
compiler, the [[likely]] attribute marks blocks as "hot code", which increments an
internal optimization score. The score is incremented more when optimizing for speed,
and not as much when optimizing for size. The net score affects the likelihood of
inlining, loop unrolling, and vectorizing optimizations. The effect of [[likely]] and
[[unlikely]] is similar to Profile-guided optimization, but limited in scope to the
current translation unit. The block reordering optimization isn't implemented yet for this
attribute.

[[maybe_unused]]

Visual Studio 2017 version 15.3 and later: (Available with /std:c++17 and later.) The
[[maybe_unused]] attribute specifies that a variable, function, class, typedef, nonstatic

data member, enum, or template specialization may be intentionally unused. The


compiler doesn't warn when an entity marked [[maybe_unused]] isn't used. An entity
that's declared without the attribute can later be redeclared with the attribute and vice-
versa. An entity is considered marked after its first declaration that's marked
[[maybe_unused]] gets analyzed, and for the rest of the current translation unit.

[[nodiscard]]

Visual Studio 2017 version 15.3 and later: (Available with /std:c++17 and later.)
Specifies that a function's return value isn't intended to be discarded. Raises warning
C4834, as shown in this example:

C++

[[nodiscard]]
int foo(int i) { return i * i; }

int main()
{
foo(42); //warning C4834: discarding return value of function with
'nodiscard' attribute
return 0;
}

[[noreturn]]

The [[noreturn]] attribute specifies that a function never returns; in other words, it
always throws an exception or exits. The compiler can adjust its compilation rules for
[[noreturn]] entities.
[[unlikely]]

Visual Studio 2019 version 16.6 and later: (Available with /std:c++20 and later.) The
[[unlikely]] attribute specifies a hint to the compiler that the code path for the
attributed label or statement is less likely to execute than alternatives. In the Microsoft
compiler, the [[unlikely]] attribute marks blocks as "cold code", which decrements an
internal optimization score. The score is decremented more when optimizing for size,
and not as much when optimizing for speed. The net score affects the likelihood of
inlining, loop unrolling, and vectorizing optimizations. The block reordering optimization
isn't implemented yet for this attribute.

Microsoft-specific attributes

[[gsl::suppress(rules)]]

The Microsoft-specific [[gsl::suppress(rules)]] attribute is used to suppress warnings


from checkers that enforce Guidelines Support Library (GSL) rules in code. For
example, consider this code snippet:

C++

int main()
{
int arr[10]; // GSL warning C26494 will be fired
int* p = arr; // GSL warning C26485 will be fired
[[gsl::suppress(bounds.1)]] // This attribute suppresses Bounds rule #1
{
int* q = p + 1; // GSL warning C26481 suppressed
p = q--; // GSL warning C26481 suppressed
}
}

The example raises these warnings:

C26494 (Type Rule 5: Always initialize an object.)

C26485 (Bounds Rule 3: No array to pointer decay.)

C26481 (Bounds Rule 1: Don't use pointer arithmetic. Use span instead.)

The first two warnings fire when you compile this code with the CppCoreCheck code
analysis tool installed and activated. But the third warning doesn't fire because of the
attribute. You can suppress the entire bounds profile by writing
[[gsl::suppress(bounds)]] without including a specific rule number. The C++ Core
Guidelines are designed to help you write better and safer code. The suppress attribute
makes it easy to turn off the warnings when they aren't wanted.

[[msvc::flatten]]

The Microsoft-specific attribute [[msvc::flatten]] is very similar to


[[msvc::forceinline_calls]] , and can be used in the same places and in the same way.

The difference is that [[msvc::flatten]] will [[msvc::forceinline_calls]] all calls in the


scope it's applied to recursively, until no calls are left. This may have consequences for
the resulting code size growth of the function or the throughput of the compiler, which
you must manage manually.

[[msvc::forceinline]]

When placed before a function declaration, the Microsoft-specific attribute


[[msvc::forceinline]] has the same meaning as __forceinline .

[[msvc::forceinline_calls]]

The Microsoft-specific attribute [[msvc::forceinline_calls]] can be placed on or


before a statement or a block. It causes the inline heuristic to attempt to
[[msvc::forceinline]] all calls in that statement or block:

C++

void f() {
[[msvc::forceinline_calls]]
{
foo();
bar();
}
...
[[msvc::forceinline_calls]]
bar();

foo();
}

The first call to foo , and both calls to bar , are treated as if they were declared
__forceinline . The second call to foo isn't treated as __forceinline .

[[msvc::intrinsic]]
The Microsoft-specific [[msvc::intrinsic]] attribute tells the compiler to inline a
metafunction that acts as a named cast from the parameter type to the return type.
When the attribute is present on a function definition, the compiler replaces all calls to
that function with a simple cast. The [[msvc::intrinsic]] attribute is available in Visual
Studio 2022 version 17.5 preview 2 and later versions. This attribute applies only to the
specific function that follows it.

The [[msvc::intrinsic]] attribute has three constraints on the function it's applied to:

The function can't be recursive; its body must only have a return statement with a
cast.
The function can only accept a single parameter.
The /permissive- compiler option is required. (The /std:c++20 and later options
imply /permissive- by default.)

Example

In this sample code, the [[msvc::intrinsic]] attribute applied to the my_move function
makes the compiler replace calls to the function with the inlined static cast in its body:

C++

template <typename T>


[[msvc::intrinsic]] T&& my_move(T&& t) { return static_cast<T&&>(t); }

void f() {
int i = 0;
i = my_move(i);
}

[[msvc::noinline]]

When placed before a function declaration, the Microsoft-specific attribute


[[msvc::noinline]] has the same meaning as declspec(noinline) .

[[msvc::noinline_calls]]

The Microsoft-specific attribute [[msvc::noinline_calls]] has the same usage as


[[msvc::forceinline_calls]] . It can be placed before any statement or block. Rather

than force-inlining all calls in that block, it has the effect of turning off inlining for the
scope it's applied to.
[[msvc::no_tls_guard]]

The Microsoft-specific [[msvc::no_tls_guard]] attribute disables checks for initialization


on first access to thread-local variables in DLLs. The checks are enabled by default in
code built using Visual Studio 2019 version 16.5 and later versions. This attribute applies
only to the specific variable that follows it. To disable checks globally, use the
/Zc:tlsGuards- compiler option.
C++ built-in operators, precedence, and
associativity
Article • 08/03/2021 • 2 minutes to read

The C++ language includes all C operators and adds several new operators. Operators
specify an evaluation to be performed on one or more operands.

Precedence and associativity


Operator precedence specifies the order of operations in expressions that contain more
than one operator. Operator associativity specifies whether, in an expression that
contains multiple operators with the same precedence, an operand is grouped with the
one on its left or the one on its right.

Alternative spellings
C++ specifies alternative spellings for some operators. In C, the alternative spellings are
provided as macros in the <iso646.h> header. In C++, these alternatives are keywords,
and use of <iso646.h> or the C++ equivalent <ciso646> is deprecated. In Microsoft
C++, the /permissive- or /Za compiler option is required to enable the alternative
spellings.

C++ operator precedence and associativity


table
The following table shows the precedence and associativity of C++ operators (from
highest to lowest precedence). Operators with the same precedence number have equal
precedence unless another relationship is explicitly forced by parentheses.

Operator Description Operator Alternative

Group 1 precedence, no associativity

Scope resolution ::

Group 2 precedence, left to right associativity

Member selection (object or pointer) . or ->

Array subscript []
Operator Description Operator Alternative

Function call ()

Postfix increment ++

Postfix decrement --

Type name typeid

Constant type conversion const_cast

Dynamic type conversion dynamic_cast

Reinterpreted type conversion reinterpret_cast

Static type conversion static_cast

Group 3 precedence, right to left associativity

Size of object or type sizeof

Prefix increment ++

Prefix decrement --

One's complement ~ compl

Logical not ! not

Unary negation -

Unary plus +

Address-of &

Indirection *

Create object new

Destroy object delete

Cast ()

Group 4 precedence, left to right associativity

Pointer-to-member (objects or pointers) .* or ->*

Group 5 precedence, left to right associativity

Multiplication *

Division /
Operator Description Operator Alternative

Modulus %

Group 6 precedence, left to right associativity

Addition +

Subtraction -

Group 7 precedence, left to right associativity

Left shift <<

Right shift >>

Group 8 precedence, left to right associativity

Less than <

Greater than >

Less than or equal to <=

Greater than or equal to >=

Group 9 precedence, left to right associativity

Equality ==

Inequality != not_eq

Group 10 precedence left to right associativity

Bitwise AND & bitand

Group 11 precedence, left to right associativity

Bitwise exclusive OR ^ xor

Group 12 precedence, left to right associativity

Bitwise inclusive OR | bitor

Group 13 precedence, left to right associativity

Logical AND && and

Group 14 precedence, left to right associativity

Logical OR || or

Group 15 precedence, right to left associativity


Operator Description Operator Alternative

Conditional ?:

Assignment =

Multiplication assignment *=

Division assignment /=

Modulus assignment %=

Addition assignment +=

Subtraction assignment -=

Left-shift assignment <<=

Right-shift assignment >>=

Bitwise AND assignment &= and_eq

Bitwise inclusive OR assignment |= or_eq

Bitwise exclusive OR assignment ^= xor_eq

throw expression throw

Group 16 precedence, left to right associativity

Comma ,

See also
Operator overloading
alignof operator
Article • 04/22/2022 • 2 minutes to read

The alignof operator returns the alignment in bytes of the specified type as a value of
type size_t .

Syntax
C++

alignof( type )

Remarks
For example:

Expression Value

alignof( char ) 1

alignof( short ) 2

alignof( int ) 4

alignof( long long ) 8

alignof( float ) 4

alignof( double ) 8

The alignof value is the same as the value for sizeof for basic types. Consider,
however, this example:

C++

typedef struct { int a; double b; } S;


// alignof(S) == 8

In this case, the alignof value is the alignment requirement of the largest element in
the structure.

Similarly, for
C++

typedef __declspec(align(32)) struct { int a; } S;

alignof(S) is equal to 32 .

One use for alignof would be as a parameter to one of your own memory-allocation
routines. For example, given the following defined structure S , you could call a
memory-allocation routine named aligned_malloc to allocate memory on a particular
alignment boundary.

C++

typedef __declspec(align(32)) struct { int a; double b; } S;


int n = 50; // array size
S* p = (S*)aligned_malloc(n * sizeof(S), alignof(S));

For more information on modifying alignment, see:

pack
align
__unaligned
/Zp (Struct member alignment)
x64 structure alignment examples

For more information on differences in alignment in code for x86 and x64, see:

Conflicts with the x86 Compiler

Microsoft-specific
alignof and __alignof are synonyms in the Microsoft compiler. Before it became part

of the standard in C++11, the Microsoft-specific __alignof operator provided this


functionality. For maximum portability, you should use the alignof operator instead of
the Microsoft-specific __alignof operator.

For compatibility with previous versions, _alignof is a synonym for __alignof unless
compiler option /Za (Disable language extensions) is specified.

See also
Expressions with Unary Operators
Keywords
__uuidof Operator
Article • 08/03/2021 • 2 minutes to read

Microsoft Specific

Retrieves the GUID attached to the expression.

Syntax
__uuidof ( expression )

Remarks
The expression can be a type name, pointer, reference, or array of that type, a template
specialized on these types, or a variable of these types. The argument is valid as long as
the compiler can use it to find the attached GUID.

A special case of this intrinsic is when either 0 or NULL is supplied as the argument. In
this case, __uuidof will return a GUID made up of zeros.

Use this keyword to extract the GUID attached to:

An object by the uuid extended attribute.

A library block created with the module attribute.

7 Note

In a debug build, __uuidof always initializes an object dynamically (at runtime). In a


release build, __uuidof can statically (at compile time) initialize an object.

For compatibility with previous versions, _uuidof is a synonym for __uuidof unless
compiler option /Za (Disable language extensions) is specified.

Example
The following code (compiled with ole32.lib) will display the uuid of a library block
created with the module attribute:

C++
// expre_uuidof.cpp
// compile with: ole32.lib
#include "stdio.h"
#include "windows.h"

[emitidl];
[module(name="MyLib")];
[export]
struct stuff {
int i;
};

int main() {
LPOLESTR lpolestr;
StringFromCLSID(__uuidof(MyLib), &lpolestr);
wprintf_s(L"%s", lpolestr);
CoTaskMemFree(lpolestr);
}

Comments
In cases where the library name is no longer in scope, you can use __LIBID_ instead of
__uuidof . For example:

C++

StringFromCLSID(__LIBID_, &lpolestr);

END Microsoft Specific

See also
Expressions with Unary Operators
Keywords
Additive Operators: + and -
Article • 08/03/2021 • 2 minutes to read

Syntax

expression + expression
expression - expression

Remarks
The additive operators are:

Addition (+)

Subtraction (-)

These binary operators have left-to-right associativity.

The additive operators take operands of arithmetic or pointer types. The result of the
addition (+) operator is the sum of the operands. The result of the subtraction (-)
operator is the difference between the operands. If one or both of the operands are
pointers, they must be pointers to objects, not to functions. If both operands are
pointers, the results are not meaningful unless both are pointers to objects in the same
array.

Additive operators take operands of arithmetic, integral, and scalar types. These are
defined in the following table.

Types Used with Additive Operators

Type Meaning

arithmetic Integral and floating types are collectively called "arithmetic" types.

integral Types char and int of all sizes (long, short) and enumerations are "integral" types.

scalar Scalar operands are operands of either arithmetic or pointer type.

The legal combinations for these operators are:


arithmetic + arithmetic

scalar + integral

integral + scalar

arithmetic - arithmetic

scalar - scalar

Note that addition and subtraction are not equivalent operations.

If both operands are of arithmetic type, the conversions covered in Standard


Conversions are applied to the operands, and the result is of the converted type.

Example
C++

// expre_Additive_Operators.cpp
// compile with: /EHsc
#include <iostream>
#define SIZE 5
using namespace std;
int main() {
int i = 5, j = 10;
int n[SIZE] = { 0, 1, 2, 3, 4 };
cout << "5 + 10 = " << i + j << endl
<< "5 - 10 = " << i - j << endl;

// use pointer arithmetic on array

cout << "n[3] = " << *( n + 3 ) << endl;


}

Pointer addition
If one of the operands in an addition operation is a pointer to an array of objects, the
other must be of integral type. The result is a pointer that is of the same type as the
original pointer and that points to another array element. The following code fragment
illustrates this concept:

C++

short IntArray[10]; // Objects of type short occupy 2 bytes


short *pIntArray = IntArray;
for( int i = 0; i < 10; ++i )
{
*pIntArray = i;
cout << *pIntArray << "\n";
pIntArray = pIntArray + 1;
}

Although the integral value 1 is added to pIntArray , it does not mean "add 1 to the
address"; rather it means "adjust the pointer to point to the next object in the array" that
happens to be 2 bytes (or sizeof( int ) ) away.

7 Note

Code of the form pIntArray = pIntArray + 1 is rarely found in C++ programs; to


perform an increment, these forms are preferable: pIntArray++ or pIntArray += 1 .

Pointer subtraction
If both operands are pointers, the result of subtraction is the difference (in array
elements) between the operands. The subtraction expression yields a signed integral
result of type ptrdiff_t (defined in the standard include file <stddef.h>).

One of the operands can be of integral type, as long as it is the second operand. The
result of the subtraction is of the same type as the original pointer. The value of the
subtraction is a pointer to the (n - i)th array element, where n is the element pointed to
by the original pointer and i is the integral value of the second operand.

See also
Expressions with Binary Operators
C++ Built-in Operators, Precedence and Associativity
C Additive Operators
Address-of operator: &
Article • 01/05/2022 • 2 minutes to read

Syntax
address-of-expression :
& cast-expression

Remarks
The unary address-of operator ( & ) returns the address of (that is, a pointer to) its
operand. The operand of the address-of operator can be a function designator or an
lvalue that refers to an object that's not a bit field.

The address-of operator can only be applied to certain lvalue expressions: either to
variables of fundamental, structure, class, or union types, or to subscripted array
references. In these expressions, a constant expression (one that doesn't include the
address-of operator) can be added to or subtracted from the address-of expression.

When applied to functions or lvalues, the result of the expression is a pointer type (an
rvalue) derived from the type of the operand. For example, if the operand is of type
char , the result of the expression is of type pointer to char . The address-of operator,
applied to const or volatile objects, evaluates to const type * or volatile type * ,
where type is the type of the original object.

You can only take the address of an overloaded function when it's clear which version of
the function is referenced. For more information about how to obtain the address of a
particular overloaded function, see Function overloading.

When the address-of operator is applied to a qualified name, the result depends on
whether the qualified-name specifies a static member. If so, the result is a pointer to the
type specified in the declaration of the member. For a member that isn't static, the result
is a pointer to the member name of the class indicated by qualified-class-name. For
more information about qualified-class-name, see Primary expressions.

Example: Address of static member


The following code fragment shows how the address-of operator result differs,
depending on whether a class member is static:
C++

// expre_Address_Of_Operator.cpp
// C2440 expected
class PTM {
public:
int iValue;
static float fValue;
};

int main() {
int PTM::*piValue = &PTM::iValue; // OK: non-static
float PTM::*pfValue = &PTM::fValue; // C2440 error: static
float *spfValue = &PTM::fValue; // OK
}

In this example, the expression &PTM::fValue yields type float * instead of type float
PTM::* because fValue is a static member.

Example: Address of a reference type


Applying the address-of operator to a reference type gives the same result as applying
the operator to the object to which the reference is bound. For example:

C++

// expre_Address_Of_Operator2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main() {
double d; // Define an object of type double.
double& rd = d; // Define a reference to the object.

// Obtain and compare their addresses


if( &d == &rd )
cout << "&d equals &rd" << endl;
}

Output

&d equals &rd

Example: Function address as parameter


The following example uses the address-of operator to pass a pointer argument to a
function:

C++

// expre_Address_Of_Operator3.cpp
// compile with: /EHsc
// Demonstrate address-of operator &

#include <iostream>
using namespace std;

// Function argument is pointer to type int


int square( int *n ) {
return (*n) * (*n);
}

int main() {
int mynum = 5;
cout << square( &mynum ) << endl; // pass address of int
}

Output

25

See also
Expressions with unary operators
C++ built-in operators, precedence, and associativity
Lvalue reference declarator: &
Indirection and address-of operators
Assignment operators
Article • 01/25/2023 • 5 minutes to read

Syntax
expression assignment-operator expression

assignment-operator : one of
= *= /= %= += -= <<= >>= &= ^= |=

Remarks
Assignment operators store a value in the object specified by the left operand. There are
two kinds of assignment operations:

simple assignment, in which the value of the second operand is stored in the object
specified by the first operand.

compound assignment, in which an arithmetic, shift, or bitwise operation is


performed before storing the result.

All assignment operators in the following table except the = operator are compound
assignment operators.

Assignment operators table

Operator Meaning

= Store the value of the second operand in the object specified by the first operand
(simple assignment).

*= Multiply the value of the first operand by the value of the second operand; store the
result in the object specified by the first operand.

/= Divide the value of the first operand by the value of the second operand; store the
result in the object specified by the first operand.

%= Take modulus of the first operand specified by the value of the second operand; store
the result in the object specified by the first operand.

+= Add the value of the second operand to the value of the first operand; store the result
in the object specified by the first operand.
Operator Meaning

-= Subtract the value of the second operand from the value of the first operand; store
the result in the object specified by the first operand.

<<= Shift the value of the first operand left the number of bits specified by the value of
the second operand; store the result in the object specified by the first operand.

>>= Shift the value of the first operand right the number of bits specified by the value of
the second operand; store the result in the object specified by the first operand.

&= Obtain the bitwise AND of the first and second operands; store the result in the
object specified by the first operand.

^= Obtain the bitwise exclusive OR of the first and second operands; store the result in
the object specified by the first operand.

|= Obtain the bitwise inclusive OR of the first and second operands; store the result in
the object specified by the first operand.

Operator keywords
Three of the compound assignment operators have keyword equivalents. They are:

Operator Equivalent

&= and_eq

|= or_eq

^= xor_eq

C++ specifies these operator keywords as alternative spellings for the compound
assignment operators. In C, the alternative spellings are provided as macros in the
<iso646.h> header. In C++, the alternative spellings are keywords; use of <iso646.h> or
the C++ equivalent <ciso646> is deprecated. In Microsoft C++, the /permissive- or /Za
compiler option is required to enable the alternative spelling.

Example
C++

// expre_Assignment_Operators.cpp
// compile with: /EHsc
// Demonstrate assignment operators
#include <iostream>
using namespace std;
int main() {
int a = 3, b = 6, c = 10, d = 0xAAAA, e = 0x5555;

a += b; // a is 9
b %= a; // b is 6
c >>= 1; // c is 5
d |= e; // Bitwise--d is 0xFFFF

cout << "a = 3, b = 6, c = 10, d = 0xAAAA, e = 0x5555" << endl


<< "a += b yields " << a << endl
<< "b %= a yields " << b << endl
<< "c >>= 1 yields " << c << endl
<< "d |= e yields " << hex << d << endl;
}

Simple assignment
The simple assignment operator ( = ) causes the value of the second operand to be
stored in the object specified by the first operand. If both objects are of arithmetic types,
the right operand is converted to the type of the left, before storing the value.

Objects of const and volatile types can be assigned to l-values of types that are only
volatile , or that aren't const or volatile .

Assignment to objects of class type ( struct , union , and class types) is performed by a
function named operator= . The default behavior of this operator function is to perform
a bitwise copy; however, this behavior can be modified using overloaded operators. For
more information, see Operator overloading. Class types can also have copy assignment
and move assignment operators. For more information, see Copy constructors and copy
assignment operators and Move constructors and move assignment operators.

An object of any unambiguously derived class from a given base class can be assigned
to an object of the base class. The reverse isn't true because there's an implicit
conversion from derived class to base class, but not from base class to derived class. For
example:

C++

// expre_SimpleAssignment.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class ABase
{
public:
ABase() { cout << "constructing ABase\n"; }
};
class ADerived : public ABase
{
public:
ADerived() { cout << "constructing ADerived\n"; }
};

int main()
{
ABase aBase;
ADerived aDerived;

aBase = aDerived; // OK
aDerived = aBase; // C2679
}

Assignments to reference types behave as if the assignment were being made to the
object to which the reference points.

For class-type objects, assignment is different from initialization. To illustrate how


different assignment and initialization can be, consider the code

C++

UserType1 A;
UserType2 B = A;

The preceding code shows an initializer; it calls the constructor for UserType2 that takes
an argument of type UserType1 . Given the code

C++

UserType1 A;
UserType2 B;

B = A;

the assignment statement

C++

B = A;

can have one of the following effects:

Call the function operator= for UserType2 , provided operator= is provided with a
UserType1 argument.
Call the explicit conversion function UserType1::operator UserType2 , if such a
function exists.

Call a constructor UserType2::UserType2 , provided such a constructor exists, that


takes a UserType1 argument and copies the result.

Compound assignment
The compound assignment operators are shown in the Assignment operators table.
These operators have the form e1 op= e2, where e1 is a non- const modifiable l-value
and e2 is:

an arithmetic type

a pointer, if op is + or -

The e1 op= e2 form behaves as e1 = e1 op e2, but e1 is evaluated only once.

Compound assignment to an enumerated type generates an error message. If the left


operand is of a pointer type, the right operand must be of a pointer type, or it must be a
constant expression that evaluates to 0. When the left operand is of an integral type, the
right operand must not be of a pointer type.

Result of assignment operators


The assignment operators return the value of the object specified by the left operand
after the assignment. The resultant type is the type of the left operand. The result of an
assignment expression is always an l-value. These operators have right-to-left
associativity. The left operand must be a modifiable l-value.

In ANSI C, the result of an assignment expression isn't an l-value. That means the legal
C++ expression (a += b) += c isn't allowed in C.

See also
Expressions with binary operators
C++ built-in operators, precedence, and associativity
C assignment operators
Bitwise AND operator: &
Article • 11/23/2021 • 2 minutes to read

Syntax
and-expression :
equality-expression

and-expression & equality-expression

Remarks
The bitwise AND operator ( & ) compares each bit of the first operand to the
corresponding bit of the second operand. If both bits are 1, the corresponding result bit
is set to 1. Otherwise, the corresponding result bit is set to 0.

Both operands to the bitwise AND operator must have integral types. The usual
arithmetic conversions covered in Standard conversions are applied to the operands.

Operator keyword for &


C++ specifies bitand as an alternative spelling for & . In C, the alternative spelling is
provided as a macro in the <iso646.h> header. In C++, the alternative spelling is a
keyword; use of <iso646.h> or the C++ equivalent <ciso646> is deprecated. In
Microsoft C++, the /permissive- or /Za compiler option is required to enable the
alternative spelling.

Example
C++

// expre_Bitwise_AND_Operator.cpp
// compile with: /EHsc
// Demonstrate bitwise AND
#include <iostream>
using namespace std;
int main() {
unsigned short a = 0xCCCC; // pattern 1100 ...
unsigned short b = 0xAAAA; // pattern 1010 ...

cout << hex << ( a & b ) << endl; // prints "8888", pattern 1000 ...
}
See also
C++ built-in operators, precedence, and associativity
C bitwise operators
Bitwise exclusive OR operator: ^
Article • 08/03/2021 • 2 minutes to read

Syntax
expression ^ expression

Remarks
The bitwise exclusive OR operator ( ^ ) compares each bit of its first operand to the
corresponding bit of its second operand. If the bit in one of the operands is 0 and the
bit in the other operand is 1, the corresponding result bit is set to 1. Otherwise, the
corresponding result bit is set to 0.

Both operands to the operator must have integral types. The usual arithmetic
conversions covered in Standard Conversions are applied to the operands.

For more information on the alternate usage of the ^ character in C++/CLI and
C++/CX, see Handle to Object Operator (^) (C++/CLI and C++/CX).

Operator keyword for ^


C++ specifies xor as an alternative spelling for ^ . In C, the alternative spelling is
provided as a macro in the <iso646.h> header. In C++, the alternative spelling is a
keyword; use of <iso646.h> or the C++ equivalent <ciso646> is deprecated. In
Microsoft C++, the /permissive- or /Za compiler option is required to enable the
alternative spelling.

Example
C++

// expre_Bitwise_Exclusive_OR_Operator.cpp
// compile with: /EHsc
// Demonstrate bitwise exclusive OR
#include <iostream>
using namespace std;
int main() {
unsigned short a = 0x5555; // pattern 0101 ...
unsigned short b = 0xFFFF; // pattern 1111 ...
cout << hex << ( a ^ b ) << endl; // prints "aaaa" pattern 1010 ...
}

See also
C++ built-in operators, precedence, and associativity
Bitwise inclusive OR operator: |
Article • 02/17/2022 • 2 minutes to read

Syntax
expression1 | expression2

Remarks
The bitwise inclusive OR operator ( | ) compares each bit of its first operand to the
corresponding bit of its second operand. If either bit is 1, the corresponding result bit is
set to 1. Otherwise, the corresponding result bit is set to 0.

Both operands to the operator must have integral types. The usual arithmetic
conversions covered in Standard Conversions are applied to the operands.

Operator keyword for |


C++ specifies bitor as an alternative spelling for | . In C, the alternative spelling is
provided as a macro in the <iso646.h> header. In C++, the alternative spelling is a
keyword; use of <iso646.h> or the C++ equivalent <ciso646> is deprecated. In
Microsoft C++, the /permissive- or /Za compiler option is required to enable the
alternative spelling.

Example
C++

// expre_Bitwise_Inclusive_OR_Operator.cpp
// compile with: /EHsc
// Demonstrate bitwise inclusive OR
#include <iostream>
using namespace std;

int main() {
unsigned short a = 0x5555; // pattern 0101 ...
unsigned short b = 0xAAAA; // pattern 1010 ...

cout << hex << ( a | b ) << endl; // prints "ffff" pattern 1111 ...
}
See also
C++ built-in operators, precedence, and associativity
C bitwise operators
Cast operator: ()
Article • 07/01/2022 • 2 minutes to read

A type cast provides a method for explicit conversion of the type of an object in a
specific situation.

Syntax
cast-expression :
unary-expression

( type-name ) cast-expression

Remarks
Any unary expression is considered a cast expression.

The compiler treats cast-expression as type type-name after a type cast has been made.
Casts can be used to convert objects of any scalar type to or from any other scalar type.
Explicit type casts are constrained by the same rules that determine the effects of
implicit conversions. Other restraints on casts may result from the actual sizes or
representation of specific types.

Examples
A standard cast conversion between built-in types:

C++

// expre_CastOperator.cpp
// compile with: /EHsc
// Demonstrate cast operator
#include <iostream>

using namespace std;

int main()
{
double x = 3.1;
int i;
cout << "x = " << x << endl;
i = (int)x; // assign i the integer part of x
cout << "i = " << i << endl;
}
A cast operator defined in a user-defined type:

C++

// expre_CastOperator2.cpp
// The following sample shows how to define and use a cast operator.
#include <string.h>
#include <stdio.h>

class CountedAnsiString
{
public:
// Assume source is not null terminated
CountedAnsiString(const char *pStr, size_t nSize) :
m_nSize(nSize)
{
m_pStr = new char[sizeOfBuffer];

strncpy_s(m_pStr, sizeOfBuffer, pStr, m_nSize);


memset(&m_pStr[m_nSize], '!', 9); // for demonstration purposes.
}

// Various string-like methods...

const char *GetRawBytes() const


{
return(m_pStr);
}

//
// operator to cast to a const char *
//
operator const char *()
{
m_pStr[m_nSize] = '\0';
return(m_pStr);
}

enum
{
sizeOfBuffer = 20
} size;

private:
char *m_pStr;
const size_t m_nSize;
};

int main()
{
const char *kStr = "Excitinggg";
CountedAnsiString myStr(kStr, 8);
const char *pRaw = myStr.GetRawBytes();
printf_s("RawBytes truncated to 10 chars: %.10s\n", pRaw);

const char *pCast = myStr; // or (const char *)myStr;


printf_s("Casted Bytes: %s\n", pCast);

puts("Note that the cast changed the raw internal string");


printf_s("Raw Bytes after cast: %s\n", pRaw);
}

Output

RawBytes truncated to 10 chars: Exciting!!


Casted Bytes: Exciting
Note that the cast changed the raw internal string
Raw Bytes after cast: Exciting

See also
Expressions with unary operators
C++ built-in operators, precedence and associativity
Explicit type conversion operator: ()
Casting operators (C++)
Cast operators (C)
Comma Operator: ,
Article • 08/03/2021 • 2 minutes to read

Allows grouping two statements where one is expected.

Syntax

expression , expression

Remarks
The comma operator has left-to-right associativity. Two expressions separated by a
comma are evaluated left to right. The left operand is always evaluated, and all side
effects are completed before the right operand is evaluated.

Commas can be used as separators in some contexts, such as function argument lists.
Do not confuse the use of the comma as a separator with its use as an operator; the two
uses are completely different.

Consider the expression e1, e2 . The type and value of the expression are the type and
value of e2; the result of evaluating e1 is discarded. The result is an l-value if the right
operand is an l-value.

Where the comma is normally used as a separator (for example in actual arguments to
functions or aggregate initializers), the comma operator and its operands must be
enclosed in parentheses. For example:

C++

func_one( x, y + 2, z );
func_two( (x--, y + 2), z );

In the function call to func_one above, three arguments, separated by commas, are
passed: x , y + 2 , and z . In the function call to func_two , parentheses force the
compiler to interpret the first comma as the sequential-evaluation operator. This
function call passes two arguments to func_two . The first argument is the result of the
sequential-evaluation operation (x--, y + 2) , which has the value and type of the
expression y + 2 ; the second argument is z .
Example
C++

// cpp_comma_operator.cpp
#include <stdio.h>
int main () {
int i = 10, b = 20, c= 30;
i = b, c;
printf("%i\n", i);

i = (b, c);
printf("%i\n", i);
}

Output

20
30

See also
Expressions with Binary Operators
C++ Built-in Operators, Precedence and Associativity
Sequential-Evaluation Operator
Conditional Operator: ?:
Article • 12/06/2021 • 2 minutes to read

Syntax

expression ? expression : expression

Remarks
The conditional operator (? :) is a ternary operator (it takes three operands). The
conditional operator works as follows:

The first operand is implicitly converted to bool . It is evaluated and all side effects
are completed before continuing.

If the first operand evaluates to true (1), the second operand is evaluated.

If the first operand evaluates to false (0), the third operand is evaluated.

The result of the conditional operator is the result of whichever operand is evaluated —
the second or the third. Only one of the last two operands is evaluated in a conditional
expression.

Conditional expressions have right-to-left associativity. The first operand must be of


integral or pointer type. The following rules apply to the second and third operands:

If both operands are of the same type, the result is of that type.

If both operands are of arithmetic or enumeration types, the usual arithmetic


conversions (covered in Standard Conversions) are performed to convert them to a
common type.

If both operands are of pointer types or if one is a pointer type and the other is a
constant expression that evaluates to 0, pointer conversions are performed to
convert them to a common type.

If both operands are of reference types, reference conversions are performed to


convert them to a common type.

If both operands are of type void, the common type is type void.
If both operands are of the same user-defined type, the common type is that type.

If the operands have different types and at least one of the operands has user-
defined type then the language rules are used to determine the common type.
(See warning below.)

Any combinations of second and third operands not in the preceding list are illegal. The
type of the result is the common type, and it is an l-value if both the second and third
operands are of the same type and both are l-values.

2 Warning

If the types of the second and third operands are not identical, then complex type
conversion rules, as specified in the C++ Standard, are invoked. These conversions
may lead to unexpected behavior including construction and destruction of
temporary objects. For this reason, we strongly advise you to either (1) avoid using
user-defined types as operands with the conditional operator or (2) if you do use
user-defined types, then explicitly cast each operand to a common type.

Example
C++

// expre_Expressions_with_the_Conditional_Operator.cpp
// compile with: /EHsc
// Demonstrate conditional operator
#include <iostream>
using namespace std;
int main() {
int i = 1, j = 2;
cout << ( i > j ? i : j ) << " is greater." << endl;
}

See also
C++ Built-in Operators, Precedence and Associativity
Conditional-Expression Operator
delete Operator (C++)
Article • 08/03/2021 • 2 minutes to read

Deallocates a block of memory.

Syntax
[ :: ] delete cast-expression
[ :: ] delete [] cast-expression

Remarks
The cast-expression argument must be a pointer to a block of memory previously
allocated for an object created with the new operator. The delete operator has a result
of type void and therefore does not return a value. For example:

C++

CDialog* MyDialog = new CDialog;


// use MyDialog
delete MyDialog;

Using delete on a pointer to an object not allocated with new gives unpredictable
results. You can, however, use delete on a pointer with the value 0. This provision
means that, when new returns 0 on failure, deleting the result of a failed new operation
is harmless. For more information, see The new and delete Operators.

The new and delete operators can also be used for built-in types, including arrays. If
pointer refers to an array, place empty brackets ( [] ) before pointer :

C++

int* set = new int[100];


//use set[]
delete [] set;

Using the delete operator on an object deallocates its memory. A program that
dereferences a pointer after the object is deleted can have unpredictable results or
crash.
When delete is used to deallocate memory for a C++ class object, the object's
destructor is called before the object's memory is deallocated (if the object has a
destructor).

If the operand to the delete operator is a modifiable l-value, its value is undefined after
the object is deleted.

If the /sdl (Enable additional security checks) compiler option is specified, the operand
to the delete operator is set to an invalid value after the object is deleted.

Using delete
There are two syntactic variants for the delete operator: one for single objects and the
other for arrays of objects. The following code fragment shows how they differ:

C++

// expre_Using_delete.cpp
struct UDType
{
};

int main()
{
// Allocate a user-defined object, UDObject, and an object
// of type double on the free store using the
// new operator.
UDType *UDObject = new UDType;
double *dObject = new double;
// Delete the two objects.
delete UDObject;
delete dObject;
// Allocate an array of user-defined objects on the
// free store using the new operator.
UDType (*UDArr)[7] = new UDType[5][7];
// Use the array syntax to delete the array of objects.
delete [] UDArr;
}

The following two cases produce undefined results: using the array form of delete
( delete [] ) on an object, and using the nonarray form of delete on an array.

Example
For examples of using delete , see new operator.
How delete works
The delete operator invokes the function operator delete.

For objects not of class type (class, struct, or union), the global delete operator is
invoked. For objects of class type, the name of the deallocation function is resolved in
global scope if the delete expression begins with the unary scope resolution operator
( :: ). Otherwise, the delete operator invokes the destructor for an object prior to
deallocating memory (if the pointer is not null). The delete operator can be defined on a
per-class basis; if there is no such definition for a given class, the global operator delete
is invoked. If the delete expression is used to deallocate a class object whose static type
has a virtual destructor, the deallocation function is resolved through the virtual
destructor of the dynamic type of the object.

See also
Expressions with Unary Operators
Keywords
new and delete Operators
Equality operators: == and !=
Article • 08/03/2021 • 2 minutes to read

Syntax
expression == expression
expression != expression

Remarks
The binary equality operators compare their operands for strict equality or inequality.

The equality operators, equal to ( == ) and not equal to ( != ), have lower precedence than
the relational operators, but they behave similarly. The result type for these operators is
bool .

The equal-to operator ( == ) returns true if both operands have the same value;
otherwise, it returns false . The not-equal-to operator ( != ) returns true if the operands
don't have the same value; otherwise, it returns false .

Operator keyword for !=


C++ specifies not_eq as an alternative spelling for != . (There's no alternative spelling
for == .) In C, the alternative spelling is provided as a macro in the <iso646.h> header. In
C++, the alternative spelling is a keyword; use of <iso646.h> or the C++ equivalent
<ciso646> is deprecated. In Microsoft C++, the /permissive- or /Za compiler option is
required to enable the alternative spelling.

Example
C++

// expre_Equality_Operators.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;

int main() {
cout << boolalpha
<< "The true expression 3 != 2 yields: "
<< (3 != 2) << endl
<< "The false expression 20 == 10 yields: "
<< (20 == 10) << endl;
}

Equality operators can compare pointers to members of the same type. In such a
comparison, pointer-to-member conversions are performed. Pointers to members can
also be compared to a constant expression that evaluates to 0.

See also
Expressions with binary operators
C++ built-in operators, precedence; and associativity
C relational and equality operators
Explicit Type Conversion Operator: ()
Article • 08/03/2021 • 2 minutes to read

C++ allows explicit type conversion using syntax similar to the function-call syntax.

Syntax

simple-type-name ( expression-list )

Remarks
A simple-type-name followed by an expression-list enclosed in parentheses constructs an
object of the specified type using the specified expressions. The following example
shows an explicit type conversion to type int:

C++

int i = int( d );

The following example shows a Point class.

Example
C++

// expre_Explicit_Type_Conversion_Operator.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;


class Point
{
public:
// Define default constructor.
Point() { _x = _y = 0; }
// Define another constructor.
Point( int X, int Y ) { _x = X; _y = Y; }

// Define "accessor" functions as


// reference types.
unsigned& x() { return _x; }
unsigned& y() { return _y; }
void Show() { cout << "x = " << _x << ", "
<< "y = " << _y << "\n"; }
private:
unsigned _x;
unsigned _y;
};

int main()
{
Point Point1, Point2;

// Assign Point1 the explicit conversion


// of ( 10, 10 ).
Point1 = Point( 10, 10 );

// Use x() as an l-value by assigning an explicit


// conversion of 20 to type unsigned.
Point1.x() = unsigned( 20 );
Point1.Show();

// Assign Point2 the default Point object.


Point2 = Point();
Point2.Show();
}

Output
Output

x = 20, y = 10
x = 0, y = 0

Although the preceding example demonstrates explicit type conversion using constants,
the same technique works to perform these conversions on objects. The following code
fragment demonstrates this:

C++

int i = 7;
float d;

d = float( i );

Explicit type conversions can also be specified using the "cast" syntax. The previous
example, rewritten using the cast syntax, is:

C++
d = (float)i;

Both cast and function-style conversions have the same results when converting from
single values. However, in the function-style syntax, you can specify more than one
argument for conversion. This difference is important for user-defined types. Consider a
Point class and its conversions:

C++

struct Point
{
Point( short x, short y ) { _x = x; _y = y; }
...
short _x, _y;
};
...
Point pt = Point( 3, 10 );

The preceding example, which uses function-style conversion, shows how to convert two
values (one for x and one for y) to the user-defined type Point .

U Caution

Use the explicit type conversions with care, since they override the C++ compiler's
built-in type checking.

The cast notation must be used for conversions to types that do not have a simple-type-
name (pointer or reference types, for example). Conversion to types that can be
expressed with a simple-type-name can be written in either form.

Type definition within casts is illegal.

See also
Postfix Expressions
C++ Built-in Operators, Precedence and Associativity
Function Call Operator: ()
Article • 08/03/2021 • 3 minutes to read

A function call is a kind of postfix-expression , formed by an expression that evaluates


to a function or callable object followed by the function-call operator, () . An object can
declare an operator () function, which provides function call semantics for the object.

Syntax
postfix-expression :

postfix-expression ( argument-expression-list opt )

Remarks
The arguments to the function-call operator come from an argument-expression-list , a
comma-separated list of expressions. The values of these expressions are passed to the
function as arguments. The argument-expression-list can be empty. Before C++ 17, the
order of evaluation of the function expression and the argument expressions is
unspecified and may occur in any order. In C++17 and later, the function expression is
evaluated before any argument expressions or default arguments. The argument
expressions are evaluated in an indeterminate sequence.

The postfix-expression evaluates to the function to call. It can take any of several
forms:

a function identifier, visible in the current scope or in the scope of any of the
function arguments provided,
an expression that evaluates to a function, a function pointer, a callable object, or
to a reference to one,
a member function accessor, either explicit or implied,
a dereferenced pointer to a member function.

The postfix-expression may be an overloaded function identifier or overloaded


member function accessor. The rules for overload resolution determine the actual
function to call. If the member function is virtual, the function to call is determined at
run time.

Some example declarations:

Function returning type T . An example declaration is


C++

T func( int i );

Pointer to a function returning type T . An example declaration is

C++

T (*func)( int i );

Reference to a function returning type T . An example declaration is

C++

T (&func)(int i);

Pointer-to-member function dereference returning type T . Example function calls


are

C++

(pObject->*pmf)();
(Object.*pmf)();

Example
The following example calls the standard library function strcat_s with three
arguments:

C++

// expre_Function_Call_Operator.cpp
// compile with: /EHsc

#include <iostream>
#include <string>

// C++ Standard Library name space


using namespace std;

int main()
{
enum
{
sizeOfBuffer = 20
};

char s1[ sizeOfBuffer ] = "Welcome to ";


char s2[ ] = "C++";

strcat_s( s1, sizeOfBuffer, s2 );

cout << s1 << endl;


}

Output

Welcome to C++

Function call results


A function call evaluates to an rvalue unless the function is declared as a reference type.
Functions with reference return types evaluate to lvalues. These functions can be used
on the left side of an assignment statement, as seen here:

C++

// expre_Function_Call_Results.cpp
// compile with: /EHsc
#include <iostream>
class Point
{
public:
// Define "accessor" functions as
// reference types.
unsigned& x() { return _x; }
unsigned& y() { return _y; }
private:
unsigned _x;
unsigned _y;
};

using namespace std;


int main()
{
Point ThePoint;

ThePoint.x() = 7; // Use x() as an l-value.


unsigned y = ThePoint.y(); // Use y() as an r-value.

// Use x() and y() as r-values.


cout << "x = " << ThePoint.x() << "\n"
<< "y = " << ThePoint.y() << "\n";
}
The preceding code defines a class called Point , which contains private data objects
that represent x and y coordinates. These data objects must be modified and their
values retrieved. This program is only one of several designs for such a class; use of the
GetX and SetX or GetY and SetY functions is another possible design.

Functions that return class types, pointers to class types, or references to class types can
be used as the left operand to member-selection operators. The following code is legal:

C++

// expre_Function_Results2.cpp
class A {
public:
A() {}
A(int i) {}
int SetA( int i ) {
return (I = i);
}

int GetA() {
return I;
}

private:
int I;
};

A func1() {
A a = 0;
return a;
}

A* func2() {
A *a = new A();
return a;
}

A& func3() {
A *a = new A();
A &b = *a;
return b;
}

int main() {
int iResult = func1().GetA();
func2()->SetA( 3 );
func3().SetA( 7 );
}

Functions can be called recursively. For more information about function declarations,
see Functions. Related material is in Translation units and linkage.
See also
Postfix expressions
C++ built-in operators, precedence, and associativity
Function call
Indirection Operator: *
Article • 08/03/2021 • 2 minutes to read

Syntax

* cast-expression

Remarks
The unary indirection operator (*) dereferences a pointer; that is, it converts a pointer
value to an l-value. The operand of the indirection operator must be a pointer to a type.
The result of the indirection expression is the type from which the pointer type is
derived. The use of the * operator in this context is different from its meaning as a
binary operator, which is multiplication.

If the operand points to a function, the result is a function designator. If it points to a


storage location, the result is an l-value designating the storage location.

The indirection operator may be used cumulatively to dereference pointers to pointers.


For example:

C++

// expre_Indirection_Operator.cpp
// compile with: /EHsc
// Demonstrate indirection operator
#include <iostream>
using namespace std;
int main() {
int n = 5;
int *pn = &n;
int **ppn = &pn;

cout << "Value of n:\n"


<< "direct value: " << n << endl
<< "indirect value: " << *pn << endl
<< "doubly indirect value: " << **ppn << endl
<< "address of n: " << pn << endl
<< "address of n via indirection: " << *ppn << endl;
}
If the pointer value is invalid, the result is undefined. The following list includes some of
the most common conditions that invalidate a pointer value.

The pointer is a null pointer.

The pointer specifies the address of a local item that is not visible at the time of
the reference.

The pointer specifies an address that is inappropriately aligned for the type of the
object pointed to.

The pointer specifies an address not used by the executing program.

See also
Expressions with Unary Operators
C++ Built-in Operators, Precedence and Associativity
Address-of Operator: &
Indirection and Address-of Operators
Left shift and right shift operators ( <<
and >> )
Article • 03/13/2023 • 5 minutes to read

The bitwise shift operators are the right-shift operator ( >> ), which moves the bits of an
integer or enumeration type expression to the right, and the left-shift operator ( << ),
which moves the bits to the left. 1

Syntax
shift-expression :
additive-expression

shift-expression << additive-expression

shift-expression >> additive-expression

Remarks

) Important

The following descriptions and examples are valid on Windows for x86 and x64
architectures. The implementation of left-shift and right-shift operators is
significantly different on Windows for ARM devices. For more information, see the
"Shift Operators" section of the Hello ARM blog post.

Left Shifts
The left-shift operator causes the bits in shift-expression to be shifted to the left by
the number of positions specified by additive-expression . The bit positions that have
been vacated by the shift operation are zero-filled. A left shift is a logical shift (the bits
that are shifted off the end are discarded, including the sign bit). For more information
about the kinds of bitwise shifts, see Bitwise shifts .

The following example shows left-shift operations using unsigned numbers. The
example shows what is happening to the bits by representing the value as a bitset. For
more information, see bitset Class.

C++
#include <iostream>
#include <bitset>

using namespace std;

int main() {
unsigned short short1 = 4;
bitset<16> bitset1{short1}; // the bitset representation of 4
cout << bitset1 << endl; // 0b00000000'00000100

unsigned short short2 = short1 << 1; // 4 left-shifted by 1 = 8


bitset<16> bitset2{short2};
cout << bitset2 << endl; // 0b00000000'00001000

unsigned short short3 = short1 << 2; // 4 left-shifted by 2 = 16


bitset<16> bitset3{short3};
cout << bitset3 << endl; // 0b00000000'00010000
}

If you left-shift a signed number so that the sign bit is affected, the result is undefined.
The following example shows what happens when a 1 bit is left-shifted into the sign bit
position.

C++

#include <iostream>
#include <bitset>

using namespace std;

int main() {
short short1 = 16384;
bitset<16> bitset1(short1);
cout << bitset1 << endl; // 0b01000000'00000000

short short3 = short1 << 1;


bitset<16> bitset3(short3); // 16384 left-shifted by 1 = -32768
cout << bitset3 << endl; // 0b10000000'00000000

short short4 = short1 << 14;


bitset<16> bitset4(short4); // 4 left-shifted by 14 = 0
cout << bitset4 << endl; // 0b00000000'00000000
}

Right Shifts
The right-shift operator causes the bit pattern in shift-expression to be shifted to the
right by the number of positions specified by additive-expression . For unsigned
numbers, the bit positions that have been vacated by the shift operation are zero-filled.
For signed numbers, the sign bit is used to fill the vacated bit positions. In other words,
if the number is positive, 0 is used, and if the number is negative, 1 is used.

) Important

The result of a right-shift of a signed negative number is implementation-


dependent. Although the Microsoft C++ compiler uses the sign bit to fill vacated
bit positions, there is no guarantee that other implementations also do so.

This example shows right-shift operations using unsigned numbers:

C++

#include <iostream>
#include <bitset>

using namespace std;

int main() {
unsigned short short11 = 1024;
bitset<16> bitset11{short11};
cout << bitset11 << endl; // 0b00000100'00000000

unsigned short short12 = short11 >> 1; // 512


bitset<16> bitset12{short12};
cout << bitset12 << endl; // 0b00000010'00000000

unsigned short short13 = short11 >> 10; // 1


bitset<16> bitset13{short13};
cout << bitset13 << endl; // 0b00000000'00000001

unsigned short short14 = short11 >> 11; // 0


bitset<16> bitset14{short14};
cout << bitset14 << endl; // 0b00000000'00000000
}

The next example shows right-shift operations with positive signed numbers.

C++

#include <iostream>
#include <bitset>

using namespace std;

int main() {
short short1 = 1024;
bitset<16> bitset1(short1);
cout << bitset1 << endl; // 0b00000100'00000000

short short2 = short1 >> 1; // 512


bitset<16> bitset2(short2);
cout << bitset2 << endl; // 0b00000010'00000000

short short3 = short1 >> 11; // 0


bitset<16> bitset3(short3);
cout << bitset3 << endl; // 0b00000000'00000000
}

The next example shows right-shift operations with negative signed integers.

C++

#include <iostream>
#include <bitset>

using namespace std;

int main() {
short neg1 = -16;
bitset<16> bn1(neg1);
cout << bn1 << endl; // 0b11111111'11110000

short neg2 = neg1 >> 1; // -8


bitset<16> bn2(neg2);
cout << bn2 << endl; // 0b11111111'11111000

short neg3 = neg1 >> 2; // -4


bitset<16> bn3(neg3);
cout << bn3 << endl; // 0b11111111'11111100

short neg4 = neg1 >> 4; // -1


bitset<16> bn4(neg4);
cout << bn4 << endl; // 0b11111111'11111111

short neg5 = neg1 >> 5; // -1


bitset<16> bn5(neg5);
cout << bn5 << endl; // 0b11111111'11111111
}

Shifts and promotions


The expressions on both sides of a shift operator must be integral types. Integral
promotions are performed according to the rules described in Standard Conversions.
The type of the result is the same as the type of the promoted shift-expression .

In the following example, a variable of type char is promoted to an int .


C++

#include <iostream>
#include <typeinfo>

using namespace std;

int main() {
char char1 = 'a';

auto promoted1 = char1 << 1; // 194


cout << typeid(promoted1).name() << endl; // int

auto promoted2 = char1 << 10; // 99328


cout << typeid(promoted2).name() << endl; // int
}

Details
The result of a shift operation is undefined if additive-expression is negative or if
additive-expression is greater than or equal to the number of bits in the (promoted)
shift-expression . No shift operation takes place if additive-expression is 0.

C++

#include <iostream>
#include <bitset>

using namespace std;

int main() {
unsigned int int1 = 4;
bitset<32> b1{int1};
cout << b1 << endl; // 0b00000000'00000000'00000000'00000100

unsigned int int2 = int1 << -3; // C4293: '<<' : shift count negative
or too big, undefined behavior
unsigned int int3 = int1 >> -3; // C4293: '>>' : shift count negative
or too big, undefined behavior
unsigned int int4 = int1 << 32; // C4293: '<<' : shift count negative
or too big, undefined behavior
unsigned int int5 = int1 >> 32; // C4293: '>>' : shift count negative
or too big, undefined behavior
unsigned int int6 = int1 << 0;
bitset<32> b6{int6};
cout << b6 << endl; // 0b00000000'00000000'00000000'00000100 (no
change)
}
Footnotes
1
The following is the description of the shift operators in the C++11 ISO specification
(INCITS/ISO/IEC 14882-2011[2012]), sections 5.8.2 and 5.8.3.

The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If
E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more

than the maximum value representable in the result type. Otherwise, if E1 has a signed
type and non-negative value, and E1 × 2E2 is representable in the corresponding
unsigned type of the result type, then that value, converted to the result type, is the
resulting value; otherwise, the behavior is undefined.

The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or


if E1 has a signed type and a non-negative value, the value of the result is the integral
part of the quotient of E1/2E2. If E1 has a signed type and a negative value, the resulting
value is implementation-defined.

See also
Expressions with binary operators
C++ built-in operators, precedence, and associativity
Logical AND operator: &&
Article • 11/23/2021 • 2 minutes to read

Syntax
logical-and-expression :
equality-expression

logical-and-expression && equality-expression

Remarks
The logical AND operator ( && ) returns true if both operands are true and returns
false otherwise. The operands are implicitly converted to type bool before evaluation,

and the result is of type bool . Logical AND has left-to-right associativity.

The operands to the logical AND operator don't need to have the same type, but they
must have boolean, integral, or pointer type. The operands are commonly relational or
equality expressions.

The first operand is completely evaluated and all side effects are completed before
evaluation of the logical AND expression continues.

The second operand is evaluated only if the first operand evaluates to true (nonzero).
This evaluation eliminates needless evaluation of the second operand when the logical
AND expression is false . You can use this short-circuit evaluation to prevent null-
pointer dereferencing, as shown in the following example:

C++

char *pch = 0;
// ...
(pch) && (*pch = 'a');

If pch is null (0), the right side of the expression is never evaluated. This short-circuit
evaluation makes the assignment through a null pointer impossible.

Operator keyword for &&


C++ specifies and as an alternative spelling for && . In C, the alternative spelling is
provided as a macro in the <iso646.h> header. In C++, the alternative spelling is a
keyword; use of <iso646.h> or the C++ equivalent <ciso646> is deprecated. In
Microsoft C++, the /permissive- or /Za compiler option is required to enable the
alternative spelling.

Example
C++

// expre_Logical_AND_Operator.cpp
// compile with: /EHsc
// Demonstrate logical AND
#include <iostream>

using namespace std;

int main() {
int a = 5, b = 10, c = 15;
cout << boolalpha
<< "The true expression "
<< "a < b && b < c yields "
<< (a < b && b < c) << endl
<< "The false expression "
<< "a > b && b < c yields "
<< (a > b && b < c) << endl;
}

See also
C++ built-in operators, precedence, and associativity
C logical operators
Logical negation operator: !
Article • 08/03/2021 • 2 minutes to read

Syntax
! cast-expression

Remarks
The logical negation operator ( ! ) reverses the meaning of its operand. The operand
must be of arithmetic or pointer type (or an expression that evaluates to arithmetic or
pointer type). The operand is implicitly converted to type bool . The result is true if the
converted operand is false ; the result is false if the converted operand is true . The
result is of type bool .

For an expression e , the unary expression !e is equivalent to the expression (e == 0) ,


except where overloaded operators are involved.

Operator keyword for !


C++ specifies not as an alternative spelling for ! . In C, the alternative spelling is
provided as a macro in the <iso646.h> header. In C++, the alternative spelling is a
keyword; use of <iso646.h> or the C++ equivalent <ciso646> is deprecated. In
Microsoft C++, the /permissive- or /Za compiler option is required to enable the
alternative spelling.

Example
C++

// expre_Logical_NOT_Operator.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

int main() {
int i = 0;
if (!i)
cout << "i is zero" << endl;
}
See also
Expressions with unary operators
C++ built-in operators, precedence, and associativity
Unary arithmetic operators
Logical OR operator: ||
Article • 02/17/2022 • 2 minutes to read

Syntax
logical-or-expression || logical-and-expression

Remarks
The logical OR operator ( || ) returns the boolean value true if either or both operands
is true and returns false otherwise. The operands are implicitly converted to type bool
before evaluation, and the result is of type bool . Logical OR has left-to-right
associativity.

The operands to the logical OR operator don't have to have the same type, but they
must be of boolean, integral, or pointer type. The operands are commonly relational or
equality expressions.

The first operand is completely evaluated and all side effects are completed before
continuing evaluation of the logical OR expression.

The second operand is evaluated only if the first operand evaluates to false , because
evaluation isn't needed when the logical OR expression is true . It's known as short-
circuit evaluation.

C++

printf( "%d" , (x == w || x == y || x == z) );

In the above example, if x is equal to either w , y , or z , the second argument to the


printf function evaluates to true , which is then promoted to an integer, and the value
1 is printed. Otherwise, it evaluates to false and the value 0 is printed. As soon as one
of the conditions evaluates to true , evaluation stops.

Operator keyword for ||


C++ specifies or as an alternative spelling for || . In C, the alternative spelling is
provided as a macro in the <iso646.h> header. In C++, the alternative spelling is a
keyword; use of <iso646.h> or the C++ equivalent <ciso646> is deprecated. In
Microsoft C++, the /permissive- or /Za compiler option is required to enable the
alternative spelling.

Example
C++

// expre_Logical_OR_Operator.cpp
// compile with: /EHsc
// Demonstrate logical OR
#include <iostream>
using namespace std;
int main() {
int a = 5, b = 10, c = 15;
cout << boolalpha
<< "The true expression "
<< "a < b || b > c yields "
<< (a < b || b > c) << endl
<< "The false expression "
<< "a > b || b > c yields "
<< (a > b || b > c) << endl;
}

See also
C++ built-in operators, precedence, and associativity
C logical operators
Member access operators: . and ->
Article • 12/08/2021 • 2 minutes to read

Syntax
postfix-expression :
postfix-expression . template opt id-expression

postfix-expression -> template opt id-expression

Remarks
The member access operators . and -> are used to refer to members of struct , union ,
and class types. Member access expressions have the value and type of the selected
member.

There are two forms of member access expressions:

1. In the first form, postfix-expression represents a value of struct , class , or union


type, and id-expression names a member of the specified struct , union , or
class . The value of the operation is that of id-expression and is an l-value if

postfix-expression is an l-value.

2. In the second form, postfix-expression represents a pointer to a struct , union ,


or class , and id-expression names a member of the specified struct , union , or
class . The value is that of id-expression and is an l-value. The -> operator
dereferences the pointer. The expressions e->member and (*(e)).member (where e
represents a pointer) yield identical results (except when the operators -> or * are
overloaded).

Example
The following example demonstrates both forms of the member access operator.

C++

// expre_Selection_Operator.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
struct Date {
Date(int i, int j, int k) : day(i), month(j), year(k){}
int month;
int day;
int year;
};

int main() {
Date mydate(1,1,1900);
mydate.month = 2;
cout << mydate.month << "/" << mydate.day
<< "/" << mydate.year << endl;

Date *mydate2 = new Date(1,1,2000);


mydate2->month = 2;
cout << mydate2->month << "/" << mydate2->day
<< "/" << mydate2->year << endl;
delete mydate2;
}

Output

2/1/1900
2/1/2000

See also
Postfix expressions
C++ built-in operators, precedence, and associativity
Classes and Structs
Structure and union members
Multiplicative Operators and the
Modulus Operator
Article • 08/03/2021 • 2 minutes to read

Syntax

expression * expression
expression / expression
expression % expression

Remarks
The multiplicative operators are:

Multiplication (*)

Division (/)

Modulus (remainder from division) (%)

These binary operators have left-to-right associativity.

The multiplicative operators take operands of arithmetic types. The modulus operator
(%) has a stricter requirement in that its operands must be of integral type. (To get the
remainder of a floating-point division, use the run-time function, fmod.) The conversions
covered in Standard Conversions are applied to the operands, and the result is of the
converted type.

The multiplication operator yields the result of multiplying the first operand by the
second.

The division operator yields the result of dividing the first operand by the second.

The modulus operator yields the remainder given by the following expression, where e1
is the first operand and e2 is the second: e1 - (e1 / e2) * e2, where both operands are of
integral types.

Division by 0 in either a division or a modulus expression is undefined and causes a run-


time error. Therefore, the following expressions generate undefined, erroneous results:
C++

i % 0
f / 0.0

If both operands to a multiplication, division, or modulus expression have the same sign,
the result is positive. Otherwise, the result is negative. The result of a modulus
operation's sign is implementation-defined.

7 Note

Since the conversions performed by the multiplicative operators do not provide for
overflow or underflow conditions, information may be lost if the result of a
multiplicative operation cannot be represented in the type of the operands after
conversion.

Microsoft Specific

In Microsoft C++, the result of a modulus expression is always the same as the sign of
the first operand.

END Microsoft Specific

If the computed division of two integers is inexact and only one operand is negative, the
result is the largest integer (in magnitude, disregarding the sign) that is less than the
exact value the division operation would yield. For example, the computed value of -11 /
3 is -3.666666666. The result of that integral division is -3.

The relationship between the multiplicative operators is given by the identity (e1 / e2) *
e2 + e1 % e2 == e1.

Example
The following program demonstrates the multiplicative operators. Note that either
operand of 10 / 3 must be explicitly cast to type float to avoid truncation so that both
operands are of type float before division.

C++

// expre_Multiplicative_Operators.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main() {
int x = 3, y = 6, z = 10;
cout << "3 * 6 is " << x * y << endl
<< "6 / 3 is " << y / x << endl
<< "10 % 3 is " << z % x << endl
<< "10 / 3 is " << (float) z / x << endl;
}

See also
Expressions with Binary Operators
C++ Built-in Operators, Precedence and Associativity
C Multiplicative Operators
new operator (C++)
Article • 01/05/2022 • 8 minutes to read

Attempts to allocate and initialize an object or array of objects of a specified or


placeholder type, and returns a suitably typed, nonzero pointer to the object (or to the
initial object of the array).

Syntax
new-expression :

:: opt new new-placement opt new-type-id new-initializer opt

:: opt new new-placement opt ( type-id ) new-initializer opt

new-placement :

( expression-list )

new-type-id :

type-specifier-seq new-declarator opt

new-declarator :
ptr-operator new-declarator opt

noptr-new-declarator

noptr-new-declarator :

[ expression ] attribute-specifier-seq opt


noptr-new-declarator [ constant-expression ] attribute-specifier-seq opt

new-initializer :

( expression-list opt )
braced-init-list

Remarks
If unsuccessful, new returns zero or throws an exception. For more information, see The
new and delete Operators. You can change this default behavior by writing a custom
exception-handling routine and calling the _set_new_handler run-time library function
with your function name as its argument.

For information on how to create an object on the managed heap in C++/CLI and
C++/CX, see gcnew.
7 Note

Microsoft C++ Component Extensions (C++/CX) provides support for the new
keyword to add vtable slot entries. For more information, see new (new slot in
vtable)

When new is used to allocate memory for a C++ class object, the object's constructor is
called after the memory is allocated.

Use the delete operator to deallocate the memory allocated by the new operator. Use
the delete[] operator to delete an array allocated by the new operator.

The following example allocates and then frees a two-dimensional array of characters of
size dim by 10. When allocating a multidimensional array, all dimensions except the first
must be constant expressions that evaluate to positive values. The leftmost array
dimension can be any expression that evaluates to a positive value. When allocating an
array using the new operator, the first dimension can be zero; the new operator returns a
unique pointer.

C++

char (*pchar)[10] = new char[dim][10];


delete [] pchar;

The type-id can't contain const , volatile , class declarations, or enumeration


declarations. The following expression is ill-formed:

C++

volatile char *vch = new volatile char[20];

The new operator doesn't allocate reference types because they're not objects.

The new operator can't be used to allocate a function, but it can be used to allocate
pointers to functions. The following example allocates and then frees an array of seven
pointers to functions that return integers.

C++

int (**p) () = new (int (*[7]) ());


delete p;
If you use the operator new without any extra arguments, and compile with the /GX,
/EHa, or /EHs option, the compiler generates code to call operator delete if the
constructor throws an exception.

The following list describes the grammar elements of new :

new-placement

Provides a way of passing extra arguments if you overload new .

type-id
Specifies the type to be allocated; it can be either a built-in or user-defined type. If the
type specification is complicated, it can be surrounded by parentheses to force the order
of binding. The type may be a placeholder ( auto ) whose type is determined by the
compiler.

new-initializer
Provides a value for the initialized object. Initializers can't be specified for arrays. The
new operator will create arrays of objects only if the class has a default constructor.

noptr-new-declarator

Specifies the bounds of an array. When allocating a multidimensional array, all


dimensions except the first must be constant expressions that evaluate to positive
values convertible to std::size_t . The leftmost array dimension can be any expression
that evaluates to a positive value. The attribute-specifier-seq applies to the
associated array type.

Example: Allocate and free a character array


The following code example allocates a character array and an object of class CName and
then frees them.

C++

// expre_new_Operator.cpp
// compile with: /EHsc
#include <string.h>

class CName {
public:
enum {
sizeOfBuffer = 256
};

char m_szFirst[sizeOfBuffer];
char m_szLast[sizeOfBuffer];
public:
void SetName(char* pszFirst, char* pszLast) {
strcpy_s(m_szFirst, sizeOfBuffer, pszFirst);
strcpy_s(m_szLast, sizeOfBuffer, pszLast);
}

};

int main() {
// Allocate memory for the array
char* pCharArray = new char[CName::sizeOfBuffer];
strcpy_s(pCharArray, CName::sizeOfBuffer, "Array of characters");

// Deallocate memory for the array


delete [] pCharArray;
pCharArray = NULL;

// Allocate memory for the object


CName* pName = new CName;
pName->SetName("Firstname", "Lastname");

// Deallocate memory for the object


delete pName;
pName = NULL;
}

Example: new operator


If you use the placement form of the new operator (the form with more arguments than
the size), the compiler doesn't support a placement form of the delete operator if the
constructor throws an exception. For example:

C++

// expre_new_Operator2.cpp
// C2660 expected
class A {
public:
A(int) { throw "Fail!"; }
};
void F(void) {
try {
// heap memory pointed to by pa1 will be deallocated
// by calling ::operator delete(void*).
A* pa1 = new A(10);
} catch (...) {
}
try {
// This will call ::operator new(size_t, char*, int).
// When A::A(int) does a throw, we should call
// ::operator delete(void*, char*, int) to deallocate
// the memory pointed to by pa2. Since
// ::operator delete(void*, char*, int) has not been implemented,
// memory will be leaked when the deallocation can't occur.

A* pa2 = new(__FILE__, __LINE__) A(20);


} catch (...) {
}
}

int main() {
A a;
}

Initializing objects allocated with new


An optional new-initializer field is included in the grammar for the new operator. This
field allows new objects to be initialized with user-defined constructors. For more
information about how initialization is done, see Initializers. The following example
illustrates how to use an initialization expression with the new operator:

C++

// expre_Initializing_Objects_Allocated_with_new.cpp
class Acct
{
public:
// Define default constructor and a constructor that accepts
// an initial balance.
Acct() { balance = 0.0; }
Acct( double init_balance ) { balance = init_balance; }
private:
double balance;
};

int main()
{
Acct *CheckingAcct = new Acct;
Acct *SavingsAcct = new Acct ( 34.98 );
double *HowMuch = new double { 43.0 };
// ...
}

In this example, the object CheckingAcct is allocated using the new operator, but no
default initialization is specified. So, the default constructor for the class, Acct() , is
called. Then the object SavingsAcct is allocated the same way, except that it's explicitly
initialized to 34.98. Because 34.98 is of type double , the constructor that takes an
argument of that type is called to handle the initialization. Finally, the non-class type
HowMuch is initialized to 43.0.

If an object is of a class type and that class has constructors (as in the preceding
example), the object can be initialized by the new operator only if one of these
conditions is met:

The arguments provided in the initializer match the arguments of a constructor.

The class has a default constructor (a constructor that can be called with no
arguments).

Explicit per-element initialization can't be done when allocating arrays using the new
operator; only the default constructor, if present, is called. For more information, see
Default arguments.

If the memory allocation fails ( operator new returns a value of 0), no initialization is
done. This behavior protects against attempts to initialize data that doesn't exist.

As with function calls, the order in which initialized expressions are evaluated isn't
defined. Furthermore, you shouldn't rely on these expressions being evaluated
completely before the memory allocation takes place. If the memory allocation fails and
the new operator returns zero, some expressions in the initializer may not be evaluated
completely.

Lifetime of objects allocated with new


Objects allocated with the new operator aren't destroyed when the scope in which
they're defined is exited. Because the new operator returns a pointer to the objects it
allocates, the program must define a pointer with suitable scope to access and delete
those objects. For example:

C++

// expre_Lifetime_of_Objects_Allocated_with_new.cpp
// C2541 expected
int main()
{
// Use new operator to allocate an array of 20 characters.
char *AnArray = new char[20];

for( int i = 0; i < 20; ++i )


{
// On the first iteration of the loop, allocate
// another array of 20 characters.
if( i == 0 )
{
char *AnotherArray = new char[20];
}
}

delete [] AnotherArray; // Error: pointer out of scope.


delete [] AnArray; // OK: pointer still in scope.
}

Once the pointer AnotherArray goes out of scope in the example, the object can no
longer be deleted.

How new works


The new-expression (the expression containing the new operator) does three things:

Locates and reserves storage for the object or objects to be allocated. When this
stage is complete, the correct amount of storage is allocated, but it's not yet an
object.

Initializes the object(s). Once initialization is complete, enough information is


present for the allocated storage to be an object.

Returns a pointer to the object(s) of a pointer type derived from new-type-id or


type-id . The program uses this pointer to access the newly allocated object.

The new operator invokes the function operator new . For arrays of any type, and for
objects that aren't class , struct , or union types, a global function, ::operator new , is
called to allocate storage. Class-type objects can define their own operator new static
member function on a per-class basis.

When the compiler encounters the new operator to allocate an object of type T , it
issues a call to T::operator new( sizeof(T) ) or, if no user-defined operator new is
defined, ::operator new( sizeof(T) ) . It's how the new operator can allocate the
correct amount of memory for the object.

7 Note

The argument to operator new is of type std::size_t . This type is defined in


<direct.h>, <malloc.h>, <memory.h>, <search.h>, <stddef.h>, <stdio.h>,
<stdlib.h>, <string.h>, and <time.h>.
An option in the grammar allows specification of new-placement (see the Grammar for
new Operator). The new-placement parameter can be used only for user-defined
implementations of operator new ; it allows extra information to be passed to operator
new . An expression with a new-placement field such as T *TObject = new ( 0x0040 ) T;
is translated to T *TObject = T::operator new( sizeof( T ), 0x0040 ); if class T has
member operator new , otherwise to T *TObject = ::operator new( sizeof( T ), 0x0040
); .

The original intention of the new-placement field was to allow hardware-dependent


objects to be allocated at user-specified addresses.

7 Note

Although the preceding example shows only one argument in the new-placement
field, there's no restriction on how many extra arguments can be passed to
operator new this way.

Even when operator new has been defined for a class type T , you can use the global
operator new explicitly, as in this example:

C++

T *TObject = ::new TObject;

The scope-resolution operator ( :: ) forces use of the global new operator.

See also
Expressions with unary operators
Keywords
new and delete operators
One's complement operator: ~
Article • 08/03/2021 • 2 minutes to read

Syntax
C++

~ cast-expression

Remarks
The one's complement operator ( ~ ), sometimes called the bitwise complement operator,
yields a bitwise one's complement of its operand. That is, every bit that is 1 in the
operand is 0 in the result. Conversely, every bit that is 0 in the operand is 1 in the result.
The operand to the one's complement operator must be an integral type.

Operator keyword for ~


C++ specifies compl as an alternative spelling for ~ . In C, the alternative spelling is
provided as a macro in the <iso646.h> header. In C++, the alternative spelling is a
keyword; use of <iso646.h> or the C++ equivalent <ciso646> is deprecated. In
Microsoft C++, the /permissive- or /Za compiler option is required to enable the
alternative spelling.

Example
C++

// expre_One_Complement_Operator.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;

int main () {
unsigned short y = 0xFFFF;
cout << hex << y << endl;
y = ~y; // Take one's complement
cout << hex << y << endl;
}
In this example, the new value assigned to y is the one's complement of the unsigned
value 0xFFFF, or 0x0000.

Integral promotion is performed on integral operands. The type the operand is


promoted to is the resultant type. For more information on integral promotion, see
Standard conversions.

See also
Expressions with unary operators
C++ built-in operators, precedence, and associativity
Unary arithmetic operators
Pointer-to-member operators: .* and -
>*
Article • 12/08/2021 • 2 minutes to read

Syntax
pm-expression :

cast-expression
pm-expression .* cast-expression

pm-expression ->* cast-expression

Remarks
The pointer-to-member operators .* and ->* return the value of a specific class
member for the object specified on the left side of the expression. The right side must
specify a member of the class. The following example shows how to use these operators:

C++

// expre_Expressions_with_Pointer_Member_Operators.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;

class Testpm {
public:
void m_func1() { cout << "m_func1\n"; }
int m_num;
};

// Define derived types pmfn and pmd.


// These types are pointers to members m_func1() and
// m_num, respectively.
void (Testpm::*pmfn)() = &Testpm::m_func1;
int Testpm::*pmd = &Testpm::m_num;

int main() {
Testpm ATestpm;
Testpm *pTestpm = new Testpm;

// Access the member function


(ATestpm.*pmfn)();
(pTestpm->*pmfn)(); // Parentheses required since * binds
// less tightly than the function call.

// Access the member data


ATestpm.*pmd = 1;
pTestpm->*pmd = 2;

cout << ATestpm.*pmd << endl


<< pTestpm->*pmd << endl;
delete pTestpm;
}

Output
Output

m_func1
m_func1
1
2

In the preceding example, a pointer to a member, pmfn , is used to invoke the member
function m_func1 . Another pointer to a member, pmd , is used to access the m_num
member.

The binary operator .* combines its first operand, which must be an object of class
type, with its second operand, which must be a pointer-to-member type.

The binary operator ->* combines its first operand, which must be a pointer to an
object of class type, with its second operand, which must be a pointer-to-member type.

In an expression containing the .* operator, the first operand must be of the class type
of, and be accessible to, the pointer to member specified in the second operand or of an
accessible type unambiguously derived from and accessible to that class.

In an expression containing the ->* operator, the first operand must be of the type
"pointer to the class type" of the type specified in the second operand, or it must be of a
type unambiguously derived from that class.

Example
Consider the following classes and program fragment:

C++
// expre_Expressions_with_Pointer_Member_Operators2.cpp
// C2440 expected
class BaseClass {
public:
BaseClass(); // Base class constructor.
void Func1();
};

// Declare a pointer to member function Func1.


void (BaseClass::*pmfnFunc1)() = &BaseClass::Func1;

class Derived : public BaseClass {


public:
Derived(); // Derived class constructor.
void Func2();
};

// Declare a pointer to member function Func2.


void (Derived::*pmfnFunc2)() = &Derived::Func2;

int main() {
BaseClass ABase;
Derived ADerived;

(ABase.*pmfnFunc1)(); // OK: defined for BaseClass.


(ABase.*pmfnFunc2)(); // Error: cannot use base class to
// access pointers to members of
// derived classes.

(ADerived.*pmfnFunc1)(); // OK: Derived is unambiguously


// derived from BaseClass.
(ADerived.*pmfnFunc2)(); // OK: defined for Derived.
}

The result of the .* or ->* pointer-to-member operators is an object or function of the


type specified in the declaration of the pointer to member. So, in the preceding
example, the result of the expression ADerived.*pmfnFunc1() is a pointer to a function
that returns void . This result is an l-value if the second operand is an l-value.

7 Note

If the result of one of the pointer-to-member operators is a function, then the


result can be used only as an operand to the function call operator.

See also
C++ built-in operators, precedence, and associativity
Postfix Increment and Decrement
Operators: ++ and --
Article • 08/17/2021 • 2 minutes to read

Syntax

postfix-expression ++
postfix-expression --

Remarks
C++ provides prefix and postfix increment and decrement operators; this section
describes only the postfix increment and decrement operators. (For more information,
see Prefix Increment and Decrement Operators.) The difference between the two is that
in the postfix notation, the operator appears after postfix-expression, whereas in the
prefix notation, the operator appears before expression. The following example shows a
postfix-increment operator:

C++

i++;

The effect of applying the postfix increment operator (++) is that the operand's value is
increased by one unit of the appropriate type. Similarly, the effect of applying the
postfix decrement operator (--) is that the operand's value is decreased by one unit of
the appropriate type.

It is important to note that a postfix increment or decrement expression evaluates to the


value of the expression prior to application of the respective operator. The increment or
decrement operation occurs after the operand is evaluated. This issue arises only when
the postfix increment or decrement operation occurs in the context of a larger
expression.

When a postfix operator is applied to a function argument, the value of the argument is
not guaranteed to be incremented or decremented before it is passed to the function.
See section 1.9.17 in the C++ standard for more information.
Applying the postfix increment operator to a pointer to an array of objects of type long
actually adds four to the internal representation of the pointer. This behavior causes the
pointer, which previously referred to the nth element of the array, to refer to the (n+1)th
element.

The operands to postfix increment and postfix decrement operators must be modifiable
(not const ) l-values of arithmetic or pointer type. The type of the result is the same as
that of the postfix-expression, but it is no longer an l-value.

Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): The
operand of a postfix increment or decrement operator may not be of type bool .

The following code illustrates the postfix increment operator:

C++

// expre_Postfix_Increment_and_Decrement_Operators.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

int main() {
int i = 10;
cout << i++ << endl;
cout << i << endl;
}

Postincrement and postdecrement operations on enumerated types are not supported:

C++

enum Compass { North, South, East, West );


Compass myCompass;
for( myCompass = North; myCompass != West; myCompass++ ) // Error

See also
Postfix Expressions
C++ Built-in Operators, Precedence and Associativity
C Postfix Increment and Decrement Operators
Prefix Increment and Decrement
Operators: ++ and --
Article • 08/17/2021 • 2 minutes to read

Syntax

++ unary-expression
-- unary-expression

Remarks
The prefix increment operator (++) adds one to its operand; this incremented value is
the result of the expression. The operand must be an l-value not of type const . The
result is an l-value of the same type as the operand.

The prefix decrement operator (--) is analogous to the prefix increment operator, except
that the operand is decremented by one and the result is this decremented value.

Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): The
operand of an increment or decrement operator may not be of type bool .

Both the prefix and postfix increment and decrement operators affect their operands.
The key difference between them is the order in which the increment or decrement
takes place in the evaluation of an expression. (For more information, see Postfix
Increment and Decrement Operators.) In the prefix form, the increment or decrement
takes place before the value is used in expression evaluation, so the value of the
expression is different from the value of the operand. In the postfix form, the increment
or decrement takes place after the value is used in expression evaluation, so the value of
the expression is the same as the value of the operand. For example, the following
program prints " ++i = 6 ":

C++

// expre_Increment_and_Decrement_Operators.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;


int main() {
int i = 5;
cout << "++i = " << ++i << endl;
}

An operand of integral or floating type is incremented or decremented by the integer


value 1. The type of the result is the same as the operand type. An operand of pointer
type is incremented or decremented by the size of the object it addresses. An
incremented pointer points to the next object; a decremented pointer points to the
previous object.

Because increment and decrement operators have side effects, using expressions with
increment or decrement operators in a preprocessor macro can have undesirable
results. Consider this example:

C++

// expre_Increment_and_Decrement_Operators2.cpp
#define max(a,b) ((a)<(b))?(b):(a)

int main()
{
int i = 0, j = 0, k;
k = max( ++i, j );
}

The macro expands to:

C++

k = ((++i)<(j))?(j):(++i);

If i is greater than or equal to j or less than j by 1, it will be incremented twice.

7 Note

C++ inline functions are preferable to macros in many cases because they eliminate
side effects such as those described here, and allow the language to perform more
complete type checking.

See also
Expressions with Unary Operators
C++ Built-in Operators, Precedence and Associativity
Prefix Increment and Decrement Operators
Relational Operators: < , > , <= , and >=
Article • 12/06/2021 • 2 minutes to read

Syntax

expression < expression


expression > expression
expression <= expression
expression >= expression

Remarks
The binary relational operators determine the following relationships:

Less than (<)

Greater than (>)

Less than or equal to (<=)

Greater than or equal to (>=)

The relational operators have left-to-right associativity. Both operands of relational


operators must be of arithmetic or pointer type. They yield values of type bool . The
value returned is false (0) if the relationship in the expression is false; otherwise, the
value returned is true (1).

Example
C++

// expre_Relational_Operators.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;

int main() {
cout << "The true expression 3 > 2 yields: "
<< (3 > 2) << endl
<< "The false expression 20 < 10 yields: "
<< (20 < 10) << endl;
}

The expressions in the preceding example must be enclosed in parentheses because the
stream insertion operator (<<) has higher precedence than the relational operators.
Therefore, the first expression without the parentheses would be evaluated as:

C++

(cout << "The true expression 3 > 2 yields: " << 3) < (2 << "\n");

The usual arithmetic conversions covered in Standard Conversions are applied to


operands of arithmetic types.

Comparing pointers
When two pointers to objects of the same type are compared, the result is determined
by the location of the objects pointed to in the program's address space. Pointers can
also be compared to a constant expression that evaluates to 0 or to a pointer of type
void * . If a pointer comparison is made against a pointer of type void * , the other

pointer is implicitly converted to type void * . Then the comparison is made.

Two pointers of different types cannot be compared unless:

One type is a class type derived from the other type.

At least one of the pointers is explicitly converted (cast) to type void * . (The other
pointer is implicitly converted to type void * for the conversion.)

Two pointers of the same type that point to the same object are guaranteed to compare
equal. If two pointers to nonstatic members of an object are compared, the following
rules apply:

If the class type is not a union , and if the two members are not separated by an
access-specifier, such as public , protected , or private , the pointer to the member
declared last will compare greater than the pointer to the member declared earlier.

If the two members are separated by an access-specifier, the results are undefined.

If the class type is a union , pointers to different data members in that union
compare equal.
If two pointers point to elements of the same array or to the element one beyond the
end of the array, the pointer to the object with the higher subscript compares higher.
Comparison of pointers is guaranteed valid only when the pointers refer to objects in
the same array or to the location one past the end of the array.

See also
Expressions with Binary Operators
C++ Built-in Operators, Precedence and Associativity
C Relational and Equality Operators
Scope resolution operator: ::
Article • 10/17/2022 • 2 minutes to read

The scope resolution operator :: is used to identify and disambiguate identifiers used
in different scopes. For more information about scope, see Scope.

Syntax
qualified-id :

nested-name-specifier template opt unqualified-id

nested-name-specifier :

::
type-name ::

namespace-name ::

decltype-specifier ::
nested-name-specifier identifier ::

nested-name-specifier template opt simple-template-id ::

unqualified-id :

identifier
operator-function-id

conversion-function-id

literal-operator-id
~ type-name

~ decltype-specifier
template-id

Remarks
The identifier can be a variable, a function, or an enumeration value.

Use :: for classes and namespaces


The following example shows how the scope resolution operator is used with
namespaces and classes:
C++

namespace NamespaceA{
int x;
class ClassA {
public:
int x;
};
}

int main() {

// A namespace name used to disambiguate


NamespaceA::x = 1;

// A class name used to disambiguate


NamespaceA::ClassA a1;
a1.x = 2;
}

A scope resolution operator without a scope qualifier refers to the global namespace.

C++

namespace NamespaceA{
int x;
}

int x;

int main() {
int x;

// the x in main()
x = 0;
// The x in the global namespace
::x = 1;

// The x in the A namespace


NamespaceA::x = 2;
}

You can use the scope resolution operator to identify a member of a namespace , or to
identify a namespace that nominates the member's namespace in a using directive. In
the example below, you can use NamespaceC to qualify ClassB , even though ClassB was
declared in namespace NamespaceB , because NamespaceB was nominated in NamespaceC
by a using directive.

C++
namespace NamespaceB {
class ClassB {
public:
int x;
};
}

namespace NamespaceC{
using namespace NamespaceB;
}

int main() {
NamespaceB::ClassB b_b;
NamespaceC::ClassB c_b;

b_b.x = 3;
c_b.x = 4;
}

You can use chains of scope resolution operators. In the following example,
NamespaceD::NamespaceD1 identifies the nested namespace NamespaceD1 , and

NamespaceE::ClassE::ClassE1 identifies the nested class ClassE1 .

C++

namespace NamespaceD{
namespace NamespaceD1{
int x;
}
}

namespace NamespaceE{
class ClassE{
public:
class ClassE1{
public:
int x;
};
};
}

int main() {
NamespaceD:: NamespaceD1::x = 6;
NamespaceE::ClassE::ClassE1 e1;
e1.x = 7 ;
}

Use :: for static members


You must use the scope resolution operator to call static members of classes.

C++

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

int ClassG::x = 6;

int main() {

int gx1 = ClassG::x;


int gx2 = ClassG::get_x();
}

Use :: for scoped enumerations


The scoped resolution operator is also used with the values of a scoped enumeration
Enumeration declarations, as in the following example:

C++

enum class EnumA{


First,
Second,
Third
};

int main() {
EnumA enum_value = EnumA::First;
}

See also
C++ built-in operators, precedence, and associativity
Namespaces
sizeof Operator
Article • 08/03/2021 • 2 minutes to read

Yields the size of its operand with respect to the size of type char .

7 Note

For information about the sizeof ... operator, see Ellipsis and variadic templates.

Syntax

sizeof unary-expression
sizeof ( type-name )

Remarks
The result of the sizeof operator is of type size_t , an integral type defined in the
include file <stddef.h>. This operator allows you to avoid specifying machine-
dependent data sizes in your programs.

The operand to sizeof can be one of the following:

A type name. To use sizeof with a type name, the name must be enclosed in
parentheses.

An expression. When used with an expression, sizeof can be specified with or


without the parentheses. The expression is not evaluated.

When the sizeof operator is applied to an object of type char , it yields 1. When the
sizeof operator is applied to an array, it yields the total number of bytes in that array,
not the size of the pointer represented by the array identifier. To obtain the size of the
pointer represented by the array identifier, pass it as a parameter to a function that uses
sizeof . For example:

Example
C++

#include <iostream>
using namespace std;

size_t getPtrSize( char *ptr )


{
return sizeof( ptr );
}

int main()
{
char szHello[] = "Hello, world!";

cout << "The size of a char is: "


<< sizeof( char )
<< "\nThe length of " << szHello << " is: "
<< sizeof szHello
<< "\nThe size of the pointer is "
<< getPtrSize( szHello ) << endl;
}

Sample Output
Output

The size of a char is: 1


The length of Hello, world! is: 14
The size of the pointer is 4

When the sizeof operator is applied to a class , struct , or union type, the result is the
number of bytes in an object of that type, plus any padding added to align members on
word boundaries. The result does not necessarily correspond to the size calculated by
adding the storage requirements of the individual members. The /Zp compiler option
and the pack pragma affect alignment boundaries for members.

The sizeof operator never yields 0, even for an empty class.

The sizeof operator cannot be used with the following operands:

Functions. (However, sizeof can be applied to pointers to functions.)

Bit fields.

Undefined classes.

The type void .


Dynamically allocated arrays.

External arrays.

Incomplete types.

Parenthesized names of incomplete types.

When the sizeof operator is applied to a reference, the result is the same as if sizeof
had been applied to the object itself.

If an unsized array is the last element of a structure, the sizeof operator returns the size
of the structure without the array.

The sizeof operator is often used to calculate the number of elements in an array using
an expression of the form:

C++

sizeof array / sizeof array[0]

See also
Expressions with Unary Operators
Keywords
Subscript Operator []
Article • 08/03/2021 • 3 minutes to read

Syntax

postfix-expression [ expression ]

Remarks
A postfix expression (which can also be a primary expression) followed by the subscript
operator, [ ], specifies array indexing.

For information about managed arrays in C++/CLI, see Arrays.

Usually, the value represented by postfix-expression is a pointer value, such as an array


identifier, and expression is an integral value (including enumerated types). However, all
that is required syntactically is that one of the expressions be of pointer type and the
other be of integral type. Thus the integral value could be in the postfix-expression
position and the pointer value could be in the brackets in the expression or subscript
position. Consider the following code fragment:

C++

int nArray[5] = { 0, 1, 2, 3, 4 };
cout << nArray[2] << endl; // prints "2"
cout << 2[nArray] << endl; // prints "2"

In the preceding example, the expression nArray[2] is identical to 2[nArray] . The


reason is that the result of a subscript expression e1[e2] is given by:

*((e2) + (e1))

The address yielded by the expression is not e2 bytes from the address e1. Rather, the
address is scaled to yield the next object in the array e2. For example:

C++

double aDbl[2];
The addresses of aDb[0] and aDb[1] are 8 bytes apart — the size of an object of type
double . This scaling according to object type is done automatically by the C++
language and is defined in Additive Operators where addition and subtraction of
operands of pointer type is discussed.

A subscript expression can also have multiple subscripts, as follows:

expression1 [ expression2 ] [ expression3 ] ...

Subscript expressions associate from left to right. The leftmost subscript expression,
expression1 [ expression2 ], is evaluated first. The address that results from adding
expression1 and expression2 forms a pointer expression; then expression3 is added to
this pointer expression to form a new pointer expression, and so on until the last
subscript expression has been added. The indirection operator (*) is applied after the
last subscripted expression is evaluated, unless the final pointer value addresses an array
type.

Expressions with multiple subscripts refer to elements of multidimensional arrays. A


multidimensional array is an array whose elements are arrays. For example, the first
element of a three-dimensional array is an array with two dimensions. The following
example declares and initializes a simple two-dimensional array of characters:

C++

// expre_Subscript_Operator.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;


#define MAX_ROWS 2
#define MAX_COLS 2

int main() {
char c[ MAX_ROWS ][ MAX_COLS ] = { { 'a', 'b' }, { 'c', 'd' } };
for ( int i = 0; i < MAX_ROWS; i++ )
for ( int j = 0; j < MAX_COLS; j++ )
cout << c[ i ][ j ] << endl;
}

Positive and negative subscripts


The first element of an array is element 0. The range of a C++ array is from array[0] to
array[size - 1]. However, C++ supports positive and negative subscripts. Negative
subscripts must fall within array boundaries; if they do not, the results are unpredictable.
The following code shows positive and negative array subscripts:
C++

#include <iostream>
using namespace std;

int main() {
int intArray[1024];
for (int i = 0, j = 0; i < 1024; i++)
{
intArray[i] = j++;
}

cout << intArray[512] << endl; // 512

cout << 257[intArray] << endl; // 257

int *midArray = &intArray[512]; // pointer to the middle of the array

cout << midArray[-256] << endl; // 256

cout << intArray[-256] << endl; // unpredictable, may crash


}

The negative subscript in the last line can produce a run-time error because it points to
an address 256 int positions lower in memory than the origin of the array. The pointer
midArray is initialized to the middle of intArray ; it is therefore possible (but dangerous)
to use both positive and negative array indices on it. Array subscript errors do not
generate compile-time errors, but they yield unpredictable results.

The subscript operator is commutative. Therefore, the expressions array[index] and


index[array] are guaranteed to be equivalent as long as the subscript operator is not
overloaded (see Overloaded Operators). The first form is the most common coding
practice, but either works.

See also
Postfix Expressions
C++ Built-in Operators, Precedence and Associativity
Arrays
One-Dimensional Arrays
Multidimensional Arrays
typeid Operator
Article • 08/03/2021 • 2 minutes to read

Syntax

typeid(type-id)
typeid(expression)

Remarks
The typeid operator allows the type of an object to be determined at run time.

The result of typeid is a const type_info& . The value is a reference to a type_info


object that represents either the type-id or the type of the expression, depending on
which form of typeid is used. For more information, see type_info Class.

The typeid operator doesn't work with managed types (abstract declarators or
instances). For information on getting the Type of a specified type, see typeid.

The typeid operator does a run-time check when applied to an l-value of a polymorphic
class type, where the true type of the object can't be determined by the static
information provided. Such cases are:

A reference to a class

A pointer, dereferenced with *

A subscripted pointer ( [ ] ). (It's not safe to use a subscript with a pointer to a


polymorphic type.)

If the expression points to a base class type, yet the object is actually of a type derived
from that base class, a type_info reference for the derived class is the result. The
expression must point to a polymorphic type (a class with virtual functions). Otherwise,
the result is the type_info for the static class referred to in the expression. Further, the
pointer must be dereferenced so that the object used is the one it points to. Without
dereferencing the pointer, the result will be the type_info for the pointer, not what it
points to. For example:
C++

// expre_typeid_Operator.cpp
// compile with: /GR /EHsc
#include <iostream>
#include <typeinfo>

class Base {
public:
virtual void vvfunc() {}
};

class Derived : public Base {};

using namespace std;


int main() {
Derived* pd = new Derived;
Base* pb = pd;
cout << typeid( pb ).name() << endl; //prints "class Base *"
cout << typeid( *pb ).name() << endl; //prints "class Derived"
cout << typeid( pd ).name() << endl; //prints "class Derived *"
cout << typeid( *pd ).name() << endl; //prints "class Derived"
delete pd;
}

If the expression is dereferencing a pointer, and that pointer's value is zero, typeid
throws a bad_typeid exception. If the pointer doesn't point to a valid object, a
__non_rtti_object exception is thrown. It indicates an attempt to analyze the RTTI that

triggered a fault because the object is somehow invalid. (For example, it's a bad pointer,
or the code wasn't compiled with /GR).

If the expression is not a pointer, and not a reference to a base class of the object, the
result is a type_info reference representing the static type of the expression. The static
type of an expression refers to the type of an expression as it is known at compile time.
Execution semantics are ignored when evaluating the static type of an expression.
Furthermore, references are ignored when possible when determining the static type of
an expression:

C++

// expre_typeid_Operator_2.cpp
#include <typeinfo>

int main()
{
typeid(int) == typeid(int&); // evaluates to true
}
typeid can also be used in templates to determine the type of a template parameter:

C++

// expre_typeid_Operator_3.cpp
// compile with: /c
#include <typeinfo>
template < typename T >
T max( T arg1, T arg2 ) {
cout << typeid( T ).name() << "s compared." << endl;
return ( arg1 > arg2 ? arg1 : arg2 );
}

See also
Run-Time Type Information
Keywords
Unary Plus and Negation Operators: +
and -
Article • 08/03/2021 • 2 minutes to read

Syntax

+ cast-expression
- cast-expression

+ operator
The result of the unary plus operator (+) is the value of its operand. The operand to the
unary plus operator must be of an arithmetic type.

Integral promotion is performed on integral operands. The resultant type is the type to
which the operand is promoted. Thus, the expression +ch , where ch is of type char ,
results in type int ; the value is unmodified. See Standard Conversions for more
information about how the promotion is done.

- operator
The unary negation operator (-) produces the negative of its operand. The operand to
the unary negation operator must be an arithmetic type.

Integral promotion is performed on integral operands, and the resultant type is the type
to which the operand is promoted. See Standard Conversions for more information
about how the promotion is performed.

Microsoft Specific

Unary negation of unsigned quantities is performed by subtracting the value of the


operand from 2^n, where n is the number of bits in an object of the given unsigned
type.

END Microsoft Specific


See also
Expressions with Unary Operators
C++ Built-in Operators, Precedence and Associativity
Expressions (C++)
Article • 08/03/2021 • 2 minutes to read

This section describes C++ expressions. Expressions are sequences of operators and
operands that are used for one or more of these purposes:

Computing a value from the operands.

Designating objects or functions.

Generating "side effects." (Side effects are any actions other than the evaluation of
the expression — for example, modifying the value of an object.)

In C++, operators can be overloaded and their meanings can be user-defined. However,
their precedence and the number of operands they take cannot be modified. This
section describes the syntax and semantics of operators as they are supplied with the
language, not overloaded. In addition to types of expressions and semantics of
expressions, the following topics are covered:

Primary expressions

Scope resolution operator

Postfix expressions

Expressions with unary operators

Expressions with binary operators

Conditional operator

Constant expressions

Casting operators

Run-time type information

Topics on operators in other sections:

C++ Built-in Operators, Precedence and Associativity

Overloaded operators

typeid (C++/CLI)

7 Note
Operators for built-in types cannot be overloaded; their behavior is
predefined.

See also
C++ Language Reference
Types of Expressions
Article • 08/03/2021 • 2 minutes to read

C++ expressions are divided into several categories:

Primary expressions. These are the building blocks from which all other expressions
are formed.

Postfix expressions. These are primary expressions followed by an operator — for


example, the array subscript or postfix increment operator.

Expressions formed with unary operators. Unary operators act on only one
operand in an expression.

Expressions formed with binary operators. Binary operators act on two operands in
an expression.

Expressions with the conditional operator. The conditional operator is a ternary


operator — the only such operator in the C++ language — and takes three
operands.

Constant expressions. Constant expressions are formed entirely of constant data.

Expressions with explicit type conversions. Explicit type conversions, or "casts," can
be used in expressions.

Expressions with pointer-to-member operators.

Casting. Type-safe "casts" can be used in expressions.

Run-Time Type Information. Determine the type of an object during program


execution.

See also
Expressions
Primary Expressions
Article • 08/03/2021 • 2 minutes to read

Primary expressions are the building blocks of more complex expressions. They may be
literals, names, and names qualified by the scope-resolution operator ( :: ). A primary
expression may have any of the following forms:

primary-expression

literal

this
name

:: name ( expression )

A literal is a constant primary expression. Its type depends on the form of its
specification. For complete information about specifying literals, see Literals .

The this keyword is a pointer to a class object. It's available within nonstatic member
functions. It points to the instance of the class for which the function was invoked. The
this keyword can't be used outside the body of a class-member function.

The type of the this pointer is type * const (where type is the class name) within
functions that don't specifically modify the this pointer. The following example shows
member function declarations and the types of this :

C++

// expre_Primary_Expressions.cpp
// compile with: /LD
class Example
{
public:
void Func(); // * const this
void Func() const; // const * const this
void Func() volatile; // volatile * const this
};

For more information about modifying the type of the this pointer, see this pointer.

The scope-resolution operator ( :: ) followed by a name is a primary expression. Such


names must be names at global scope, not member names. The type of the expression
is determined by the declaration of the name. It's an l-value (that is, it can appear on the
left-hand side of an assignment expression) if the declaring name is an l-value. The
scope-resolution operator allows a global name to be referred to, even if that name is
hidden in the current scope. See Scope for an example of how to use the scope-
resolution operator.

An expression enclosed in parentheses is a primary expression. Its type and value are
identical to the type and value of the unparenthesized expression. It's an l-value if the
unparenthesized expression is an l-value.

Examples of primary expressions include:

C++

100 // literal
'c' // literal
this // in a member function, a pointer to the class instance
::func // a global function
::operator + // a global operator function
::A::B // a global qualified name
( i + 1 ) // a parenthesized expression

These examples are all considered names, and as such, primary expressions, in various
forms:

C++

MyClass // an identifier
MyClass::f // a qualified name
operator = // an operator function name
operator char* // a conversion operator function name
~MyClass // a destructor name
A::B // a qualified name
A<int> // a template id

See also
Types of Expressions
Ellipsis and variadic templates
Article • 09/28/2022 • 3 minutes to read

This article shows how to use the ellipsis ( ... ) with C++ variadic templates. The ellipsis
has had many uses in C and C++. These include variable argument lists for functions.
The printf() function from the C Runtime Library is one of the most well-known
examples.

A variadic template is a class or function template that supports an arbitrary number of


arguments. This mechanism is especially useful to C++ library developers: You can apply
it to both class templates and function templates, and thereby provide a wide range of
type-safe and non-trivial functionality and flexibility.

Syntax
An ellipsis is used in two ways by variadic templates. To the left of the parameter name,
it signifies a parameter pack, and to the right of the parameter name, it expands the
parameter packs into separate names.

Here's a basic example of variadic class template definition syntax:

C++

template<typename... Arguments> class classname;

For both parameter packs and expansions, you can add whitespace around the ellipsis,
based on your preference, as shown in this example:

C++

template<typename ...Arguments> class classname;

Or this example:

C++

template<typename ... Arguments> class classname;

This article uses the convention that's shown in the first example (the ellipsis is attached
to typename ).
In the preceding examples, Arguments is a parameter pack. The class classname can
accept a variable number of arguments, as in these examples:

C++

template<typename... Arguments> class vtclass;

vtclass< > vtinstance1;


vtclass<int> vtinstance2;
vtclass<float, bool> vtinstance3;
vtclass<long, std::vector<int>, std::string> vtinstance4;

By using a variadic class template definition, you can also require at least one parameter:

C++

template <typename First, typename... Rest> class classname;

Here's a basic example of variadic function template syntax:

C++

template <typename... Arguments> returntype functionname(Arguments... args);

The Arguments parameter pack is then expanded for use, as shown in the next section.

Other forms of variadic function template syntax are possible—including, but not limited
to, these examples:

C++

template <typename... Arguments> returntype functionname(Arguments&...


args);
template <typename... Arguments> returntype functionname(Arguments&&...
args);
template <typename... Arguments> returntype functionname(Arguments*...
args);

Specifiers like const are also allowed:

C++

template <typename... Arguments> returntype functionname(const Arguments&...


args);
As with variadic template class definitions, you can make functions that require at least
one parameter:

C++

template <typename First, typename... Rest> returntype functionname(const


First& first, const Rest&... args);

Variadic templates use the sizeof...() operator (unrelated to the older sizeof()
operator):

C++

template<typename... Arguments>
void tfunc(const Arguments&... args)
{
constexpr auto numargs{ sizeof...(Arguments) };

X xobj[numargs]; // array of some previously defined type X

helper_func(xobj, args...);
}

More about ellipsis placement


Previously, this article described ellipsis placement that defines parameter packs and
expansions in this form: "to the left of the parameter name, it signifies a parameter pack,
and to the right of the parameter name, it expands the parameter packs into separate
names". While technically true, it can be confusing in translation to code. Consider:

In a template-parameter-list ( template <parameter-list> ), typename... introduces


a template parameter pack.

In a parameter-declaration-clause ( func(parameter-list) ), a "top-level" ellipsis


introduces a function parameter pack, and the ellipsis positioning is important:

C++

// v1 is NOT a function parameter pack:


template <typename... Types> void func1(std::vector<Types...> v1);

// v2 IS a function parameter pack:


template <typename... Types> void func2(std::vector<Types>... v2);
Where the ellipsis appears immediately after a parameter name, you have a
parameter pack expansion.

Example
A good way to illustrate the variadic function template mechanism is to use it in a
rewrite of some of the functionality of printf :

C++

#include <iostream>

using namespace std;

void print() {
cout << endl;
}

template <typename T> void print(const T& t) {


cout << t << endl;
}

template <typename First, typename... Rest> void print(const First& first,


const Rest&... rest) {
cout << first << ", ";
print(rest...); // recursive call using pack expansion syntax
}

int main()
{
print(); // calls first overload, outputting only a newline
print(1); // calls second overload

// these call the third overload, the variadic template,


// which uses recursion as needed.
print(10, 20);
print(100, 200, 300);
print("first", 2, "third", 3.14159);
}

Output
Output

1
10, 20
100, 200, 300
first, 2, third, 3.14159
7 Note

Most implementations that incorporate variadic function templates use recursion of


some form, but it's slightly different from traditional recursion. Traditional recursion
involves a function calling itself by using the same signature. (It may be overloaded
or templated, but the same signature is chosen each time.) Variadic recursion
involves calling a variadic function template by using differing (almost always
decreasing) numbers of arguments, and thereby stamping out a different signature
every time. A "base case" is still required, but the nature of the recursion is
different.
Postfix Expressions
Article • 08/03/2021 • 6 minutes to read

Postfix expressions consist of primary expressions or expressions in which postfix


operators follow a primary expression. The postfix operators are listed in the following
table.

Postfix Operators

Operator Name Operator Notation

Subscript operator []

Function call operator ()

Explicit type conversion operator type-name ( )

Member access operator . or ->

Postfix increment operator ++

Postfix decrement operator --

The following syntax describes possible postfix expressions:

primary-expression
postfix-expression[expression]postfix-expression(expression-list)simple-
type-name(expression-list)postfix-expression.namepostfix-expression-
>namepostfix-expression++postfix-expression--cast-keyword < typename >
(expression )typeid ( typename )

The postfix-expression above may be a primary expression or another postfix expression.


Postfix expressions group left to right, thus allowing the expressions to be chained
together as follows:

C++

func(1)->GetValue()++

In the above expression, func is a primary expression, func(1) is a function postfix


expression, func(1)->GetValue is a postfix expression specifying a member of the class,
func(1)->GetValue() is another function postfix expression, and the entire expression is
a postfix expression incrementing the return value of GetValue. The meaning of the
expression as a whole is "call func passing 1 as an argument and get a pointer to a class
as a return value. Then call GetValue() on that class, then increment the value returned.

The expressions listed above are assignment expressions, meaning that the result of
these expressions must be an r-value.

The postfix expression form

C++

simple-type-name ( expression-list )

indicates the invocation of the constructor. If the simple-type-name is a fundamental


type, the expression list must be a single expression, and this expression indicates a cast
of the expression's value to the fundamental type. This type of cast expression mimics a
constructor. Because this form allows fundamental types and classes to be constructed
using the same syntax, this form is especially useful when defining template classes.

The cast-keyword is one of dynamic_cast , static_cast or reinterpret_cast . More


information may be found in dynamic_cast, static_cast and reinterpet_cast.

The typeid operator is considered a postfix expression. See typeid operator.

Formal and actual arguments


Calling programs pass information to called functions in "actual arguments." The called
functions access the information using corresponding "formal arguments."

When a function is called, the following tasks are performed:

All actual arguments (those supplied by the caller) are evaluated. There is no
implied order in which these arguments are evaluated, but all arguments are
evaluated and all side effects completed prior to entry to the function.

Each formal argument is initialized with its corresponding actual argument in the
expression list. (A formal argument is an argument that is declared in the function
header and used in the body of a function.) Conversions are done as if by
initialization — both standard and user-defined conversions are performed in
converting an actual argument to the correct type. The initialization performed is
illustrated conceptually by the following code:

C++
void Func( int i ); // Function prototype
...
Func( 7 ); // Execute function call

The conceptual initializations prior to the call are:

C++

int Temp_i = 7;
Func( Temp_i );

Note that the initialization is performed as if using the equal-sign syntax instead of
the parentheses syntax. A copy of i is made prior to passing the value to the
function. (For more information, see Initializers and Conversions).

Therefore, if the function prototype (declaration) calls for an argument of type


long , and if the calling program supplies an actual argument of type int , the
actual argument is promoted using a standard type conversion to type long (see
Standard Conversions).

It is an error to supply an actual argument for which there is no standard or user-


defined conversion to the type of the formal argument.

For actual arguments of class type, the formal argument is initialized by calling the
class's constructor. (See Constructors for more about these special class member
functions.)

The function call is executed.

The following program fragment demonstrates a function call:

C++

// expre_Formal_and_Actual_Arguments.cpp
void func( long param1, double param2 );

int main()
{
long i = 1;
double j = 2;

// Call func with actual arguments i and j.


func( i, j );
}

// Define func with formal parameters param1 and param2.


void func( long param1, double param2 )
{
}

When func is called from main, the formal parameter param1 is initialized with the value
of i ( i is converted to type long to correspond to the correct type using a standard
conversion), and the formal parameter param2 is initialized with the value of j ( j is
converted to type double using a standard conversion).

Treatment of argument types


Formal arguments declared as const types cannot be changed within the body of a
function. Functions can change any argument that is not of type const . However, the
change is local to the function and does not affect the actual argument's value unless
the actual argument was a reference to an object not of type const .

The following functions illustrate some of these concepts:

C++

// expre_Treatment_of_Argument_Types.cpp
int func1( const int i, int j, char *c ) {
i = 7; // C3892 i is const.
j = i; // value of j is lost at return
*c = 'a' + j; // changes value of c in calling function
return i;
}

double& func2( double& d, const char *c ) {


d = 14.387; // changes value of d in calling function.
*c = 'a'; // C3892 c is a pointer to a const object.
return d;
}

Ellipsis and default arguments


Functions can be declared to accept fewer arguments than specified in the function
definition, using one of two methods: ellipsis ( ... ) or default arguments.

Ellipsis denotes that arguments may be required but that the number and types are not
specified in the declaration. This is normally poor C++ programming practice because it
defeats one of the benefits of C++: type safety. Different conversions are applied to
functions declared with ellipsis than to those functions for which the formal and actual
argument types are known:
If the actual argument is of type float , it is promoted to type double prior to the
function call.

Any signed char or unsigned char , signed short or unsigned short , enumerated
type, or bit field is converted to either a signed int or an unsigned int using
integral promotion.

Any argument of class type is passed by value as a data structure; the copy is
created by binary copying instead of by invoking the class's copy constructor (if
one exists).

Ellipsis, if used, must be declared last in the argument list. For more information about
passing a variable number of arguments, see the discussion of va_arg, va_start, and
va_list in the Run-Time Library Reference.

For information on default arguments in CLR programming, see Variable Argument Lists
(...) (C++/CLI).

Default arguments enable you to specify the value an argument should assume if none
is supplied in the function call. The following code fragment shows how default
arguments work. For more information about restrictions on specifying default
arguments, see Default Arguments.

C++

// expre_Ellipsis_and_Default_Arguments.cpp
// compile with: /EHsc
#include <iostream>

// Declare the function print that prints a string,


// then a terminator.
void print( const char *string,
const char *terminator = "\n" );

int main()
{
print( "hello," );
print( "world!" );

print( "good morning", ", " );


print( "sunshine." );
}

using namespace std;


// Define print.
void print( const char *string, const char *terminator )
{
if( string != NULL )
cout << string;
if( terminator != NULL )
cout << terminator;
}

The preceding program declares a function, print , that takes two arguments. However,
the second argument, terminator, has a default value, "\n" . In main , the first two calls to
print allow the default second argument to supply a new line to terminate the printed

string. The third call specifies an explicit value for the second argument. The output from
the program is

Output

hello,
world!
good morning, sunshine.

See also
Types of Expressions
Expressions with Unary Operators
Article • 12/01/2021 • 2 minutes to read

Unary operators act on only one operand in an expression. The unary operators are as
follows:

Indirection operator (*)

Address-of operator (&)

Unary plus operator (+)

Unary negation operator (-)

Logical negation operator (!)

One's complement operator (~)

Prefix increment operator (++)

Prefix decrement operator (--)

Cast operator ()

sizeof operator

alignof operator

noexcept expression

new operator

delete operator

These operators have right-to-left associativity. Unary expressions generally involve


syntax that precedes a postfix or primary expression.

Syntax
unary-expression :
postfix-expression

++ cast-expression

-- cast-expression
unary-operator cast-expression
sizeof unary-expression

sizeof ( type-id )
sizeof ... ( identifier )

alignof ( type-id )
noexcept-expression

new-expression

delete-expression
unary-operator : one of

* & + - ! ~

Remarks
Any postfix-expression is considered a unary-expression , and because any primary-
expression is considered a postfix-expression , any primary-expression is considered a

unary-expression also. For more information, see Postfix expressions and Primary

expressions.

The cast-expression is a unary-expression with an optional cast to change the type. For
more information, see Cast operator: ().

The noexcept-expression is a noexcept-specifier with a constant-expression


argument. For more information, see noexcept.

The new-expression refers to the new operator. The delete-expression refers to the
delete operator. For more information, see new operator and delete operator.

See also
Types of expressions
Expressions with Binary Operators
Article • 02/17/2022 • 2 minutes to read

Binary operators act on two operands in an expression. The binary operators are:

Multiplicative operators

Multiplication (*)

Division (/)

Modulus (%)

Additive operators

Addition (+)

Subtraction (-)

Shift operators

Right shift (>>)

Left shift (<<)

Relational and equality operators

Less than (<)

Greater than (>)

Less than or equal to (<=)

Greater than or equal to (>=)

Equal to (==)

Not equal to (!=)

Bitwise operators

Bitwise AND (&)

Bitwise exclusive OR (^)

Bitwise inclusive OR (|)

Logical operators
Logical AND (&&)

Logical OR (||)

Assignment operators

Assignment (=)

Addition assignment (+=)

Subtraction assignment (-=)

Multiplication assignment (*=)

Division assignment (/=)

Modulus assignment (%=)

Left shift assignment (<<=)

Right shift assignment (>>=)

Bitwise AND assignment (&=)

Bitwise exclusive OR assignment (^=)

Bitwise inclusive OR assignment (|=)

Comma Operator (,)

See also
Types of Expressions
C++ Constant Expressions
Article • 08/03/2021 • 2 minutes to read

A constant value is one that doesn't change. C++ provides two keywords to enable you
to express the intent that an object is not intended to be modified, and to enforce that
intent.

C++ requires constant expressions — expressions that evaluate to a constant — for


declarations of:

Array bounds

Selectors in case statements

Bit-field length specification

Enumeration initializers

The only operands that are legal in constant expressions are:

Literals

Enumeration constants

Values declared as const that are initialized with constant expressions

sizeof expressions

Nonintegral constants must be converted (either explicitly or implicitly) to integral types


to be legal in a constant expression. Therefore, the following code is legal:

C++

const double Size = 11.0;


char chArray[(int)Size];

Explicit conversions to integral types are legal in constant expressions; all other types
and derived types are illegal except when used as operands to the sizeof operator.

The comma operator and assignment operators cannot be used in constant expressions.

See also
Types of Expressions
Semantics of Expressions
Article • 02/17/2022 • 4 minutes to read

Expressions are evaluated according to the precedence and grouping of their operators.
(Operator Precedence and Associativity in Lexical Conventions, shows the relationships
the C++ operators impose on expressions.)

Order of evaluation
Consider this example:

C++

// Order_of_Evaluation.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
int a = 2, b = 4, c = 9;

cout << a + b * c << "\n";


cout << a + (b * c) << "\n";
cout << (a + b) * c << "\n";
}

Output

38
38
54

Expression-evaluation order

The order in which the expression shown in the above figure is evaluated is determined
by the precedence and associativity of the operators:

1. Multiplication (*) has the highest precedence in this expression; hence the
subexpression b * c is evaluated first.
2. Addition (+) has the next highest precedence, so a is added to the product of b
and c .

3. Left shift (<<) has the lowest precedence in the expression, but there are two
occurrences. Because the left-shift operator groups left-to-right, the left
subexpression is evaluated first and then the right one.

When parentheses are used to group the subexpressions, they alter the precedence and
also the order in which the expression is evaluated, as shown in the following figure.

Expression-evaluation order with parentheses

Expressions such as those in the above figure are evaluated purely for their side effects
— in this case, to transfer information to the standard output device.

Notation in expressions
The C++ language specifies certain compatibilities when specifying operands. The
following table shows the types of operands acceptable to operators that require
operands of type type.

Operand Types Acceptable to Operators

Type expected Types allowed

type const type


volatile type
type&
const type&
volatile type&
volatile const type
volatile const type&

type * type *
const type *
volatile type *
volatile const type *
Type expected Types allowed

const type type


const type
const type&

volatile type type


volatile type
volatile type&

Because the preceding rules can always be used in combination, a const pointer to a
volatile object can be supplied where a pointer is expected.

Ambiguous expressions
Certain expressions are ambiguous in their meaning. These expressions occur most
frequently when an object's value is modified more than once in the same expression.
These expressions rely on a particular order of evaluation where the language does not
define one. Consider the following example:

int i = 7;

func( i, ++i );

The C++ language does not guarantee the order in which arguments to a function call
are evaluated. Therefore, in the preceding example, func could receive the values 7 and
8, or 8 and 8 for its parameters, depending on whether the parameters are evaluated
from left to right or from right to left.

C++ sequence points (Microsoft-specific)


An expression can modify an object's value only once between consecutive "sequence
points."

The C++ language definition does not currently specify sequence points. Microsoft C++
uses the same sequence points as ANSI C for any expression involving C operators and
not involving overloaded operators. When operators are overloaded, the semantics
change from operator sequencing to function-call sequencing. Microsoft C++ uses the
following sequence points:
Left operand of the logical AND operator ( && ). The left operand of the logical AND
operator is completely evaluated and all side effects completed before continuing.
There's no guarantee that the right operand of the logical AND operator will be
evaluated.

Left operand of the logical OR operator ( || ). The left operand of the logical OR
operator is completely evaluated and all side effects completed before continuing.
There's no guarantee that the right operand of the logical OR operator will be
evaluated.

Left operand of the comma operator. The left operand of the comma operator is
completely evaluated and all side effects completed before continuing. Both
operands of the comma operator are always evaluated.

Function-call operator. The function-call expression and all arguments to a


function, including default arguments, are evaluated and all side effects completed
prior to entry to the function. There is no specified order of evaluation among the
arguments or the function-call expression.

First operand of the conditional operator. The first operand of the conditional
operator is completely evaluated and all side effects completed before continuing.

The end of a full initialization expression, such as the end of an initialization in a


declaration statement.

The expression in an expression statement. Expression statements consist of an


optional expression followed by a semicolon (;). The expression is completely
evaluated for its side effects.

The controlling expression in a selection (if or switch) statement. The expression is


completely evaluated and all side effects completed before the code dependent on
the selection is executed.

The controlling expression of a while or do statement. The expression is completely


evaluated and all side effects completed before any statements in the next
iteration of the while or do loop are executed.

Each of the three expressions of a for statement. Each expression is completely


evaluated and all side effects completed before moving to the next expression.

The expression in a return statement. The expression is completely evaluated and


all side effects completed before control returns to the calling function.
See also
Expressions
Casting
Article • 08/03/2021 • 2 minutes to read

The C++ language provides that if a class is derived from a base class containing virtual
functions, a pointer to that base class type can be used to call the implementations of
the virtual functions residing in the derived class object. A class containing virtual
functions is sometimes called a "polymorphic class."

Since a derived class completely contains the definitions of all the base classes from
which it is derived, it is safe to cast a pointer up the class hierarchy to any of these base
classes. Given a pointer to a base class, it might be safe to cast the pointer down the
hierarchy. It is safe if the object being pointed to is actually of a type derived from the
base class. In this case, the actual object is said to be the "complete object." The pointer
to the base class is said to point to a "subobject" of the complete object. For example,
consider the class hierarchy shown in the following figure.

Class hierarchy

An object of type C could be visualized as shown in the following figure.

Class C with sub-objects B and A

Given an instance of class C , there is a B subobject and an A subobject. The instance of


C , including the A and B subobjects, is the "complete object."

Using run-time type information, it is possible to check whether a pointer actually points
to a complete object and can be safely cast to point to another object in its hierarchy.
The dynamic_cast operator can be used to make these types of casts. It also performs
the run-time check necessary to make the operation safe.

For conversion of nonpolymorphic types, you can use the static_cast operator (this topic
explains the difference between static and dynamic casting conversions, and when it is
appropriate to use each).

This section covers the following topics:

Casting operators

Run-time type information


See also
Expressions
Casting Operators
Article • 08/03/2021 • 2 minutes to read

There are several casting operators specific to the C++ language. These operators are
intended to remove some of the ambiguity and danger inherent in old style C language
casts. These operators are:

dynamic_cast Used for conversion of polymorphic types.

static_cast Used for conversion of nonpolymorphic types.

const_cast Used to remove the const , volatile , and __unaligned attributes.

reinterpret_cast Used for simple reinterpretation of bits.

safe_cast Used in C++/CLI to produce verifiable MSIL.

Use const_cast and reinterpret_cast as a last resort, since these operators present the
same dangers as old style casts. However, they are still necessary in order to completely
replace old style casts.

See also
Casting
dynamic_cast Operator
Article • 04/04/2023 • 8 minutes to read

Converts the operand expression to an object of type type-id .

Syntax

dynamic_cast < type-id > ( expression )

Remarks
The type-id must be a pointer or a reference to a previously defined class type or a
"pointer to void". The type of expression must be a pointer if type-id is a pointer, or an
l-value if type-id is a reference.

See static_cast for an explanation of the difference between static and dynamic casting
conversions, and when it's appropriate to use each.

There are two breaking changes in the behavior of dynamic_cast in managed code:

dynamic_cast to a pointer to the underlying type of a boxed enum will fail at


runtime, returning 0 instead of the converted pointer.

dynamic_cast will no longer throw an exception when type-id is an interior

pointer to a value type; instead, the cast fails at runtime. The cast returns the 0
pointer value instead of throwing.

If type-id is a pointer to an unambiguous accessible direct or indirect base class of


expression , then a pointer to the unique subobject of type type-id is the result. For

example:

C++

// dynamic_cast_1.cpp
// compile with: /c
class B { };
class C : public B { };
class D : public C { };

void f(D* pd) {


C* pc = dynamic_cast<C*>(pd); // ok: C is a direct base class
// pc points to C subobject of pd
B* pb = dynamic_cast<B*>(pd); // ok: B is an indirect base class
// pb points to B subobject of pd
}

This type of conversion is called an "upcast" because it moves a pointer up a class


hierarchy, from a derived class to a class it's derived from. An upcast is an implicit
conversion.

If type-id is void*, a run-time check is made to determine the actual type of


expression . The result is a pointer to the complete object pointed to by expression . For

example:

C++

// dynamic_cast_2.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
A* pa = new A;
B* pb = new B;
void* pv = dynamic_cast<void*>(pa);
// pv now points to an object of type A

pv = dynamic_cast<void*>(pb);
// pv now points to an object of type B
}

If type-id isn't void* , a run-time check is made to see if the object pointed to by
expression can be converted to the type pointed to by type-id .

If the type of expression is a base class of the type of type-id , a run-time check is
made to see if expression actually points to a complete object of the type of type-id . If
this is true, the result is a pointer to a complete object of the type of type-id . For
example:

C++

// dynamic_cast_3.cpp
// compile with: /c /GR
class B {virtual void f();};
class D : public B {virtual void f();};

void f() {
B* pb = new D; // unclear but ok
B* pb2 = new B;

D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D


D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D
}

This type of conversion is called a "downcast" because it moves a pointer down a class
hierarchy, from a given class to a class derived from it.

In cases of multiple inheritance, possibilities for ambiguity are introduced. Consider the
class hierarchy shown in the following figure.

For CLR types, dynamic_cast results in either a no-op if the conversion can be
performed implicitly, or an MSIL isinst instruction, which performs a dynamic check
and returns nullptr if the conversion fails.

The following sample uses dynamic_cast to determine if a class is an instance of


particular type:

C++

// dynamic_cast_clr.cpp
// compile with: /clr
using namespace System;

void PrintObjectType( Object^o ) {


if( dynamic_cast<String^>(o) )
Console::WriteLine("Object is a String");
else if( dynamic_cast<int^>(o) )
Console::WriteLine("Object is an int");
}

int main() {
Object^o1 = "hello";
Object^o2 = 10;

PrintObjectType(o1);
PrintObjectType(o2);
}

A pointer to an object of type D can be safely cast to B or C . However, if D is cast to


point to an A object, which instance of A would result? This would result in an
ambiguous casting error. To get around this problem, you can perform two
unambiguous casts. For example:
C++

// dynamic_cast_4.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A {virtual void f();};
class D : public B, public C {virtual void f();};

void f() {
D* pd = new D;
A* pa = dynamic_cast<A*>(pd); // C4540, ambiguous cast fails at runtime
B* pb = dynamic_cast<B*>(pd); // first cast to B
A* pa2 = dynamic_cast<A*>(pb); // ok: unambiguous
}

Further ambiguities can be introduced when you use virtual base classes. Consider the
class hierarchy shown in the following figure.

Class hierarchy that shows virtual base classes

In this hierarchy, A is a virtual base class. Given an instance of class E and a pointer to
the A subobject, a dynamic_cast to a pointer to B fails due to ambiguity. You must first
cast back to the complete E object, then work your way back up the hierarchy, in an
unambiguous manner, to reach the correct B object.

Consider the class hierarchy shown in the following figure.

Class hierarchy that shows duplicate base classes

Given an object of type E and a pointer to the D subobject, to navigate from the D
subobject to the left-most A subobject, three conversions can be made. You can
perform a dynamic_cast conversion from the D pointer to an E pointer, then a
conversion (either dynamic_cast or an implicit conversion) from E to B , and finally an
implicit conversion from B to A . For example:

C++
// dynamic_cast_5.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {


E* pe = dynamic_cast<E*>(pd);
B* pb = pe; // upcast, implicit conversion
A* pa = pb; // upcast, implicit conversion
}

The dynamic_cast operator can also be used to perform a "cross cast." Using the same
class hierarchy, it's possible to cast a pointer, for example, from the B subobject to the
D subobject, as long as the complete object is of type E .

Considering cross casts, it's possible to do the conversion from a pointer to D to a


pointer to the left-most A subobject in just two steps. You can perform a cross cast from
D to B , then an implicit conversion from B to A . For example:

C++

// dynamic_cast_6.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {


B* pb = dynamic_cast<B*>(pd); // cross cast
A* pa = pb; // upcast, implicit conversion
}

A null pointer value is converted to the null pointer value of the destination type by
dynamic_cast .

When you use dynamic_cast < type-id > ( expression ) , if expression can't be safely
converted to type type-id , the run-time check causes the cast to fail. For example:

C++

// dynamic_cast_7.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
A* pa = new A;
B* pb = dynamic_cast<B*>(pa); // fails at runtime, not safe;
// B not derived from A
}

The value of a failed cast to pointer type is the null pointer. A failed cast to reference
type throws a bad_cast Exception. If expression doesn't point to or reference a valid
object, a __non_rtti_object exception is thrown.

See typeid for an explanation of the __non_rtti_object exception.

Example
The following sample creates the base class (struct A) pointer, to an object (struct C).
This, plus the fact there are virtual functions, enables runtime polymorphism.

The sample also calls a nonvirtual function in the hierarchy.

C++

// dynamic_cast_8.cpp
// compile with: /GR /EHsc
#include <stdio.h>
#include <iostream>

struct A {
virtual void test() {
printf_s("in A\n");
}
};

struct B : A {
virtual void test() {
printf_s("in B\n");
}

void test2() {
printf_s("test2 in B\n");
}
};

struct C : B {
virtual void test() {
printf_s("in C\n");
}
void test2() {
printf_s("test2 in C\n");
}
};

void Globaltest(A& a) {
try {
C &c = dynamic_cast<C&>(a);
printf_s("in GlobalTest\n");
}
catch(std::bad_cast) {
printf_s("Can't cast to C\n");
}
}

int main() {
A *pa = new C;
A *pa2 = new B;

pa->test();

B * pb = dynamic_cast<B *>(pa);
if (pb)
pb->test2();

C * pc = dynamic_cast<C *>(pa2);
if (pc)
pc->test2();

C ConStack;
Globaltest(ConStack);

// fails because B knows nothing about C


B BonStack;
Globaltest(BonStack);
}

Output

in C
test2 in B
in GlobalTest
Can't cast to C

See also
Casting Operators
Keywords
bad_cast exception
Article • 08/03/2021 • 2 minutes to read

The bad_cast exception is thrown by the dynamic_cast operator as the result of a failed
cast to a reference type.

Syntax

catch (bad_cast)
statement

Remarks
The interface for bad_cast is:

C++

class bad_cast : public exception

The following code contains an example of a failed dynamic_cast that throws the
bad_cast exception.

C++

// expre_bad_cast_Exception.cpp
// compile with: /EHsc /GR
#include <typeinfo>
#include <iostream>

class Shape {
public:
virtual void virtualfunc() const {}
};

class Circle: public Shape {


public:
virtual void virtualfunc() const {}
};

using namespace std;


int main() {
Shape shape_instance;
Shape& ref_shape = shape_instance;
try {
Circle& ref_circle = dynamic_cast<Circle&>(ref_shape);
}
catch (bad_cast b) {
cout << "Caught: " << b.what();
}
}

The exception is thrown because the object being cast (a Shape) isn't derived from the
specified cast type (Circle). To avoid the exception, add these declarations to main :

C++

Circle circle_instance;
Circle& ref_circle = circle_instance;

Then reverse the sense of the cast in the try block as follows:

C++

Shape& ref_shape = dynamic_cast<Shape&>(ref_circle);

Members

Constructors

Constructor Description

bad_cast The constructor for objects of type bad_cast .

Functions

Function Description

what TBD

Operators

Operator Description

operator= An assignment operator that assigns one bad_cast object to another.


bad_cast
The constructor for objects of type bad_cast .

C++

bad_cast(const char * _Message = "bad cast");


bad_cast(const bad_cast &);

operator=
An assignment operator that assigns one bad_cast object to another.

C++

bad_cast& operator=(const bad_cast&) noexcept;

what
C++

const char* what() const noexcept override;

See also
dynamic_cast Operator
Keywords
Modern C++ best practices for exceptions and error handling
static_cast Operator
Article • 08/03/2021 • 4 minutes to read

Converts an expression to the type of type-id, based only on the types that are present in
the expression.

Syntax

static_cast <type-id> ( expression )

Remarks
In standard C++, no run-time type check is made to help ensure the safety of the
conversion. In C++/CX, a compile time and runtime check are performed. For more
information, see Casting.

The static_cast operator can be used for operations such as converting a pointer to a
base class to a pointer to a derived class. Such conversions are not always safe.

In general you use static_cast when you want to convert numeric data types such as
enums to ints or ints to floats, and you are certain of the data types involved in the
conversion. static_cast conversions are not as safe as dynamic_cast conversions,
because static_cast does no run-time type check, while dynamic_cast does. A
dynamic_cast to an ambiguous pointer will fail, while a static_cast returns as if nothing

were wrong; this can be dangerous. Although dynamic_cast conversions are safer,
dynamic_cast only works on pointers or references, and the run-time type check is an

overhead. For more information, see dynamic_cast Operator.

In the example that follows, the line D* pd2 = static_cast<D*>(pb); is not safe because
D can have fields and methods that are not in B . However, the line B* pb2 =

static_cast<B*>(pd); is a safe conversion because D always contains all of B .

C++

// static_cast_Operator.cpp
// compile with: /LD
class B {};

class D : public B {};


void f(B* pb, D* pd) {
D* pd2 = static_cast<D*>(pb); // Not safe, D can have fields
// and methods that are not in B.

B* pb2 = static_cast<B*>(pd); // Safe conversion, D always


// contains all of B.
}

In contrast to dynamic_cast, no run-time check is made on the static_cast conversion


of pb . The object pointed to by pb may not be an object of type D , in which case the
use of *pd2 could be disastrous. For instance, calling a function that is a member of the
D class, but not the B class, could result in an access violation.

The dynamic_cast and static_cast operators move a pointer throughout a class


hierarchy. However, static_cast relies exclusively on the information provided in the
cast statement and can therefore be unsafe. For example:

C++

// static_cast_Operator_2.cpp
// compile with: /LD /GR
class B {
public:
virtual void Test(){}
};
class D : public B {};

void f(B* pb) {


D* pd1 = dynamic_cast<D*>(pb);
D* pd2 = static_cast<D*>(pb);
}

If pb really points to an object of type D , then pd1 and pd2 will get the same value.
They will also get the same value if pb == 0 .

If pb points to an object of type B and not to the complete D class, then dynamic_cast
will know enough to return zero. However, static_cast relies on the programmer's
assertion that pb points to an object of type D and simply returns a pointer to that
supposed D object.

Consequently, static_cast can do the inverse of implicit conversions, in which case the
results are undefined. It is left to the programmer to verify that the results of a
static_cast conversion are safe.
This behavior also applies to types other than class types. For instance, static_cast can
be used to convert from an int to a char . However, the resulting char may not have
enough bits to hold the entire int value. Again, it is left to the programmer to verify
that the results of a static_cast conversion are safe.

The static_cast operator can also be used to perform any implicit conversion,
including standard conversions and user-defined conversions. For example:

C++

// static_cast_Operator_3.cpp
// compile with: /LD /GR
typedef unsigned char BYTE;

void f() {
char ch;
int i = 65;
float f = 2.5;
double dbl;

ch = static_cast<char>(i); // int to char


dbl = static_cast<double>(f); // float to double
i = static_cast<BYTE>(ch);
}

The static_cast operator can explicitly convert an integral value to an enumeration


type. If the value of the integral type does not fall within the range of enumeration
values, the resulting enumeration value is undefined.

The static_cast operator converts a null pointer value to the null pointer value of the
destination type.

Any expression can be explicitly converted to type void by the static_cast operator.
The destination void type can optionally include the const , volatile , or __unaligned
attribute.

The static_cast operator cannot cast away the const , volatile , or __unaligned
attributes. See const_cast Operator for information on removing these attributes.

C++/CLI: Due to the danger of performing unchecked casts on top of a relocating


garbage collector, the use of static_cast should only be in performance-critical code
when you are certain it will work correctly. If you must use static_cast in release mode,
substitute it with safe_cast in your debug builds to ensure success.
See also
Casting Operators
Keywords
const_cast Operator
Article • 08/03/2021 • 2 minutes to read

Removes the const , volatile , and __unaligned attribute(s) from a class.

Syntax

const_cast <type-id> (expression)

Remarks
A pointer to any object type or a pointer to a data member can be explicitly converted
to a type that is identical except for the const , volatile , and __unaligned qualifiers. For
pointers and references, the result will refer to the original object. For pointers to data
members, the result will refer to the same member as the original (uncast) pointer to
data member. Depending on the type of the referenced object, a write operation
through the resulting pointer, reference, or pointer to data member might produce
undefined behavior.

You cannot use the const_cast operator to directly override a constant variable's
constant status.

The const_cast operator converts a null pointer value to the null pointer value of the
destination type.

Example
C++

// expre_const_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;


class CCTest {
public:
void setNumber( int );
void printNumber() const;
private:
int number;
};

void CCTest::setNumber( int num ) { number = num; }

void CCTest::printNumber() const {


cout << "\nBefore: " << number;
const_cast< CCTest * >( this )->number--;
cout << "\nAfter: " << number;
}

int main() {
CCTest X;
X.setNumber( 8 );
X.printNumber();
}

On the line containing the const_cast , the data type of the this pointer is const CCTest
* . The const_cast operator changes the data type of the this pointer to CCTest * ,

allowing the member number to be modified. The cast lasts only for the remainder of the
statement in which it appears.

See also
Casting Operators
Keywords
reinterpret_cast Operator
Article • 08/03/2021 • 2 minutes to read

Allows any pointer to be converted into any other pointer type. Also allows any integral
type to be converted into any pointer type and vice versa.

Syntax

reinterpret_cast < type-id > ( expression )

Remarks
Misuse of the reinterpret_cast operator can easily be unsafe. Unless the desired
conversion is inherently low-level, you should use one of the other cast operators.

The reinterpret_cast operator can be used for conversions such as char* to int* , or
One_class* to Unrelated_class* , which are inherently unsafe.

The result of a reinterpret_cast cannot safely be used for anything other than being
cast back to its original type. Other uses are, at best, nonportable.

The reinterpret_cast operator cannot cast away the const , volatile , or __unaligned
attributes. See const_cast Operator for information on removing these attributes.

The reinterpret_cast operator converts a null pointer value to the null pointer value of
the destination type.

One practical use of reinterpret_cast is in a hash function, which maps a value to an


index in such a way that two distinct values rarely end up with the same index.

C++

#include <iostream>
using namespace std;

// Returns a hash code based on an address


unsigned short Hash( void *p ) {
unsigned int val = reinterpret_cast<unsigned int>( p );
return ( unsigned short )( val ^ (val >> 16));
}
using namespace std;
int main() {
int a[20];
for ( int i = 0; i < 20; i++ )
cout << Hash( a + i ) << endl;
}

Output:
64641
64645
64889
64893
64881
64885
64873
64877
64865
64869
64857
64861
64849
64853
64841
64845
64833
64837
64825
64829

The reinterpret_cast allows the pointer to be treated as an integral type. The result is
then bit-shifted and XORed with itself to produce a unique index (unique to a high
degree of probability). The index is then truncated by a standard C-style cast to the
return type of the function.

See also
Casting Operators
Keywords
Run-Time Type Information
Article • 08/03/2021 • 2 minutes to read

Run-time type information (RTTI) is a mechanism that allows the type of an object to be
determined during program execution. RTTI was added to the C++ language because
many vendors of class libraries were implementing this functionality themselves. This
caused incompatibilities between libraries. Thus, it became obvious that support for run-
time type information was needed at the language level.

For the sake of clarity, this discussion of RTTI is almost completely restricted to pointers.
However, the concepts discussed also apply to references.

There are three main C++ language elements to run-time type information:

The dynamic_cast operator.

Used for conversion of polymorphic types.

The typeid operator.

Used for identifying the exact type of an object.

The type_info class.

Used to hold the type information returned by the typeid operator.

See also
Casting
bad_typeid exception
Article • 08/03/2021 • 2 minutes to read

The bad_typeid exception is thrown by the typeid operator when the operand for
typeid is a NULL pointer.

Syntax

catch (bad_typeid)
statement

Remarks
The interface for bad_typeid is:

C++

class bad_typeid : public exception


{
public:
bad_typeid();
bad_typeid(const char * _Message = "bad typeid");
bad_typeid(const bad_typeid &);
virtual ~bad_typeid();

bad_typeid& operator=(const bad_typeid&);


const char* what() const;
};

The following example shows the typeid operator throwing a bad_typeid exception.

C++

// expre_bad_typeid.cpp
// compile with: /EHsc /GR
#include <typeinfo>
#include <iostream>

class A{
public:
// object for class needs vtable
// for RTTI
virtual ~A();
};

using namespace std;


int main() {
A* a = NULL;

try {
cout << typeid(*a).name() << endl; // Error condition
}
catch (bad_typeid){
cout << "Object is NULL" << endl;
}
}

Output
Output

Object is NULL

See also
Run-Time Type Information
Keywords
type_info Class
Article • 08/03/2021 • 2 minutes to read

The type_info class describes type information generated within the program by the
compiler. Objects of this class effectively store a pointer to a name for the type. The
type_info class also stores an encoded value suitable for comparing two types for
equality or collating order. The encoding rules and collating sequence for types are
unspecified and may differ between programs.

The <typeinfo> header file must be included in order to use the type_info class. The
interface for the type_info class is:

C++

class type_info {
public:
type_info(const type_info& rhs) = delete; // cannot be copied
virtual ~type_info();
size_t hash_code() const;
_CRTIMP_PURE bool operator==(const type_info& rhs) const;
type_info& operator=(const type_info& rhs) = delete; // cannot be copied
_CRTIMP_PURE bool operator!=(const type_info& rhs) const;
_CRTIMP_PURE int before(const type_info& rhs) const;
size_t hash_code() const noexcept;
_CRTIMP_PURE const char* name() const;
_CRTIMP_PURE const char* raw_name() const;
};

You cannot instantiate objects of the type_info class directly, because the class has only
a private copy constructor. The only way to construct a (temporary) type_info object is
to use the typeid operator. Since the assignment operator is also private, you cannot
copy or assign objects of class type_info.

type_info::hash_code defines a hash function suitable for mapping values of type

typeinfo to a distribution of index values.

The operators == and != can be used to compare for equality and inequality with other
type_info objects, respectively.

There is no link between the collating order of types and inheritance relationships. Use
the type_info::before member function to determine the collating sequence of types.
There is no guarantee that type_info::before will yield the same result in different
programs or even different runs of the same program. In this manner,
type_info::before is similar to the address-of (&) operator.
The type_info::name member function returns a const char* to a null-terminated string
representing the human-readable name of the type. The memory pointed to is cached
and should never be directly deallocated.

The type_info::raw_name member function returns a const char* to a null-terminated


string representing the decorated name of the object type. The name is actually stored
in its decorated form to save space. Consequently, this function is faster than
type_info::name because it doesn't need to undecorate the name. The string returned
by the type_in