C++ Programming Guide by Microsoft
C++ Programming Guide by Microsoft
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++
8/17/2022 • 8 minutes to read • Edit Online
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.
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).
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.
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;
}
}
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 .
#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} };
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:
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
8/17/2022 • 2 minutes to read • Edit Online
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
8/17/2022 • 3 minutes to read • Edit Online
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
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:
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++)
8/17/2022 • 2 minutes to read • Edit Online
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++)
8/17/2022 • 3 minutes to read • Edit Online
_ 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.
// 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++)
8/17/2022 • 3 minutes to read • Edit Online
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.
constinit c
continue
co_await c
co_return c
co_yield c
decltype
default
delete
do
double
dynamic_cast
else
enum
explicit
c
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.
__hook d
__if_exists
__if_not_exists
__inline e
__int16 e
__int32 e
__int64 e
e
__int8 e
__interface
__leave e
__m128
__m128d
__m128i
__m64
__multiple_inheritance e
__ptr32 e
__ptr64 e
__raise
__restrict e
__single_inheritance e
__sptr e
__stdcall e
__super
__thiscall
__unaligned e
__unhook d
__uptr e
__uuidof e
__vectorcall e
__virtual_inheritance e
__w64 e
__wchar_t
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).
dllexport
dllimport
jitintrinsic
naked
noalias
noinline
noreturn
no_sanitize_address
nothrow
novtable
process
property
restrict
safebuffers
selectany
spectre
thread
uuid
__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
g
value class g
value struct g
fApplicable 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++)
8/17/2022 • 2 minutes to read • Edit Online
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:
! % ^ & * ( ) - + = { } | ~
[ ] \ ; ' : " < > ? , . / #
See also
Lexical Conventions
Numeric, boolean, and pointer literals
8/17/2022 • 5 minutes to read • Edit Online
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:
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:
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:
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:
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:
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.
18.46
38.
The exponent, if present, specifies the magnitude of the number as a power of 10, as shown in the following
example:
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
and
void func( long double );
Boolean literals
The boolean literals are true and false .
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++)
8/17/2022 • 18 minutes to read • Edit Online
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.
#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
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'
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:
newline \n
backslash \\
horizontal tab \t
question mark ? or \?
vertical tab \v
backspace \b
carriage return \r
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.
#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.
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:
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:
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".
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.
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.
// 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:-)";
You can construct a raw string literal that contains a newline (not the escaped character) in the source:
//#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 };
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 .
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:
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:
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:
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:
"\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:
std::string literals (and the related std::u8string , std::u16string , and ste::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:
See also
Character sets
Numeric, Boolean, and pointer literals
User-defined literals
User-defined literals
8/17/2022 • 6 minutes to read • Edit Online
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:
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.
// UDL_Distance.cpp
#include <iostream>
#include <string>
struct Distance
{
private:
explicit Distance(long double val) : kilometers(val)
{}
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
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:
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:
#include <cstddef>
#include <cstdio>
// 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;
}
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
8/17/2022 • 13 minutes to read • Edit Online
The concept of type is very important in C++. Every variable, function argument, and function return value must
have a type in order to be compiled. Also, every expression (including literal values) is implicitly given a type by
the compiler before it is evaluated. Some examples of types include int to store integer values, double to
store floating-point values (also known as scalar data types), or the Standard Library 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 will be allocated for the variable (or expression result), the kinds of values that may be stored in
that variable, how those values (as bit patterns) are interpreted, and the operations that can be performed on it.
This article contains an informal overview of the major features of the C++ type system.
Terminology
Variable : The symbolic name of a quantity of data so that the name can be used to access the data it refers to
throughout the scope of the code where it is defined. In C++, variable is generally used to refer to instances of
scalar data types, whereas instances of other types are usually called objects.
Object : For simplicity and consistency, this article uses the term object to refer to any instance of a class or
structure, and when it is used in the general sense 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).
The following table lists the most frequently used fundamental types, and their sizes in the Microsoft C++
implementation:
TYPE SIZ E C O M M EN T
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 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 are not
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 are part of the standard libraries that are included in any conformant C++ build
environment. Simply use the #include <string> directive to make these types available in your program. (If you
are using MFC or ATL, the CString class is also available, but is not part of the C++ standard.) The use of null-
terminated character arrays (the C-style strings previously mentioned) is strongly 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
Dating back to 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 are referred to as raw pointers, and are accessed in
your code through special operators * (asterisk) or -> (dash with greater-than). This is called dereferencing,
and which one that you use depends on whether you are 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, but 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 is
still useful and safe to use raw pointers for observing objects, but if you must use them for object ownership,
you should do so with caution and very careful consideration of how the objects owned by them are created
and destroyed.
The first thing that you should know is declaring a raw pointer variable will allocate only the memory that is
required to store an address of the memory location that the pointer will be referring to when it is dereferenced.
Allocation of the memory for the data value itself (also called backing store) is not yet allocated. In other words,
by declaring a raw pointer variable, you are creating a memory address variable, not an actual data variable.
Dereferencing a pointer variable before making sure that it contains a valid address to a backing store will cause
undefined behavior (usually a fatal error) in your program. The following example demonstrates this kind of
error:
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:
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 store 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 usually referred to as objects, especially if they are 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 is 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 strongly discouraged in modern
C++. It is almost always better to wrap a raw pointer in a smart pointer, which will automatically release the
memory when its destructor is invoked (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();
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.
More information
For more information about the C++ type system, see the following topics.
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++)
8/17/2022 • 4 minutes to read • Edit Online
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:
i = 0
i = 7
j = 9
i = 0
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.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
class Account Checking( Account ); // Qualifies Account as
// class name
The following example demonstrates how to declare a pointer to an object of type Account using the class
keyword:
The Account in the initializer (in parentheses) in the preceding statement has global scope; it is of type double .
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.
#include <iostream>
See also
Basic Concepts
Header files (C++)
8/17/2022 • 4 minutes to read • Edit Online
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'.
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.
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:
// 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!
// 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() .
// 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.
// 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 */
private:
vstr vals;
int i;
};
struct RGB
{
short r{ 0 }; // member initialization
short g{ 0 };
short b{ 0 };
};
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:
int i;
int f(int x);
class 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.
To give a const object external linkage, declare it as extern and assign it a value:
See also
Basic concepts
main function and command-line arguments
8/17/2022 • 8 minutes to read • Edit Online
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.
int main();
int main(int argc, char *argv[]);
If no return value is specified in main , the compiler supplies a return value of zero.
Microsoft-specific extensions
The following sections describe Microsoft-specific behavior.
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.
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 :
// argument_definitions.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>
// command_line_arguments.cpp
// compile with: /EHsc
#include <iostream>
"abc" d e abc d e
a\\\"b c d a\"b c d
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.
See also
Basic concepts
C++ program termination
8/17/2022 • 3 minutes to read • Edit Online
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.
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.)
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:
int main() {
ShowData sd1( "CON" ), sd2( "hello.dat" );
See also
main function and command-line arguments
Lvalues and Rvalues (C++)
8/17/2022 • 2 minutes to read • Edit Online
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 is not 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 non-reference 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:
// lvalues_and_rvalues2.cpp
int main()
{
int i, j, *p;
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
8/17/2022 • 2 minutes to read • Edit Online
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:
...
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
8/17/2022 • 4 minutes to read • Edit Online
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.
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).
// alignas_alignof.cpp
// compile with: cl /EHsc alignas_alignof.cpp
#include <iostream>
int main()
{
std::cout << alignof(Bar) << std::endl; // output: 16
}
See also
Data structure alignment
Trivial, standard-layout, POD, and literal types
8/17/2022 • 5 minutes to read • Edit Online
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.
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
};
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:
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:
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:
#include <type_traits>
#include <iostream>
struct B
{
protected:
virtual void Foo() {}
};
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
8/17/2022 • 3 minutes to read • Edit Online
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.
class MyRefType {
private:
MyRefType & operator=(const MyRefType &);
MyRefType(const MyRefType &);
public:
MyRefType () {}
};
int main()
{
MyRefType Data1, Data2;
// ...
Data1 = Data2;
}
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'
#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
#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
8/17/2022 • 9 minutes to read • Edit Online
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.
F RO M TO
float double
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.
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'.
char* s = "Help" + 3;
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.
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
//Output: d3 is null;
NOTE
This cast operator isn't used as often as the others, and it's not guaranteed to be portable to other compilers.
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
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):
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:
#include <iostream>
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:
#include <iostream>
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.
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".
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
C O N DIT IO N S M ET C O N VERSIO N
Either operand is of type long double . Other operand is converted to type long double .
C O N DIT IO N S M ET C O N VERSIO N
Preceding condition not met and either operand is of type Other operand is converted to type double .
double .
Preceding conditions not met and either operand is of type Other operand is converted to type float .
float .
Preceding conditions not met (none of the operands are of Operands get integral promotions as follows:
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:
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;
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.
C O N VERSIO N F RO M
T Y P E O F F UN C T IO N DERIVAT IO N B * TO A* L EGA L?
Protected No
Public Yes
Protected Yes
Public Yes
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.
// 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).
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.
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.
class A
{
public:
int i;
};
int A::*pai = 0;
int main()
{
}
See also
C++ language reference
Built-in types (C++)
8/17/2022 • 5 minutes to read • Edit Online
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 C O N T EN T S
long double Type long double is a floating point type that is larger
than or equal to type 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 intkeyword 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
long long , long long int , signed long long , signed 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 .
TYPE SIZ E
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
8/17/2022 • 2 minutes to read • Edit Online
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.
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 are modifiers that you can use with any integral type except bool . Note that char ,
unsigned
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
8/17/2022 • 2 minutes to read • Edit Online
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> .
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++)
8/17/2022 • 2 minutes to read • Edit Online
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 .
Example
// void.cpp
void vobject; // C2182
void *pv; // okay
int *pint; int i;
int main() {
pv = &i;
// Cast optional in C required in C++
pint = (int *)pv;
}
See also
Keywords
Built-in types
bool (C++)
8/17/2022 • 2 minutes to read • Edit Online
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:
b++;
++b;
b--;
--b;
!false == true
!true == false
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++)
8/17/2022 • 2 minutes to read • Edit Online
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
// bool_false.cpp
#include <stdio.h>
int main()
{
bool bb = true;
printf_s("%d\n", bb);
bb = false;
printf_s("%d\n", bb);
}
1
0
See also
Keywords
true (C++)
8/17/2022 • 2 minutes to read • Edit Online
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
// bool_true.cpp
#include <stdio.h>
int main()
{
bool bb = true;
printf_s("%d\n", bb);
bb = false;
printf_s("%d\n", bb);
}
1
0
See also
Keywords
char, wchar_t, char8_t, char16_t, char32_t
8/17/2022 • 2 minutes to read • Edit Online
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
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
8/17/2022 • 2 minutes to read • Edit Online
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:
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 :
// 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
}
func
See also
Keywords
Built-in types
Data Type Ranges
__m64
8/17/2022 • 2 minutes to read • Edit Online
Microsoft Specific
The __m64 data type is for use with the MMX and 3DNow! intrinsics, and is defined in <xmmintrin.h>.
// 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
8/17/2022 • 2 minutes to read • Edit Online
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>.
// 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
8/17/2022 • 2 minutes to read • Edit Online
Microsoft Specific
The __m128d data type, for use with the Streaming SIMD Extensions 2 instructions intrinsics, is defined in
<emmintrin.h>.
// 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
8/17/2022 • 2 minutes to read • Edit Online
Microsoft Specific
The __m128i data type, for use with the Streaming SIMD Extensions 2 (SSE2) instructions intrinsics, is defined in
<emmintrin.h>.
// 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.
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.
See also
Keywords
Built-in types
Data Type Ranges
__ptr32, __ptr64
8/17/2022 • 2 minutes to read • Edit Online
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:
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.
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.
#include <cstdlib>
#include <iostream>
int main()
{
using namespace std;
32
64
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
8/17/2022 • 2 minutes to read • Edit Online
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>.
CHAR_MAX Maximum value for a variable of type 127; 255 if /J option used
char .
If a value exceeds the largest integer representation, the Microsoft compiler generates an error.
See also
Floating Limits
Floating Limits
8/17/2022 • 2 minutes to read • Edit Online
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>.
FLT_GUARD 0
FLT_NORMALIZE 0
NOTE
The information in the table may differ in future versions of the product.
See also
Integer Limits
Declarations and definitions (C++)
8/17/2022 • 4 minutes to read • Edit Online
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:
#include <string>
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:
extern int i;
char *strchr( const char *Str, const char Target );
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
8/17/2022 • 8 minutes to read • Edit Online
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:
// 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.
// static1.cpp
// compile with: /EHsc
#include <iostream>
int main() {
for ( int i = 0; i < 5; i++ )
showstat( i );
}
nStatic is 0
nStatic is 1
nStatic is 3
nStatic is 6
nStatic is 10
// static2.cpp
// compile with: /EHsc
#include <iostream>
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;
}
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.
// 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);
}
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.
thread_local float f = 42.0; // Global namespace. Not implicitly static.
void DoSomething()
{
// Apply thread_local to a local variable.
// Implicitly "thread_local static S my_struct".
thread_local S my_struct;
}
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.
register int val; // warning C5033: 'register' is no longer a supported storage class
private:
char *szObjName;
size_t sizeofObjName;
};
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++)
8/17/2022 • 6 minutes to read • Edit Online
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 ;
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—this includes when a function return type is changed—
it just works.
Performance: You’re guaranteed that there will be 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 :
When you want a specific type and nothing else will do.
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.14156 }; .
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 is not itself a type. Therefore, the auto keyword cannot be
used in casts or operators such as sizeof and (for C++/CLI) typeid .
Usefulness
The autokeyword 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.
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 had not been dropped by auto .
#include <initializer_list>
int main()
{
// std::initializer_list<int>
auto A = { 1, 2 };
// std::initializer_list<int>
auto B = { 3 };
// int
auto C{ 4 };
return 0;
}
C3537 You cannot 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.
ERRO R N UM B ER DESC RIP T IO N
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.
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.
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.
int main()
{
deque<double> dqDoubleData(10, 0.1);
for (auto elem : dqDoubleData) // COPIES elements, not much better than the previous examples
{ /* ... */ }
The following code fragment uses the new operator and pointer declaration to declare pointers.
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.
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:
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 .
See also
Keywords
/Zc:auto (Deduce Variable Type)
sizeof Operator
typeid
operator new
Declarations and Definitions
Examples of Lambda Expressions
Initializers
decltype
const (C++)
8/17/2022 • 3 minutes to read • Edit Online
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.
// 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:
// 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.
// 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 .
// constant_values4.cpp
#include <stdio.h>
int main() {
const char *mybuf = "test";
char *yourbuf = "test2";
printf_s("%s\n", mybuf);
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.
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.
// 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;
};
const int i = 2;
But to get the same behavior in C++, you must declare your const variable as:
If you wish to declare an extern variable in a C++ source code file for use in a C source code file, use:
extern "C" const int x=10;
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++)
8/17/2022 • 5 minutes to read • Edit Online
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.
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.)
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 .
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.
// constexpr.cpp
// Compile with: cl /EHsc /W4 constexpr.cpp
#include <iostream>
// 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;
}
// 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++)
8/17/2022 • 4 minutes to read • Edit Online
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.
//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)
//fileB.cpp
extern const int i; // declaration only. same as i in FileA
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:
Example
The following example shows how to declare names that have C linkage:
// Declare printf with C linkage.
extern "C" int printf(const char *fmt, ...);
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:
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
8/17/2022 • 12 minutes to read • Edit Online
An initializer specifies the initial value of a variable. You can initialize variables in these contexts:
In the definition of a variable:
int i = 3;
Point p1{ 1, 2 };
set_point(Point{ 5, 6 });
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:
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 are not 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:
struct my_struct{
int i;
char c;
};
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:
MyClass mc1;
MyClass* mc3 = new MyClass;
If the class, struct, or union does not have a default constructor, the compiler emits an error.
Scalar variables are default initialized when they are defined with no initialization expression. They have
indeterminate values.
int i1;
float f;
char c;
Arrays are default initialized when they are 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:
int int_arr[3];
If the array members do not 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 are scalar types they cause a compiler
error, and if they are class types that have a default constructor they cause a warning:
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
}
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 non-union 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
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:
#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();
}
}
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:
class BaseClass{
public:
BaseClass(int n) :m_int(n){} // m_int is direct initialized
private:
int m_int;
};
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:
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' });
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
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:
#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 };
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.
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'
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:
// 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 cannot 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:
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.
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
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++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++11
using fmtfl = std::ios_base::fmtflags;
// C++03 equivalent:
// typedef std::ios_base::fmtflags fmtfl;
Aliases also work with function pointers, but are much more readable than the equivalent typedef:
// C++11
using func = void(*)(int);
// C++03 equivalent:
// typedef void (*func)(int);
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:
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.
#include <stdlib.h>
#include <new>
MyAlloc() { }
template <typename U> MyAlloc(const MyAlloc<U>&) { }
if (!pv) {
throw std::bad_alloc();
}
#include <vector>
using MyIntVector = std::vector<int, MyAlloc<int>>;
#include <iostream>
int main ()
{
MyIntVector foov = { 1701, 1764, 1664 };
return 0;
}
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:
// 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++:
// typedef_names2.cpp
typedef unsigned long UL; // Declare a typedef name, UL
int main()
{
unsigned int UL; // Redeclaration hides typedef name
}
// typedef_specifier1.cpp
typedef char FlagType;
int main()
{
}
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:
To reuse the FlagType name for an identifier, a structure member, or a union member, the type must be
provided:
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:
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:
To use typedef to specify fundamental and derived types in the same declaration, you can separate declarators
with commas. For example:
The following example provides the type DRAWF for a function returning no value and taking two int arguments:
DRAWF box;
typedef is often combined with struct to declare and name user-defined types:
// typedef_specifier2.cpp
#include <stdio.h>
int main()
{
mystruct ms;
ms.i = 10;
ms.f = 0.99;
printf_s("%d %f\n", ms.i, ms.f);
}
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 :
// file1.h
typedef char CHAR;
// file2.h
typedef char CHAR;
// 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 :
// 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:
// 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;
instead of:
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.
// 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
8/17/2022 • 5 minutes to read • Edit Online
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.
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');
}
In D::f()
In B::f()
In B::g()
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');
}
In B::f()
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();
}
In h
In f
In A::g
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);
}
// 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.
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)
}
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)
};
int main() {
D * myd = new D();
f(myd);
}
In D::f(int)
In B::f(char)
In B::g
In D::g(char)
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++)
8/17/2022 • 3 minutes to read • Edit Online
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.
NOTE
When it relies on the enhanced guarantee that's provided when the /volatile:ms compiler option is used, the code is
non-portable.
See also
Keywords
const
const and volatile Pointers
decltype (C++)
8/17/2022 • 5 minutes to read • Edit Online
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 template function whose return type depends on the types of its template arguments. Or, use auto
and decltype to declare a template function 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 is 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 have
coded the following statements.
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.
STAT EM EN T TYPE N OT ES
The introduction of the decltype type specifier enables a developer to obtain the type of the expression that the
template function 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 is coded.
The following prototype illustrates the syntax of an alternative function declaration. Note that 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 ( parametersopt ) const opt volatile opt -> decltype( expression ) noexcept opt
{ function_body };
In the following code example, the late-specified return type of the myFunc template function 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++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); };
Examples
The following code example declares the late-specified return type of template function Plus() . The Plus
function processes its two operands with the operator+ overload. Consequently, the interpretation of the plus
operator ( + ) and the return type of the Plus function depends on the types of the function arguments.
// decltype_1.cpp
// compile with: cl /EHsc decltype_1.cpp
#include <iostream>
#include <string>
#include <utility>
#include <iomanip>
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;
}
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. Consequently, if a non-dependent specialization is found in the decltype argument, it
will not be deferred to instantiation-time and will be processed immediately and any resulting errors will be
diagnosed at that time.
The following example shows such a compiler error that is raised at the point of declaration:
#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;
};
Requirements
Visual Studio 2010 or later versions.
decltype(auto) requires Visual Studio 2015 or later.
Attributes in C++
8/17/2022 • 5 minutes to read • Edit Online
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:
void g() {
[[using rpr: kernel, target(cpu,gpu)]] // equivalent to [[ rpr::kernel, rpr::target(cpu,gpu) ]]
do task();
}
[[deprecated]]
void Foo(int);
[[nodiscard]]
int foo(int i) { return i * i; }
int main()
{
foo(42); //warning C4834: discarding return value of function with 'nodiscard' attribute
return 0;
}
[[maybe_unused]] Visual Studio 2017 version 15.3 and later : (Available with /std:c++17 and later.)
Specifies that a variable, function, class, typedef, non-static 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.
[[likely]] Visual Studio 2019 version 16.6 and later : (Available with /std:c++20 and later.)
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 re-ordering
optimization is not yet implemented for this attribute.
[[unlikely]] Visual Studio 2019 version 16.6 and later : (Available with /std:c++20 and later.)
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 re-ordering optimization is not yet implemented for
this attribute.
Microsoft-specific attributes
[[gsl::suppress(rules)]] This Microsoft-specific attribute is used for suppressing warnings from
checkers that enforce Guidelines Support Library (GSL) rules in code. For example, consider this code
snippet:
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 C++ language includes all C operators and adds several new operators. Operators specify an evaluation to
be performed on one or more operands.
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.
Group 1 precedence, no
associativity
Scope resolution ::
Array subscript []
Function call ()
Postfix increment ++
Postfix decrement --
Prefix increment ++
Prefix decrement --
Unary negation -
Unary plus +
Address-of &
Indirection *
Cast ()
Multiplication *
Division /
Modulus %
O P ERATO R DESC RIP T IO N O P ERATO R A LT ERN AT IVE
Addition +
Subtraction -
Equality ==
Inequality != not_eq
Logical OR || or
Conditional ? :
Assignment =
Multiplication assignment *=
Division assignment /=
Modulus assignment %=
Addition assignment +=
Subtraction assignment -=
Comma ,
See also
Operator overloading
alignof operator
8/17/2022 • 2 minutes to read • Edit Online
The alignof operator returns the alignment in bytes of the specified type as a value of type size_t .
Syntax
alignof( type )
Remarks
For example:
EXP RESSIO N VA L UE
alignof( char ) 1
alignof( short ) 2
alignof( int ) 4
alignof( float ) 4
alignof( double ) 8
The alignof value is the same as the value for sizeof for basic types. Consider, however, this example:
In this case, the alignof value is the alignment requirement of the largest element in the structure.
Similarly, for
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.
See also
Expressions with Unary Operators
Keywords
__uuidof Operator
8/17/2022 • 2 minutes to read • Edit Online
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.
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:
// 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:
StringFromCLSID(__LIBID_, &lpolestr);
See also
Expressions with Unary Operators
Keywords
Additive Operators: + and -
8/17/2022 • 2 minutes to read • Edit Online
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 M EA N IN G
integral Types char and int of all sizes (long, short) and enumerations
are "integral" types.
Example
// 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;
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:
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.
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: &
8/17/2022 • 2 minutes to read • Edit Online
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.
// 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:
// 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.
// expre_Address_Of_Operator3.cpp
// compile with: /EHsc
// Demonstrate address-of operator &
#include <iostream>
using namespace std;
int main() {
int mynum = 5;
cout << square( &mynum ) << endl; // pass address of int
}
25
See also
Expressions with unary operators
C++ built-in operators, precedence, and associativity
Lvalue reference declarator: &
Indirection and address-of operators
Assignment operators
8/17/2022 • 5 minutes to read • Edit Online
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
O P ERATO R M EA N IN G
+= 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.
<<= 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.
O P ERATO R M EA N IN G
>>= 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.
Operator keywords
Three of the compound assignment operators have keyword equivalents. They are:
O P ERATO R EQ UIVA L EN T
&= 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
// 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
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:
// expre_SimpleAssignment.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class ABase
{
public:
ABase() { cout << "constructing ABase\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
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
UserType1 A;
UserType2 B;
B = A;
the assignment statement
B = A;
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 -
See also
Expressions with binary operators
C++ built-in operators, precedence, and associativity
C assignment operators
Bitwise AND operator: &
8/17/2022 • 2 minutes to read • Edit Online
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.
Example
// 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: ^
8/17/2022 • 2 minutes to read • Edit Online
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).
Example
// 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: |
8/17/2022 • 2 minutes to read • Edit Online
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.
Example
// 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: ()
8/17/2022 • 2 minutes to read • Edit Online
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:
// expre_CastOperator.cpp
// compile with: /EHsc
// Demonstrate cast operator
#include <iostream>
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;
}
class CountedAnsiString
{
public:
// Assume source is not null terminated
CountedAnsiString(const char *pStr, size_t nSize) :
m_nSize(nSize)
{
m_pStr = new char[sizeOfBuffer];
//
// 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);
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:
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
// 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);
}
20
30
See also
Expressions with Binary Operators
C++ Built-in Operators, Precedence and Associativity
Sequential-Evaluation Operator
Conditional Operator: ?:
8/17/2022 • 2 minutes to read • Edit Online
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.
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
// 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++)
8/17/2022 • 2 minutes to read • Edit Online
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:
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 :
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:
// 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.
See also
Expressions with Unary Operators
Keywords
new and delete Operators
Equality operators: == and !=
8/17/2022 • 2 minutes to read • Edit Online
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 .
Example
// expre_Equality_Operators.cpp
// compile with: /EHsc
#include <iostream>
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: ()
8/17/2022 • 2 minutes to read • Edit Online
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:
int i = int( d );
Example
// expre_Explicit_Type_Conversion_Operator.cpp
// compile with: /EHsc
#include <iostream>
int main()
{
Point Point1, Point2;
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:
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:
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:
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 .
Cau t i on
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: ()
8/17/2022 • 3 minutes to read • Edit Online
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
T func( int i );
T (*func)( int i );
T (&func)(int i);
Example
The following example calls the standard library function strcat_s with three arguments:
// expre_Function_Call_Operator.cpp
// compile with: /EHsc
#include <iostream>
#include <string>
int main()
{
enum
{
sizeOfBuffer = 20
};
Welcome to C++
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:
// 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: *
8/17/2022 • 2 minutes to read • Edit Online
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:
// 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;
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 >> )
8/17/2022 • 5 minutes to read • Edit Online
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 :
&emsp additive-expression
&emsp shift-expression << additive-expression
&emsp 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.
#include <iostream>
#include <bitset>
int main() {
unsigned short short1 = 4;
bitset<16> bitset1{short1}; // the bitset representation of 4
cout << bitset1 << endl; // 0b00000000'00000100
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.
#include <iostream>
#include <bitset>
int main() {
short short1 = 16384;
bitset<16> bitset1(short1);
cout << bitset1 << endl; // 0b01000000'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.
#include <iostream>
#include <bitset>
int main() {
unsigned short short11 = 1024;
bitset<16> bitset11{short11};
cout << bitset11 << endl; // 0b00000100'00000000
The next example shows right-shift operations with positive signed numbers.
#include <iostream>
#include <bitset>
int main() {
short short1 = 1024;
bitset<16> bitset1(short1);
cout << bitset1 << endl; // 0b00000100'00000000
The next example shows right-shift operations with negative signed integers.
#include <iostream>
#include <bitset>
int main() {
short neg1 = -16;
bitset<16> bn1(neg1);
cout << bn1 << endl; // 0b11111111'11110000
int main() {
char char1 = 'a';
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.
#include <iostream>
#include <bitset>
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 × 2 E2 , 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 × 2 E2 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/2 E2 . 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: &&
8/17/2022 • 2 minutes to read • Edit Online
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:
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.
Example
// expre_Logical_AND_Operator.cpp
// compile with: /EHsc
// Demonstrate logical AND
#include <iostream>
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: !
8/17/2022 • 2 minutes to read • Edit Online
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.
Example
// 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: ||
8/17/2022 • 2 minutes to read • Edit Online
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.
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.
Example
// 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 ->
8/17/2022 • 2 minutes to read • Edit Online
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.
// 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;
See also
Postfix expressions
C++ built-in operators, precedence, and associativity
Classes and Structs
Structure and union members
Multiplicative Operators and the Modulus Operator
8/17/2022 • 2 minutes to read • Edit Online
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:
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.
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.
// 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++)
8/17/2022 • 8 minutes to read • Edit Online
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.
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.
The type-id can't contain const , volatile , class declarations, or enumeration declarations. The following
expression is ill-formed:
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.
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.
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");
int main() {
A a;
}
// 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.
// 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];
Once the pointer AnotherArray goes out of scope in the example, the object can no longer be deleted.
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.
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:
See also
Expressions with unary operators
Keywords
new and delete operators
One's complement operator: ~
8/17/2022 • 2 minutes to read • Edit Online
Syntax
~ 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.
Example
// expre_One_Complement_Operator.cpp
// compile with: /EHsc
#include <iostream>
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 ->*
8/17/2022 • 2 minutes to read • Edit Online
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:
// expre_Expressions_with_Pointer_Member_Operators.cpp
// compile with: /EHsc
#include <iostream>
class Testpm {
public:
void m_func1() { cout << "m_func1\n"; }
int m_num;
};
int main() {
Testpm ATestpm;
Testpm *pTestpm = new Testpm;
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:
// expre_Expressions_with_Pointer_Member_Operators2.cpp
// C2440 expected
class BaseClass {
public:
BaseClass(); // Base class constructor.
void Func1();
};
int main() {
BaseClass ABase;
Derived ADerived;
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.
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 --
8/17/2022 • 2 minutes to read • Edit Online
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:
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:
// 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;
}
See also
Postfix Expressions
C++ Built-in Operators, Precedence and Associativity
C Postfix Increment and Decrement Operators
Prefix Increment and Decrement Operators: ++ and
--
8/17/2022 • 2 minutes to read • Edit Online
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 ":
// expre_Increment_and_Decrement_Operators.cpp
// compile with: /EHsc
#include <iostream>
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:
// 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 );
}
k = ((++i)<(j))?(j):(++i);
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 >=
8/17/2022 • 2 minutes to read • Edit Online
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
// expre_Relational_Operators.cpp
// compile with: /EHsc
#include <iostream>
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:
(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: ::
8/17/2022 • 2 minutes to read • Edit Online
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.
int main() {
A scope resolution operator without a scope qualifier refers to the global namespace.
namespace NamespaceA{
int x;
}
int x;
int main() {
int x;
// the x in main()
x = 0;
// The x in the global namespace
::x = 1;
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.
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 .
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 ;
}
class ClassG {
public:
static int get_x() { return x;}
static int x;
};
int ClassG::x = 6;
int main() {
int main() {
EnumA enum_value = EnumA::First;
}
See also
C++ built-in operators, precedence, and associativity
Namespaces
sizeof Operator
8/17/2022 • 2 minutes to read • Edit Online
Yields the size of its operand with respect to the size of type char .
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
#include <iostream>
using namespace std;
int main()
{
char szHello[] = "Hello, world!";
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:
See also
Expressions with Unary Operators
Keywords
Subscript Operator []
8/17/2022 • 3 minutes to read • Edit Online
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:
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:
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:
// expre_Subscript_Operator.cpp
// compile with: /EHsc
#include <iostream>
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;
}
#include <iostream>
using namespace std;
int main() {
int intArray[1024];
for (int i = 0, j = 0; i < 1024; i++)
{
intArray[i] = j++;
}
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
8/17/2022 • 2 minutes to read • Edit Online
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:
// expre_typeid_Operator.cpp
// compile with: /GR /EHsc
#include <iostream>
#include <typeinfo>
class Base {
public:
virtual void vvfunc() {}
};
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:
// 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:
// 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 -
8/17/2022 • 2 minutes to read • Edit Online
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++)
8/17/2022 • 2 minutes to read • Edit Online
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)
NOTE
Operators for built-in types cannot be overloaded; their behavior is predefined.
See also
C++ Language Reference
Types of Expressions
8/17/2022 • 2 minutes to read • Edit Online
See also
Expressions
Primary Expressions
8/17/2022 • 2 minutes to read • Edit Online
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 :
// 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:
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:
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
8/17/2022 • 3 minutes to read • Edit Online
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 because 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 template class definition syntax:
For both parameter packs and expansions, you can add whitespace around the ellipsis, based on your
preference, as shown in these examples:
Or this:
Notice that 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:
By using a variadic template class definition, you can also require at least one parameter:
The Arguments parameter pack is then expanded for use, as shown in the next section, Understanding
variadic templates .
Other forms of variadic template function syntax are possible—including, but not limited to, these examples:
As with variadic template class definitions, you can make functions that require at least one parameter:
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):
template<typename... Arguments>
void tfunc(const Arguments&... args)
{
constexpr auto numargs{ sizeof...(Arguments) };
helper_func(xobj, args...);
}
Where the ellipsis appears immediately after a parameter name, you have a parameter pack expansion.
Example
A good way to illustrate the variadic template function mechanism is to use it in a re-write of some of the
functionality of printf :
#include <iostream>
void print() {
cout << 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
Output
1
10, 20
100, 200, 300
first, 2, third, 3.14159
NOTE
Most implementations that incorporate variadic template functions 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
8/17/2022 • 6 minutes to read • Edit Online
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
O P ERATO R N A M E O P ERATO R N OTAT IO N
Subscript operator []
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:
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
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 .
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:
// expre_Formal_and_Actual_Arguments.cpp
void func( long param1, double param2 );
int main()
{
long i = 1;
double j = 2;
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).
// 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;
}
// expre_Ellipsis_and_Default_Arguments.cpp
// compile with: /EHsc
#include <iostream>
int main()
{
print( "hello," );
print( "world!" );
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
hello,
world!
good morning, sunshine.
See also
Types of Expressions
Expressions with Unary Operators
8/17/2022 • 2 minutes to read • Edit Online
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
8/17/2022 • 2 minutes to read • Edit Online
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
8/17/2022 • 2 minutes to read • Edit Online
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:
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
8/17/2022 • 4 minutes to read • Edit Online
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:
// Order_of_Evaluation.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
int a = 2, b = 4, c = 9;
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.
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
T Y P E EXP EC T ED T Y P ES A L LO W ED
type * type *
const type *
volatile type *
volatile const 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.
See also
Expressions
Casting
8/17/2022 • 2 minutes to read • Edit Online
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.
See also
Expressions
Casting Operators
8/17/2022 • 2 minutes to read • Edit Online
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
8/17/2022 • 7 minutes to read • Edit Online
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
is 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, with
the cast failing at runtime. The cast will now return the 0 pointer value instead of throwing.
If type-id is a pointer to an unambiguous accessible direct or indirect base class of expression , a pointer to the
unique subobject of type type-id is the result. For example:
// dynamic_cast_1.cpp
// compile with: /c
class B { };
class C : public B { };
class D : public C { };
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 is 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:
// 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 is not 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:
// 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;
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:
// dynamic_cast_clr.cpp
// compile with: /clr
using namespace System;
int main() {
Object^o1 = "hello";
Object^o2 = 10;
PrintObjectType(o1);
PrintObjectType(o2);
}
// 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.
// 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();};
The dynamic_cast operator can also be used to perform a "cross cast." Using the same class hierarchy, it is
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 is actually 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:
// 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();};
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 cannot be safely converted to type
type-id , the run-time check causes the cast to fail. For example:
// 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 does not 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 non-virtual function in the hierarchy.
// 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);
See also
Casting Operators
Keywords
bad_cast exception
8/17/2022 • 2 minutes to read • Edit Online
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:
The following code contains an example of a failed dynamic_cast that throws the bad_cast exception.
// expre_bad_cast_Exception.cpp
// compile with: /EHsc /GR
#include <typeinfo>
#include <iostream>
class Shape {
public:
virtual void virtualfunc() const {}
};
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 :
Circle circle_instance;
Circle& ref_circle = circle_instance;
Then reverse the sense of the cast in the try block as follows:
Shape& ref_shape = dynamic_cast<Shape&>(ref_circle);
Members
Constructors
C O N ST RUC TO R DESC RIP T IO N
Functions
F UN C T IO N DESC RIP T IO N
what TBD
Operators
O P ERATO R DESC RIP T IO N
bad_cast
The constructor for objects of type bad_cast .
operator=
An assignment operator that assigns one bad_cast object to another.
what
const char* what() const noexcept override;
See also
dynamic_cast Operator
Keywords
Modern C++ best practices for exceptions and error handling
static_cast Operator
8/17/2022 • 4 minutes to read • Edit Online
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 .
// static_cast_Operator.cpp
// compile with: /LD
class 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:
// static_cast_Operator_2.cpp
// compile with: /LD /GR
class B {
public:
virtual void Test(){}
};
class D : public B {};
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:
// 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;
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
8/17/2022 • 2 minutes to read • Edit Online
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
// expre_const_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>
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
8/17/2022 • 2 minutes to read • Edit Online
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_castoperator 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.
#include <iostream>
using namespace std;
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
8/17/2022 • 2 minutes to read • Edit Online
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
8/17/2022 • 2 minutes to read • Edit Online
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:
The following example shows the typeid operator throwing a bad_typeid exception.
// expre_bad_typeid.cpp
// compile with: /EHsc /GR
#include <typeinfo>
#include <iostream>
class A{
public:
// object for class needs vtable
// for RTTI
virtual ~A();
};
try {
cout << typeid(*a).name() << endl; // Error condition
}
catch (bad_typeid){
cout << "Object is NULL" << endl;
}
}
Output
Object is NULL
See also
Run-Time Type Information
Keywords
type_info Class
8/17/2022 • 2 minutes to read • Edit Online
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:
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_info::raw_name function is useful in comparison operations but is not readable. If
you need a human-readable string, use the type_info::name function instead.
Type information is generated for polymorphic classes only if the /GR (Enable Run-Time Type Information)
compiler option is specified.
See also
Run-Time Type Information
Statements (C++)
8/17/2022 • 2 minutes to read • Edit Online
C++ statements are the program elements that control how and in what order objects are manipulated. This
section includes:
Overview
Labeled Statements
Categories of Statements
Expression statements. These statements evaluate an expression for its side effects or for its return
value.
Null statements. These statements can be provided where a statement is required by the C++
syntax but where no action is to be taken.
Compound statements. These statements are groups of statements enclosed in curly braces ({ }).
They can be used wherever a single statement may be used.
Selection statements. These statements perform a test; they then execute one section of code if the
test evaluates to true (nonzero). They may execute another section of code if the test evaluates to
false.
Iteration statements. These statements provide for repeated execution of a block of code until a
specified termination criterion is met.
Jump statements. These statements either transfer control immediately to another location in the
function or return control from the function.
Declaration statements. Declarations introduce a name into a program.
For information on exception handling statements see Exception Handling.
See also
C++ Language Reference
Overview of C++ Statements
8/17/2022 • 2 minutes to read • Edit Online
C++ statements are executed sequentially, except when an expression statement, a selection statement, an
iteration statement, or a jump statement specifically modifies that sequence.
Statements may be of the following types:
labeled-statement
expression-statement
compound-statement
selection-statement
iteration-statement
jump-statement
declaration-statement
try-throw-catch
In most cases, the C++ statement syntax is identical to that of ANSI C89. The primary difference between the
two is that in C89, declarations are allowed only at the start of a block; C++ adds the declaration-statement ,
which effectively removes this restriction. This enables you to introduce variables at a point in the program