C++ Development in Visual Studio
C++ Development in Visual Studio
a DOWNLOAD
b GET STARTED
q VIDEO
d TRAINING
h WHAT'S NEW
e OVERVIEW
i REFERENCE
Compiler reference
Linker reference
C++ language
i REFERENCE
C++ keywords
C++ operators
i REFERENCE
Iterators
Algorithms
Allocators
Function objects
iostream programming
Regular expressions
For an overview of Modern C++ programming practices, see Welcome Back to C++.
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.
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.
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.
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.
Microsoft Extensions
Microsoft extensions to C++.
Nonstandard Behavior
Information about nonstandard behavior of the Microsoft C++ compiler.
Related Sections
Component Extensions for Runtime Platforms
Reference material on using the Microsoft C++ compiler to target .NET.
See also
C Language Reference
Welcome back to C++ - Modern C++
Article • 11/07/2022 • 8 minutes to read
Since its creation, C++ has become one of the most widely used programming
languages in the world. Well-written C++ programs are fast and efficient. The language
is more flexible than other languages: It can work at the highest levels of abstraction,
and down at the level of the silicon. C++ supplies highly optimized standard libraries. It
enables access to low-level hardware features, to maximize speed and minimize memory
requirements. C++ can create almost any kind of program: Games, device drivers, HPC,
cloud, desktop, embedded, and mobile apps, and much more. Even libraries and
compilers for other programming languages get written in C++.
One of the original requirements for C++ was backward compatibility with the C
language. As a result, C++ has always permitted C-style programming, with raw
pointers, arrays, null-terminated character strings, and other features. They may enable
great performance, but can also spawn bugs and complexity. The evolution of C++ has
emphasized features that greatly reduce the need to use C-style idioms. The old C-
programming facilities are still there when you need them. However, in modern C++
code you should need them less and less. Modern C++ code is simpler, safer, more
elegant, and still as fast as ever.
The following sections provide an overview of the main features of modern C++. Unless
noted otherwise, the features listed here are available in C++11 and later. In the
Microsoft C++ compiler, you can set the /std compiler option to specify which version
of the standard to use for your project.
To support easy adoption of RAII principles, the C++ Standard Library provides three
smart pointer types: std::unique_ptr, std::shared_ptr, and std::weak_ptr. A smart pointer
handles the allocation and deletion of the memory it owns. The following example
shows a class with an array member that is allocated on the heap in the call to
make_unique() . The calls to new and delete are encapsulated by the unique_ptr class.
When a widget object goes out of scope, the unique_ptr destructor will be invoked and
it will release the memory that was allocated for the array.
C++
#include <memory>
class widget
{
private:
std::unique_ptr<int[]> data;
public:
widget(const int size) { data = std::make_unique<int[]>(size); }
void do_something() {}
};
void functionUsingWidget() {
widget w(1000000); // lifetime automatically tied to enclosing scope
// constructs w, including the w.data gadget member
// ...
w.do_something();
// ...
} // automatic destruction and deallocation for w and w.data
Whenever possible, use a smart pointer to manage heap memory. If you must use the
new and delete operators explicitly, follow the principle of RAII. For more information,
see Object lifetime and resource management (RAII).
C++
vector<string> apples;
apples.push_back("Granny Smith");
Use map (not unordered_map ) as the default associative container. Use set, multimap,
and multiset for degenerate and multi cases.
C++
The array type when embedding is important, for example, as a class member.
Don't use C-style arrays. For older APIs that need direct access to the data, use accessor
methods such as f(vec.data(), vec.size()); instead. For more information about
containers, see C++ Standard Library Containers.
for_each , the default traversal algorithm (along with range-based for loops).
sort , lower_bound , and the other default sorting and searching algorithms.
To write a comparator, use strict < and use named lambdas when you can.
C++
C++
C++
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v {1,2,3};
// C-style
for(int i = 0; i < v.size(); ++i)
{
std::cout << v[i];
}
// Modern C++:
for(auto& num : v)
{
std::cout << num;
}
}
C++
Uniform initialization
In modern C++, you can use brace initialization for any type. This form of initialization is
especially convenient when initializing arrays, vectors, or other containers. In the
following example, v2 is initialized with three instances of S . v3 is initialized with three
instances of S that are themselves initialized using braces. The compiler infers the type
of each element based on the declared type of v3 .
C++
#include <vector>
struct S
{
std::string name;
float num;
S(std::string s, float f) : name(s), num(f) {}
};
int main()
{
// C-style initialization
std::vector<S> v;
S s1("Norah", 2.7);
S s2("Frank", 3.5);
S s3("Jeri", 85.9);
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
// Modern C++:
std::vector<S> v2 {s1, s2, s3};
// or...
std::vector<S> v3{ {"Norah", 2.7}, {"Frank", 3.5}, {"Jeri", 85.9} };
Move semantics
Modern C++ provides move semantics, which make it possible to eliminate unnecessary
memory copies. In earlier versions of the language, copies were unavoidable in certain
situations. A move operation transfers ownership of a resource from one object to the
next without making a copy. Some classes own resources such as heap memory, file
handles, and so on. When you implement a resource-owning class, you can define a
move constructor and move assignment operator for it. The compiler chooses these
special members during overload resolution in situations where a copy isn't needed. The
Standard Library container types invoke the move constructor on objects if one is
defined. For more information, see Move Constructors and Move Assignment Operators
(C++).
Lambda expressions
In C-style programming, a function can be passed to another function by using a
function pointer. Function pointers are inconvenient to maintain and understand. The
function they refer to may be defined elsewhere in the source code, far away from the
point at which it's invoked. Also, they're not type-safe. Modern C++ provides function
objects, classes that override the operator() operator, which enables them to be called
like a function. The most convenient way to create function objects is with inline lambda
expressions. The following example shows how to use a lambda expression to pass a
function object, that the find_if function will invoke on each element in the vector:
C++
std::vector<int> v {1,2,3,4,5};
int x = 2;
int y = 4;
auto result = find_if(begin(v), end(v), [=](int i) { return i > x && i <
y; });
The lambda expression [=](int i) { return i > x && i < y; } can be read as "function
that takes a single argument of type int and returns a boolean that indicates whether
the argument is greater than x and less than y ." Notice that the variables x and y
from the surrounding context can be used in the lambda. The [=] specifies that those
variables are captured by value; in other words, the lambda expression has its own
copies of those values.
Exceptions
Modern C++ emphasizes exceptions, not error codes, as the best way to report and
handle error conditions. For more information, see Modern C++ best practices for
exceptions and error handling.
std::atomic
Use the C++ Standard Library std::atomic struct and related types for inter-thread
communication mechanisms.
std::variant (C++17)
Unions are commonly used in C-style programming to conserve memory by enabling
members of different types to occupy the same memory location. However, unions
aren't type-safe and are prone to programming errors. C++17 introduces the
std::variant class as a more robust and safe alternative to unions. The std::visit function
can be used to access the members of a variant type in a type-safe manner.
See also
C++ Language Reference
Lambda Expressions
C++ Standard Library
Microsoft C/C++ language conformance
Lexical conventions
Article • 08/03/2021 • 2 minutes to read
This section introduces the fundamental elements of a C++ program. You use these
elements, called "lexical elements" or "tokens" to construct statements, definitions,
declarations, and so on, which are used to construct complete programs. The following
lexical elements are discussed in this section:
For more information about how C++ source files are parsed, see Phases of translation.
See also
C++ Language Reference
Translation units and linkage
Tokens and character sets
Article • 08/03/2021 • 3 minutes to read
The text of a C++ program consists of tokens and white space. A token is the smallest
element of a C++ program that is meaningful to the compiler. The C++ parser
recognizes these kinds of tokens:
Keywords
Identifiers
Numeric, Boolean and Pointer Literals
String and Character Literals
User-Defined Literals
Operators
Punctuators
Tokens are usually separated by white space, which can be one or more:
Blanks
Horizontal or vertical tabs
New lines
Form feeds
Comments
a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9
Microsoft Specific
MSVC includes the $ character as a member of the basic source character set. MSVC
also allows an additional set of characters to be used in source files, based on the file
encoding. By default, Visual Studio stores source files by using the default codepage.
When source files are saved by using a locale-specific codepage or a Unicode codepage,
MSVC allows you to use any of the characters of that code page in your source code,
except for the control codes not explicitly allowed in the basic source character set. For
example, you can put Japanese characters in comments, identifiers, or string literals if
you save the file using a Japanese codepage. MSVC does not allow character sequences
that cannot be translated into valid multibyte characters or Unicode code points.
Depending on compiler options, not all allowed characters may appear in identifiers. For
more information, see Identifiers.
Universal character names can be used in identifiers and in string and character literals.
A universal character name cannot be used to represent a surrogate code point in the
range 0xD800-0xDFFF. Instead, use the desired code point; the compiler automatically
generates any required surrogates. Additional restrictions apply to the universal
character names that can be used in identifiers. For more information, see Identifiers
and String and Character Literals.
Microsoft Specific
The Microsoft C++ compiler treats a character in universal character name form and
literal form interchangeably. For example, you can declare an identifier using universal
character name form, and use it in literal form:
C++
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.
See also
Lexical Conventions
Identifiers (C++)
Article • 08/03/2021 • 3 minutes to read
typedef name
Label name
Macro name
Macro parameter
_ 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:
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:
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:
The dollar sign $ is a valid identifier character in the Microsoft C++ compiler (MSVC).
MSVC also allows you to use the actual characters represented by the allowed ranges of
universal character names in identifiers. To use these characters, you must save the file
by using a file encoding codepage that includes them. This example shows how both
extended characters and universal character names can be used interchangeably in your
code.
C++
// extended_identifier.cpp
// In Visual Studio, use File, Advanced Save Options to set
// the file encoding to Unicode codepage 1200
struct テスト // Japanese 'test'
{
void トスト() {} // Japanese 'toast'
};
int main() {
テスト \u30D1\u30F3; // Japanese パン 'bread' in UCN form
パン.トスト(); // compiler recognizes UCN or literal form
}
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.
See also
Lexical Conventions
Keywords (C++)
Article • 09/21/2021 • 3 minutes to read
Keywords are predefined reserved identifiers that have special meanings. They can't be
used as identifiers in your program. The following keywords are reserved for Microsoft
C++. Names with leading underscores and names specified for C++/CX and C++/CLI
are Microsoft extensions.
const
const_cast
consteval c
constexpr
constinit c
continue
co_await c
co_return c
co_yield c
decltype
default
delete
do
double
dynamic_cast
else
enum
explicit
export c
extern
false
float
for
friend
goto
if
inline
int
long
mutable
namespace
new
noexcept
not b
not_eq b
nullptr
operator
or b
or_eq b
private
protected
public
register reinterpret_cast
requires c
return
short
signed
sizeof
static
static_assert
static_cast
struct
switch
template
this
thread_local
throw
true
try
typedef
typeid
typename
union
unsigned
using declaration
using directive
virtual
void
volatile
wchar_t
while
xor b
xor_eq b
a The Microsoft-specific __asm keyword replaces C++ asm syntax. asm is reserved for
compatibility with other C++ implementations, but not implemented. Use __asm for
inline assembly on x86 targets. Microsoft C++ doesn't support Inline assembly for other
targets.
b
The extended operator synonyms are keywords when /permissive- or /Za (Disable
language extensions) is specified. They aren't keywords when Microsoft extensions are
enabled.
c
Supported when /std:c++20 or later (such as /std:c++latest ) is specified.
Microsoft extensions are enabled by default. To ensure that your programs are fully
portable, you can disable Microsoft extensions by specifying the /permissive- or /Za
(Disable language extensions) option during compilation. These options disable some
Microsoft-specific keywords.
When Microsoft extensions are enabled, you can use the Microsoft-specific keywords in
your programs. For ANSI conformance, these keywords are prefaced by a double
underscore. For backward compatibility, single-underscore versions of many of the
double-underscored keywords are supported. The __cdecl keyword is available with no
leading underscore.
The __asm keyword replaces C++ asm syntax. asm is reserved for compatibility with
other C++ implementations, but not implemented. Use __asm .
The __based keyword has limited uses for 32-bit and 64-bit target compilations.
__alignof e
__asm e
__assume e
__based e
__cdecl e
__declspec e
__event
__except e
__fastcall e
__finally e
__forceinline e
__hook d
__if_exists
__if_not_exists
__inline e
__int16 e
__int32 e
__int64 e
__int8 e
__interface
__leave e
__m128
__m128d
__m128i
__m64
__multiple_inheritance e
__ptr32 e
__ptr64e
__raise
__restrict e
__single_inheritancee
__sptre
__stdcall e
__super
__thiscall
__unaligned e
__unhook d
__uptr e
__uuidof e
__vectorcall e
__virtual_inheritance e
__w64 e
__wchar_t
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).
align
allocate
allocator
appdomain
code_seg
deprecated
dllexport
dllimport
jitintrinsic
naked
noalias
noinline
noreturn
no_sanitize_address
nothrow
novtable
process
property
restrict
safebuffers
selectany
spectre
thread
uuid
__sealed f
__try_cast f
__value f
abstract g
array g
as_friend
delegate g
enum class
enum struct
event g
finally
for each in
gcnew g
generic g
initonly
interface class g
interface struct g
interior_ptr g
literal g
new g
property g
ref class
ref struct
safecast
sealed g
typeid
value class g
value struct g
f
Applicable to Managed Extensions for C++ only. This syntax is now deprecated. For
more information, see Component Extensions for Runtime Platforms.
g
Applicable to C++/CLI.
See also
Lexical conventions
C++ built-in operators, precedence, and associativity
Punctuators (C++)
Article • 08/03/2021 • 2 minutes to read
Punctuators in C++ have syntactic and semantic meaning to the compiler but do not, of
themselves, specify an operation that yields a value. Some punctuators, either alone or
in combination, can also be C++ operators or be significant to the preprocessor.
! % ^ & * ( ) - + = { } | ~
[ ] \ ; ' : " < > ? , . / #
See also
Lexical Conventions
Numeric, boolean, and pointer literals
Article • 10/26/2022 • 5 minutes to read
A literal is a program element that directly represents a value. This article covers literals
of type integer, floating-point, boolean, and pointer. For information about string and
character literals, see String and Character Literals (C++). You can also define your own
literals based on any of these categories. For more information, see User-defined literals
(C++).
You can use literals in many contexts, but most commonly to initialize named variables
and to pass arguments to functions:
C++
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
Integer literals
Integer literals begin with a digit and have no fractional parts or exponents. You can
specify integer literals in decimal, binary, octal, or hexadecimal form. You can optionally
specify an integer literal as unsigned, and as a long or long long type, by using a suffix.
When no prefix or suffix is present, the compiler will give an integral literal value type
int (32 bits), if the value will fit, otherwise it will give it type long long (64 bits).
To specify a decimal integral literal, begin the specification with a nonzero digit. For
example:
C++
To specify an octal integral literal, begin the specification with 0, followed by a sequence
of digits in the range 0 through 7. The digits 8 and 9 are errors in specifying an octal
literal. For example:
C++
To specify a hexadecimal integral literal, begin the specification with 0x or 0X (the case
of the "x" doesn't matter), followed by a sequence of digits in the range 0 through 9
and a (or A ) through f (or F ). Hexadecimal digits a (or A ) through f (or F ) represent
values in the range 10 through 15. For example:
C++
To specify an unsigned type, use either the u or U suffix. To specify a long type, use
either the l or L suffix. To specify a 64-bit integral type, use the LL, or ll suffix. The i64
suffix is still supported, but we don't recommend it. It's specific to Microsoft and isn't
portable. For example:
C++
Digit separators: You can use the single-quote character (apostrophe) to separate place
values in larger numbers to make them easier for humans to read. Separators have no
effect on compilation.
C++
C++
18.46
38.
The exponent, if present, specifies the magnitude of the number as a power of 10, as
shown in the following example:
C++
18.46e0 // 18.46
18.46e1 // 184.6
The exponent may be specified using e or E , which have the same meaning, followed
by an optional sign (+ or -) and a sequence of digits. If an exponent is present, the
trailing decimal point is unnecessary in whole numbers such as 18E0 .
Although long double and double have the same representation, they're not the same
type. For example, you can have overloaded functions such as
C++
and
C++
C++
C++
In the previous example, a better practice is to use a named constant that conveys a
clear meaning, for example "MAXIMUM_ERROR_THRESHOLD". And if the return value
"Success" is seen by end users, then it might be better to use a named string constant.
You can keep string constants in a single location in a file that can be localized into
other languages. Using named constants helps both yourself and others to understand
the intent of the code.
See also
Lexical conventions
C++ string literals
C++ user-defined literals
String and character literals (C++)
Article • 11/02/2022 • 18 minutes to read
C++ supports various string and character types, and provides ways to express literal
values of each of these types. In your source code, you express the content of your
character and string literals using a character set. Universal character names and escape
characters allow you to express any string using only the basic source character set. A
raw string literal enables you to avoid using escape characters, and can be used to
express all types of string literals. You can also create std::string literals without having
to perform extra construction or conversion steps.
C++
#include <string>
using namespace std::string_literals; // enables s-suffix for std::string
literals
int main()
{
// Character literals
auto c0 = 'A'; // char
auto c1 = u8'A'; // char
auto c2 = L'A'; // wchar_t
auto c3 = u'A'; // char16_t
auto c4 = U'A'; // char32_t
// Multicharacter literals
auto m0 = 'abcd'; // int, value 0x61626364
// String literals
auto s0 = "hello"; // const char*
auto s1 = u8"hello"; // const char* before C++20, encoded as UTF-8,
// const char8_t* in C++20
auto s2 = L"hello"; // const wchar_t*
auto s3 = u"hello"; // const char16_t*, encoded as UTF-16
auto s4 = U"hello"; // const char32_t*, encoded as UTF-32
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:
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 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
C++
#include <iostream>
using namespace std;
int main() {
char newline = '\n';
char tab = '\t';
char backspace = '\b';
char backslash = '\\';
char nullChar = '\0';
cout << "Newline character: " << newline << "ending" << endl;
cout << "Tab character: " << tab << "ending" << endl;
cout << "Backspace character: " << backspace << "ending" << endl;
cout << "Backslash character: " << backslash << "ending" << endl;
cout << "Null character: " << nullChar << "ending" << endl;
}
/* Output:
Newline character:
ending
Tab character: ending
Backspace character:ending
Backslash character: \ending
Null character: ending
*/
The backslash character ( \ ) is a line-continuation character when it's placed at the end
of a line. If you want a backslash character to appear as a character literal, you must type
two backslashes in a row ( \\ ). For more information about the line continuation
character, see Phases of Translation.
Microsoft-specific
To create a value from a narrow multicharacter literal, the compiler converts the
character or character sequence between single quotes into 8-bit values within a 32-bit
integer. Multiple characters in the literal fill corresponding bytes as needed from high-
order to low-order. The compiler then converts the integer to the destination type
following the usual rules. For example, to create a char value, the compiler takes the
low-order byte. To create a wchar_t or char16_t value, the compiler takes the low-order
word. The compiler warns that the result is truncated if any bits are set above the
assigned byte or word.
C++
char c0 = 'abcd'; // C4305, C4309, truncates to 'd'
wchar_t w0 = 'abcd'; // C4305, C4309, truncates to '\x6364'
int i0 = 'abcd'; // 0x61626364
An octal escape sequence that appears to contain more than three digits is treated as a
3-digit octal sequence, followed by the subsequent digits as characters in a
multicharacter literal, which can give surprising results. For example:
C++
Escape sequences that appear to contain non-octal characters are evaluated as an octal
sequence up to the last octal character, followed by the remaining characters as the
subsequent characters in a multicharacter literal. Warning C4125 is generated if the first
non-octal character is a decimal digit. For example:
C++
An octal escape sequence that has a higher value than \377 causes error C2022: 'value-
in-decimal': too big for character.
C++
If a wide character literal prefixed with L contains a multicharacter sequence, the value
is taken from the first character, and the compiler raises warning C4066. Subsequent
characters are ignored, unlike the behavior of the equivalent ordinary multicharacter
literal.
C++
C++
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
C++
C++20 introduces the portable char8_t (UTF-8 encoded 8-bit Unicode) character type.
In C++20, u8 literal prefixes specify characters or strings of char8_t instead of char .
C++
// Before C++20
const char* str1 = u8"Hello World";
const char* str2 = u8"\U0001F607 is O:-)";
// C++20 and later
const char8_t* u8str1 = u8"Hello World";
const char8_t* u8str2 = u8"\U0001F607 is O:-)";
C++
C++11 introduces the portable char16_t (16-bit Unicode) and char32_t (32-bit
Unicode) character types:
C++
C++
C++
C++
You can construct a raw string literal that contains a newline (not the escaped character)
in the source:
C++
C++
//#include <string>
//using namespace std::string_literals;
string str{ "hello"s };
string str2{ u8"Hello World" }; // Before C++20
u8string u8str2{ u8"Hello World" }; // C++20
wstring str3{ L"hello"s };
u16string str4{ u"hello"s };
u32string str5{ U"hello"s };
The s suffix may also be used on raw string literals:
C++
bytes) to encode a single code unit. This example shows the size of a wide string literal in
bytes:
C++
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.
and removed in C++11. An attempt to modify the string causes an access violation, as in
this example:
C++
You can cause the compiler to emit an error when a string literal is converted to a non-
const character pointer when you set the /Zc:strictStrings (Disable string literal type
conversion) compiler option. We recommend it for standards-conformant portable
code. It's also a good practice to use the auto keyword to declare string literal-
initialized pointers, because it resolves to the correct (const) type. For example, this code
example catches an attempt to write to a string literal at compile time:
C++
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.
C++
C++
char atr[] = "1234";
C++
Using embedded hexadecimal escape codes to specify string literals can cause
unexpected results. The following example seeks to create a string literal that contains
the ASCII 5 character, followed by the characters f, i, v, and e:
C++
"\x05five"
The actual result is a hexadecimal 5F, which is the ASCII code for an underscore,
followed by the characters i, v, and e. To get the correct result, you can use one of these
escape sequences:
C++
std::u32string ) can be concatenated with the + operator that's defined for basic_string
types. They can also be concatenated in the same way as adjacent string literals. In both
cases, the string encoding and the suffix must match:
C++
C++
See also
Character sets
Numeric, Boolean, and pointer literals
User-defined literals
User-defined literals
Article • 08/03/2021 • 6 minutes to read
There are six major categories of literals in C++: integer, character, floating-point, string,
boolean, and pointer. Starting in C++ 11, you can define your own literals based on
these categories, to provide syntactic shortcuts for common idioms and increase type
safety. For example, let's say you have a Distance class. You could define a literal for
kilometers and another one for miles, and encourage the user to be explicit about the
units of measure by writing: auto d = 42.0_km or auto d = 42.0_mi . There's no
performance advantage or disadvantage to user-defined literals; they're primarily for
convenience or for compile-time type deduction. The Standard Library has user-defined
literals for std::string , for std::complex , and for units in time and duration operations
in the <chrono> header:
C++
C++
ReturnType operator "" _a(unsigned long long int); // Literal operator for
user-defined INTEGRAL literal
ReturnType operator "" _b(long double); // Literal operator for
user-defined FLOATING literal
ReturnType operator "" _c(char); // Literal operator for
user-defined CHARACTER literal
ReturnType operator "" _d(wchar_t); // Literal operator for
user-defined CHARACTER literal
ReturnType operator "" _e(char16_t); // Literal operator for
user-defined CHARACTER literal
ReturnType operator "" _f(char32_t); // Literal operator for
user-defined CHARACTER literal
ReturnType operator "" _g(const char*, size_t); // Literal operator for
user-defined STRING literal
ReturnType operator "" _h(const wchar_t*, size_t); // Literal operator for
user-defined STRING literal
ReturnType operator "" _i(const char16_t*, size_t); // Literal operator for
user-defined STRING literal
ReturnType operator "" _g(const char32_t*, size_t); // Literal operator for
user-defined STRING literal
ReturnType operator "" _r(const char*); // Raw literal operator
template<char...> ReturnType operator "" _t(); // Literal operator
template
The operator names in the previous example are placeholders for whatever name you
provide; however, the leading underscore is required. (Only the Standard Library is
allowed to define literals without the underscore.) The return type is where you
customize the conversion or other operations done by the literal. Also, any of these
operators can be defined as constexpr .
Cooked literals
In source code, any literal, whether user-defined or not, is essentially a sequence of
alphanumeric characters, such as 101 , or 54.7 , or "hello" or true . The compiler
interprets the sequence as an integer, float, const char* string, and so on. A user-defined
literal that accepts as input whatever type the compiler assigned to the literal value is
informally known as a cooked literal. All the operators above except _r and _t are
cooked literals. For example, a literal 42.0_km would bind to an operator named _km
that had a signature similar to _b and the literal 42_km would bind to an operator with a
signature similar to _a.
The following example shows how user-defined literals can encourage callers to be
explicit about their input. To construct a Distance , the user must explicitly specify
kilometers or miles by using the appropriate user-defined literal. You can achieve the
same result in other ways, but user-defined literals are less verbose than the alternatives.
C++
// UDL_Distance.cpp
#include <iostream>
#include <string>
struct Distance
{
private:
explicit Distance(long double val) : kilometers(val)
{}
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:
C++
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.
C++
#include <cstddef>
#include <cstdio>
Output
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:
See also
C++ Language Reference
C++ type system
Article • 11/07/2022 • 13 minutes to read
The concept of type is important in C++. Every variable, function argument, and function
return value must have a type in order to be compiled. Also, all expressions (including
literal values) are implicitly given a type by the compiler before they're evaluated. Some
examples of types include built-in types such as int to store integer values, double to
store floating-point values, or Standard Library types such as class std::basic_string to
store text. You can create your own type by defining a class or struct . The type
specifies the amount of memory that's allocated for the variable (or expression result).
The type also specifies the kinds of values that may be stored, how the compiler
interprets the bit patterns in those values, and the operations you can perform on them.
This article contains an informal overview of the major features of the C++ type system.
Terminology
Scalar type: A type that holds a single value of a defined range. Scalars include
arithmetic types (integral or floating-point values), enumeration type members, pointer
types, pointer-to-member types, and std::nullptr_t . Fundamental types are typically
scalar types.
Compound type: A type that isn't a scalar type. Compound types include array types,
function types, class (or struct) types, union types, enumerations, references, and
pointers to non-static class members.
Variable: The symbolic name of a quantity of data. The name can be used to access the
data it refers to throughout the scope of the code where it's defined. In C++, variable is
often used to refer to instances of scalar data types, whereas instances of other types
are typically called objects.
Object: For simplicity and consistency, this article uses the term object to refer to any
instance of a class or structure. When it's used in the general sense, it includes all types,
even scalar variables.
POD type (plain old data): This informal category of data types in C++ refers to types
that are scalar (see the Fundamental types section) or are POD classes. A POD class has
no static data members that aren't also PODs, and has no user-defined constructors,
user-defined destructors, or user-defined assignment operators. Also, a POD class has
no virtual functions, no base class, and no private or protected non-static data members.
POD types are often used for external data interchange, for example with a module
written in the C language (which has POD types only).
After you first declare a variable, you can't change its type at some later point. However,
you can copy the variable's value or a function's return value into another variable of a
different type. Such operations are called type conversions, which are sometimes
necessary but are also potential sources of data loss or incorrectness.
When you declare a variable of POD type, we strongly recommend you initialize it,
which means to give it an initial value. Until you initialize a variable, it has a "garbage"
value that consists of whatever bits happened to be in that memory location previously.
It's an important aspect of C++ to remember, especially if you're coming from another
language that handles initialization for you. When you declare a variable of non-POD
class type, the constructor handles initialization.
The following example shows some simple variable declarations with some descriptions
for each. The example also shows how the compiler uses type information to allow or
disallow certain subsequent operations on the variable.
C++
2,147,483,647. An unsigned int , which is also stored as 32 bits, can store a value from 0
to 4,294,967,295. The total number of possible values in each case is the same; only the
range is different.
The compiler recognizes these built-in types, and it has built-in rules that govern what
operations you can perform on them, and how they can be converted to other
fundamental types. For a complete list of built-in types and their size and numeric limits,
see Built-in types.
The following illustration shows the relative sizes of the built-in types in the Microsoft
C++ implementation:
The following table lists the most frequently used fundamental types, and their sizes in
the Microsoft C++ implementation:
Type Size Comment
char 1 Use for ASCII characters in older C-style strings or std::string objects that will
byte never have to be converted to UNICODE.
wchar_t 2 Represents "wide" character values that may be encoded in UNICODE format
bytes (UTF-16 on Windows, other operating systems may differ). wchar_t is the
character type that's used in strings of type std::wstring .
unsigned 1 C++ has no built-in byte type. Use unsigned char to represent a byte value.
char byte
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.
C++
The const qualifier is used extensively in function and variable declarations and "const
correctness" is an important concept in C++; essentially it means to use const to
guarantee, at compile time, that values aren't modified unintentionally. For more
information, see const.
A const type is distinct from its non- const version; for example, const int is a distinct
type from int . You can use the C++ const_cast operator on those rare occasions when
you must remove const-ness from a variable. For more information, see Type
conversions and type safety.
String types
Strictly speaking, the C++ language has no built-in string type; char and wchar_t store
single characters - you must declare an array of these types to approximate a string,
adding a terminating null value (for example, ASCII '\0' ) to the array element one past
the last valid character (also called a C-style string). C-style strings required much more
code to be written or the use of external string utility library functions. But in modern
C++, we have the Standard Library types std::string (for 8-bit char -type character
strings) or std::wstring (for 16-bit wchar_t -type character strings). These C++
Standard Library containers can be thought of as native string types because they're
part of the standard libraries that are included in any conformant C++ build
environment. Use the #include <string> directive to make these types available in your
program. (If you're using MFC or ATL, the CString class is also available, but isn't part of
the C++ standard.) The use of null-terminated character arrays (the C-style strings
previously mentioned) is discouraged in modern C++.
User-defined types
When you define a class , struct , union , or enum , that construct is used in the rest of
your code as if it were a fundamental type. It has a known size in memory, and certain
rules about how it can be used apply to it for compile-time checking and, at runtime, for
the life of your program. The primary differences between the fundamental built-in
types and user-defined types are as follows:
The compiler has no built-in knowledge of a user-defined type. It learns of the type
when it first encounters the definition during the compilation process.
You specify what operations can be performed on your type, and how it can be
converted to other types, by defining (through overloading) the appropriate
operators, either as class members or non-member functions. For more
information, see Function overloading
Pointer types
As in the earliest versions of the C language, C++ continues to let you declare a variable
of a pointer type by using the special declarator * (asterisk). A pointer type stores the
address of the location in memory where the actual data value is stored. In modern
C++, these pointer types are referred to as raw pointers, and they're accessed in your
code through special operators: * (asterisk) or -> (dash with greater-than, often called
arrow). This memory access operation is called dereferencing. Which operator you use
depends on whether you're dereferencing a pointer to a scalar, or a pointer to a
member in an object.
Working with pointer types has long been one of the most challenging and confusing
aspects of C and C++ program development. This section outlines some facts and
practices to help use raw pointers if you want to. However, in modern C++, it's no
longer required (or recommended) to use raw pointers for object ownership at all, due
to the evolution of the smart pointer (discussed more at the end of this section). It's still
useful and safe to use raw pointers for observing objects. However, if you must use
them for object ownership, you should do so with caution and with careful
consideration of how the objects owned by them are created and destroyed.
The first thing that you should know is that a raw pointer variable declaration only
allocates enough memory to store an address: the memory location that the pointer
refers to when it's dereferenced. The pointer declaration doesn't allocate the memory
needed to store the data value. (That memory is also called the backing store.) In other
words, by declaring a raw pointer variable, you're creating a memory address variable,
not an actual data variable. If you dereference a pointer variable before you've made
sure that it contains a valid address for a backing store, it causes undefined behavior
(usually a fatal error) in your program. The following example demonstrates this kind of
error:
C++
int* pNumber; // Declare a pointer-to-int variable.
*pNumber = 10; // error. Although this may compile, it is
// a serious error. We are dereferencing an
// uninitialized pointer variable with no
// allocated memory to point to.
The example dereferences a pointer type without having any memory allocated to store
the actual integer data or a valid memory address assigned to it. The following code
corrects these errors:
C++
The corrected code example uses local stack memory to create the backing store that
pNumber points to. We use a fundamental type for simplicity. In practice, the backing
stores for pointers are most often user-defined types that are dynamically allocated in
an area of memory called the heap (or free store) by using a new keyword expression (in
C-style programming, the older malloc() C runtime library function was used). Once
allocated, these variables are normally referred to as objects, especially if they're based
on a class definition. Memory that is allocated with new must be deleted by a
corresponding delete statement (or, if you used the malloc() function to allocate it, the
C runtime function free() ).
C++
void someFunction() {
unique_ptr<MyClass> pMc(new MyClass);
pMc->DoSomeWork();
}
// No memory leak. Out-of-scope automatically calls the destructor
// for the unique_ptr, freeing the resource.
For more information about pointer conversions, see Type conversions and type safety.
More information
For more information about the C++ type system, see the following articles.
Value types
Describes value types along with issues relating to their use.
See also
Welcome back to C++
C++ language reference
C++ Standard Library
Scope (C++)
Article • 11/11/2021 • 4 minutes to read
When you declare a program element such as a class, function, or variable, its name can
only be "seen" and used in certain parts of your program. The context in which a name
is visible is called its scope. For example, if you declare a variable x within a function, x
is only visible within that function body. It has local scope. You may have other variables
by the same name in your program; as long as they are in different scopes, they do not
violate the One Definition Rule and no error is raised.
For automatic non-static variables, scope also determines when they are created and
destroyed in program memory.
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.
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 ->*).
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.
C++
i = 0
i = 7
j = 9
i = 0
7 Note
C++
// hiding_class_names.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
class Account Checking( Account ); // Qualifies Account as
// class name
7 Note
Any place the class name ( Account ) is called for, the keyword class must be used to
differentiate it from the global-scoped variable Account. This rule does not apply
when the class name occurs on the left side of the scope-resolution operator (::).
Names on the left side of the scope-resolution operator are always considered class
names.
C++
7 Note
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.
C++
#include <iostream>
Output
See also
Basic Concepts
Header files (C++)
Article • 08/03/2021 • 4 minutes to read
The names of program elements such as variables, functions, classes, and so on must be
declared before they can be used. For example, you can't just write x = 42 without first
declaring 'x'.
C++
int x; // declaration
x = 42; // use x
The declaration tells the compiler whether the element is an int , a double , a function, a
class or some other thing. Furthermore, each name must be declared (directly or
indirectly) in every .cpp file in which it is used. When you compile a program, each .cpp
file is compiled independently into a compilation unit. The compiler has no knowledge
of what names are declared in other compilation units. That means that if you define a
class or function or global variable, you must provide a declaration of that thing in each
additional .cpp file that uses it. Each declaration of that thing must be exactly identical in
all files. A slight inconsistency will cause errors, or unintended behavior, when the linker
attempts to merge all the compilation units into a single program.
To minimize the potential for errors, C++ has adopted the convention of using header
files to contain declarations. You make the declarations in a header file, then use the
#include directive in every .cpp file or other header file that requires that declaration.
The #include directive inserts a copy of the header file directly into the .cpp file prior to
compilation.
7 Note
Example
The following example shows a common way to declare a class and then use it in a
different source file. We'll start with the header file, my_class.h . It contains a class
definition, but note that the definition is incomplete; the member function do_something
is not defined:
C++
// my_class.h
namespace N
{
class my_class
{
public:
void do_something();
};
Next, create an implementation file (typically with a .cpp or similar extension). We'll call
the file my_class.cpp and provide a definition for the member declaration. We add an
#include directive for "my_class.h" file in order to have the my_class declaration inserted
at this point in the .cpp file, and we include <iostream> to pull in the declaration for
std::cout . Note that quotes are used for header files in the same directory as the
source file, and angle brackets are used for standard library headers. Also, many
standard library headers do not have .h or any other file extension.
In the implementation file, we can optionally use a using statement to avoid having to
qualify every mention of "my_class" or "cout" with "N::" or "std::". Don't put using
statements in your header files!
C++
// my_class.cpp
#include "my_class.h" // header in local directory
#include <iostream> // header in standard library
using namespace N;
using namespace std;
void my_class::do_something()
{
cout << "Doing something!" << endl;
}
Now we can use my_class in another .cpp file. We #include the header file so that the
compiler pulls in the declaration. All the compiler needs to know is that my_class is a
class that has a public member function called do_something() .
C++
// my_program.cpp
#include "my_class.h"
using namespace N;
int main()
{
my_class mc;
mc.do_something();
return 0;
}
After the compiler finishes compiling each .cpp file into .obj files, it passes the .obj files
to the linker. When the linker merges the object files it finds exactly one definition for
my_class; it is in the .obj file produced for my_class.cpp, and the build succeeds.
Include guards
Typically, header files have an include guard or a #pragma once directive to ensure that
they are not inserted multiple times into a single .cpp file.
C++
// my_class.h
#ifndef MY_CLASS_H // include guard
#define MY_CLASS_H
namespace N
{
class my_class
{
public:
void do_something();
};
}
#endif /* MY_CLASS_H */
Use of the using directive will not necessarily cause an error, but can potentially cause a
problem because it brings the namespace into scope in every .cpp file that directly or
indirectly includes that header.
C++
// sample.h
#pragma once
#include <vector> // #include directive
#include <string>
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.)
C++
int i;
int f(int x);
class C;
C++
int i{42};
int f(int x){ return x * i; }
class C {
public:
void DoSomething();
};
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 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.
You can force a global name to have internal linkage by explicitly declaring it as static .
This keyword limits its visibility to the same translation unit in which it's declared. In this
context, static means something different than when applied to local variables.
const objects
constexpr objects
typedef objects
To give a const object external linkage, declare it as extern and assign it a value:
C++
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:
C++
int main();
int main(int argc, char *argv[]);
If no return value is specified in main , the compiler supplies a return value of zero.
An integer that contains the count of arguments that follow in argv. The argc parameter
is always greater than or equal to 1.
argv
An array of null-terminated strings representing command-line arguments entered by
the user of the program. By convention, argv[0] is the command with which the
program is invoked. argv[1] is the first command-line argument. The last argument
from the command line is argv[argc - 1] , and argv[argc] is always NULL.
7 Note
Microsoft-specific extensions
The following sections describe Microsoft-specific behavior.
C++
int wmain();
int wmain(int argc, wchar_t *argv[]);
You can also use the Microsoft-specific _tmain , which is a preprocessor macro defined
in tchar.h . _tmain resolves to main unless _UNICODE is defined. In that case, _tmain
resolves to wmain . The _tmain macro and other macros that begin with _t are useful for
code that must build separate versions for both narrow and wide character sets. For
more information, see Using generic-text mappings.
If you declare main or wmain as returning void , you can't return an exit code to the
parent process or the operating system by using a return statement. To return an exit
code when main or wmain is declared as void , you must use the exit function.
C++
envp
The optional envp parameter is an array of strings representing the variables set in the
user's environment. This array is terminated by a NULL entry. It can be declared as an
array of pointers to char ( char *envp[] ) or as a pointer to pointers to char ( char
**envp ). If your program uses wmain instead of main , use the wchar_t data type instead
of char .
The environment block passed to main and wmain is a "frozen" copy of the current
environment. If you later change the environment by making a call to putenv or
_wputenv , the current environment (as returned by getenv or _wgetenv and the
_environ or _wenviron variable) will change, but the block pointed to by envp won't
change. For more information on how to suppress environment processing, see
Customize C++ command-line processing. The envp argument is compatible with the
C89 standard, but not with C++ standards.
Example arguments to main
The following example shows how to use the argc , argv , and envp arguments to main :
C++
// argument_definitions.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>
The first argument ( argv[0] ) is treated specially. It represents the program name.
Because it must be a valid pathname, parts surrounded by double quote marks ( " )
are allowed. The double quote marks aren't included in the argv[0] output. The
parts surrounded by double quote marks prevent interpretation of a space or tab
character as the end of the argument. The later rules in this list don't apply.
C++
// 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.
For more information on runtime startup linker options, see Link options.
Similarly, if you never access the environment table through the envp argument, you
can suppress the internal environment-processing routine. To suppress its use, include
the noenv.obj file (for both main and wmain ) in your /link compiler options or your
LINK command line.
Your program might make calls to the spawn or exec family of routines in the C runtime
library. If it does, you shouldn't suppress the environment-processing routine, since it's
used to pass an environment from the parent process to the child process.
See also
Basic concepts
C++ program termination
Article • 07/07/2022 • 3 minutes to read
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.
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.
C++
// return_statement.cpp
#include <stdlib.h>
struct S
{
int value;
};
int main()
{
S s{ 3 };
exit( 3 );
// or
return 3;
}
The exit and return statements in the preceding example have similar behavior. Both
terminate the program and return a value of 3 to the operating system. The difference is
that exit doesn't destroy the automatic variable s , while the return statement does.
Normally, C++ requires that functions that have return types other than void return a
value. The main function is an exception; it can end without a return statement. In that
case, it returns an implementation-specific value to the invoking process. (By default,
MSVC returns 0.)
Example
In the following example, the static objects sd1 and sd2 are created and initialized
before entry to main . After this program terminates using the return statement, first
sd2 is destroyed and then sd1 . The destructor for the ShowData class closes the files
C++
// using_exit_or_return1.cpp
#include <stdio.h>
class ShowData {
public:
// Constructor opens a file.
ShowData( const char *szDev ) {
errno_t err;
err = fopen_s(&OutputDev, szDev, "w" );
}
int main() {
sd1.Disp( "hello to default device\n" );
sd2.Disp( "hello to file hello.dat\n" );
}
Another way to write this code is to declare the ShowData objects with block scope,
which implicitly destroys them when they go out of scope:
C++
int main() {
ShowData sd1( "CON" ), sd2( "hello.dat" );
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.
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.
An xvalue expression has an address that no longer accessible by your program but can
be used to initialize an rvalue reference, which provides access to the expression.
Examples include function calls that return an rvalue reference, and the array subscript,
member and pointer to member expressions where the array or object is an rvalue
reference.
Example
The following example demonstrates several correct and incorrect usages of lvalues and
rvalues:
C++
// lvalues_and_rvalues2.cpp
int main()
{
int i, j, *p;
7 Note
The examples in this topic illustrate correct and incorrect usage when operators are
not overloaded. By overloading operators, you can make an expression such as j *
4 an lvalue.
The terms lvalue and rvalue are often used when you refer to object references. For
more information about references, see Lvalue Reference Declarator: & and Rvalue
Reference Declarator: &&.
See also
Basic Concepts
Lvalue Reference Declarator: &
Rvalue Reference Declarator: &&
Temporary objects
Article • 03/22/2022 • 2 minutes to read
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 store the return value of a function that returns a user-defined type (UDT).
These temporaries are created only if your program doesn't copy the return value
to an object. For example:
C++
...
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.
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.
See also
Herb Sutter's blog on References, simply
Alignment
Article • 08/03/2021 • 4 minutes to read
One of the low-level features of C++ is the ability to specify the precise alignment of
objects in memory to take maximum advantage of a specific hardware architecture. By
default, the compiler aligns class and struct members on their size value: bool and char
on 1-byte boundaries, short on 2-byte boundaries, int , long , and float on 4-byte
boundaries, and long long , double , and long double on 8-byte boundaries.
In most scenarios, you never have to be concerned with alignment because the default
alignment is already optimal. In some cases, however, you can achieve significant
performance improvements, or memory savings, by specifying a custom alignment for
your data structures. Before Visual Studio 2015 you could use the Microsoft-specific
keywords __alignof and __declspec(align) to specify an alignment greater than the
default. Starting in Visual Studio 2015 you should use the C++11 standard keywords
alignof and alignas for maximum code portability. The new keywords behave in the
same way under the hood as the Microsoft-specific extensions. The documentation for
those extensions also applies to the new keywords. For more information, see alignof
Operator and align. The C++ standard doesn't specify packing behavior for alignment
on boundaries smaller than the compiler default for the target platform, so you still
need to use the Microsoft #pragma pack in that case.
Use the aligned_storage class for memory allocation of data structures with custom
alignments. The aligned_union class is for specifying alignment for unions with non-
trivial constructors or destructors.
CPUs execute instructions that operate on data stored in memory. The data are
identified by their addresses in memory. A single datum also has a size. We call a datum
naturally aligned if its address is aligned to its size. It's called misaligned otherwise. For
example, an 8-byte floating-point datum is naturally aligned if the address used to
identify it has an 8-byte alignment.
Compiler handling of data alignment
Compilers attempt to make data allocations in a way that prevents data misalignment.
For simple data types, the compiler assigns addresses that are multiples of the size in
bytes of the data type. For example, the compiler assigns addresses to variables of type
long that are multiples of 4, setting the bottom 2 bits of the address to zero.
The compiler also pads structures in a way that naturally aligns each element of the
structure. Consider the structure struct x_ in the following code example:
C++
struct x_
{
char a; // 1 byte
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
} bar[3];
The following code example shows how the compiler places the padded structure in
memory:
C++
2. char _pad1[1] to align the array elements of the structure struct _x bar[3]; on a
four-byte boundary.
The padding aligns the elements of bar[3] in a way that allows natural access.
Output
Example
You can use alignas on a class, struct or union, or on individual members. When
multiple alignas specifiers are encountered, the compiler will choose the strictest one,
(the one with the largest value).
C++
// alignas_alignof.cpp
// compile with: cl /EHsc alignas_alignof.cpp
#include <iostream>
struct alignas(16) Bar
{
int i; // 4 bytes
int n; // 4 bytes
alignas(4) char arr[3];
short s; // 2 bytes
};
int main()
{
std::cout << alignof(Bar) << std::endl; // output: 16
}
See also
Data structure alignment
Trivial, standard-layout, POD, and literal
types
Article • 01/05/2022 • 5 minutes to read
The term layout refers to how the members of an object of class, struct or union type
are arranged in memory. In some cases, the layout is well-defined by the language
specification. But when a class or struct contains certain C++ language features such as
virtual base classes, virtual functions, members with different access control, then the
compiler is free to choose a layout. That layout may vary depending on what
optimizations are being performed and in many cases the object might not even occupy
a contiguous area of memory. For example, if a class has virtual functions, all the
instances of that class might share a single virtual function table. Such types are very
useful, but they also have limitations. Because the layout is undefined they cannot be
passed to programs written in other languages, such as C, and because they might be
non-contiguous they cannot be reliably copied with fast low-level functions such as
memcopy , or serialized over a network.
To enable compilers as well as C++ programs and metaprograms to reason about the
suitability of any given type for operations that depend on a particular memory layout,
C++14 introduced three categories of simple classes and structs: trivial, standard-layout,
and POD or Plain Old Data. The Standard Library has the function templates
is_trivial<T> , is_standard_layout<T> and is_pod<T> that determine whether a given
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,
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
C++
struct Trivial
{
int i;
private:
int j;
};
struct Trivial2
{
int i;
Trivial2(int a, int b) : i(a), j(b) {}
Trivial2() = default;
private:
int j; // Different access control
};
has no base classes of the same type as the first non-static data member.
meets one of these conditions:
no non-static data member in the most-derived class and no more than one
base class with non-static data members, or
C++
struct SL
{
// All members have same access:
int i;
int j;
SL(int a, int b) : i(a), j(b) {} // User-defined constructor OK
};
The last two requirements can perhaps be better illustrated with code. In the next
example, even though Base is standard-layout, Derived is not standard layout because
both it (the most derived class) and Base have non-static data members:
C++
struct Base
{
int i;
int j;
};
// std::is_standard_layout<Derived> == false!
struct Derived : public Base
{
int x;
int y;
};
C++
struct Base
{
void Foo() {}
};
// std::is_standard_layout<Derived> == true
struct Derived : public Base
{
int x;
int y;
};
Derived would also be standard-layout if Base had the data members and Derived had
only member functions.
POD types
When a class or struct is both trivial and standard-layout, it is a POD (Plain Old Data)
type. The memory layout of POD types is therefore contiguous and each member has a
higher address than the member that was declared before it, so that byte for byte
copies and binary I/O can be performed on these types. Scalar types such as int are also
POD types. POD types that are classes can have only POD types as non-static data
members.
Example
The following example shows the distinctions between trivial, standard-layout, and POD
types:
C++
#include <type_traits>
#include <iostream>
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
Article • 10/17/2022 • 3 minutes to read
C++ classes are, by default, value types. They can be specified as reference types, which
enable polymorphic behavior to support object-oriented programming. Value types are
sometimes viewed from the perspective of memory and layout control, whereas
reference types are about base classes and virtual functions for polymorphic purposes.
By default, value types are copyable, which means there's always a copy constructor and
a copy assignment operator. For reference types, you make the class non-copyable
(disable the copy constructor and copy assignment operator) and use a virtual
destructor, which supports their intended polymorphism. Value types are also about the
contents, which, when they're copied, always give you two independent values that can
be modified separately. Reference types are about identity - what kind of object is it?
For this reason, "reference types" are also referred to as "polymorphic types".
If you really want a reference-like type (base class, virtual functions), you need to
explicitly disable copying, as shown in the MyRefType class in the following code.
C++
class MyRefType {
private:
MyRefType & operator=(const MyRefType &);
MyRefType(const MyRefType &);
public:
MyRefType () {}
};
int main()
{
MyRefType Data1, Data2;
// ...
Data1 = Data2;
}
Output
How do you decide if you need to enable move operations? If you already know you
need to enable copy construction, you probably want to enable move construction, too,
especially if it's cheaper than a deep copy. However, if you know you need move
support, it doesn't necessarily mean you want to enable copy operations. This latter case
would be called a "move-only type". An example already in the standard library is
unique_ptr . As a side note, the old auto_ptr is deprecated, and was replaced by
unique_ptr precisely due to the lack of move semantics support in the previous version
of C++.
C++
#include <set>
#include <vector>
#include <string>
using namespace std;
//...
set<widget> LoadHugeData() {
set<widget> ret;
// ... load data from disk and populate ret
return ret;
}
//...
widgets = LoadHugeData(); // efficient, no deep copy
vector<string> v = IfIHadAMillionStrings();
v.insert( begin(v)+v.size()/2, "scott" ); // efficient, no deep copy-
shuffle
v.insert( begin(v)+v.size()/2, "Andrei" ); // (just 1M ptr/len assignments)
//...
HugeMatrix operator+(const HugeMatrix& , const HugeMatrix& );
HugeMatrix operator+(const HugeMatrix& , HugeMatrix&&);
HugeMatrix operator+( HugeMatrix&&, const HugeMatrix& );
HugeMatrix operator+( HugeMatrix&&, HugeMatrix&&);
//...
hm5 = hm1+hm2+hm3+hm4+hm5; // efficient, no extra copies
C++
#include <memory>
#include <stdexcept>
using namespace std;
// ...
class my_class {
unique_ptr<BigHugeData> data;
public:
my_class( my_class&& other ) // move construction
: data( move( other.data ) ) { }
my_class& operator=( my_class&& other ) // move assignment
{ data = move( other.data ); return *this; }
// ...
void method() { // check (if appropriate)
if( !data )
throw std::runtime_error("RUNTIME ERROR: Insufficient
resources!");
}
};
Some non-value types are move-only, such as when you can't clone a resource, only
transfer ownership. Example: unique_ptr .
See also
C++ type system
Welcome back to C++
C++ Language Reference
C++ Standard Library
Type conversions and type safety
Article • 08/03/2021 • 9 minutes to read
This document identifies common type conversion problems and describes how you can
avoid them in your C++ code.
When you write a C++ program, it's important to ensure that it's type-safe. This means
that every variable, function argument, and function return value is storing an
acceptable kind of data, and that operations that involve values of different types "make
sense" and don't cause data loss, incorrect interpretation of bit patterns, or memory
corruption. A program that never explicitly or implicitly converts values from one type to
another is type-safe by definition. However, type conversions, even unsafe conversions,
are sometimes required. For example, you might have to store the result of a floating
point operation in a variable of type int , or you might have to pass the value in an
unsigned int to a function that takes a signed int . Both examples illustrate unsafe
conversions because they may cause data loss or re-interpretation of a value.
When the compiler detects an unsafe conversion, it issues either an error or a warning.
An error stops compilation; a warning allows compilation to continue but indicates a
possible error in the code. However, even if your program compiles without warnings, it
still may contain code that leads to implicit type conversions that produce incorrect
results. Type errors can also be introduced by explicit conversions, or casts, in the code.
From To
Any signed or unsigned integral type except long long or __int64 double
float double
Any conversion from a floating point type to an integral type is a narrowing conversion
because the fractional portion of the floating point value is discarded and lost.
The following code example shows some implicit narrowing conversions, and the
warnings that the compiler issues for them.
C++
C++
Notice that values are reinterpreted in both directions. If your program produces odd
results in which the sign of the value seems inverted from what you expect, look for
implicit conversions between signed and unsigned integral types. In the following
example, the result of the expression ( 0 - 1) is implicitly converted from int to unsigned
int when it's stored in num . This causes the bit pattern to be reinterpreted.
C++
unsigned int u3 = 0 - 1;
cout << u3 << endl; // prints 4294967295
The compiler doesn't warn about implicit conversions between signed and unsigned
integral types. So, we recommend that you avoid signed-to-unsigned conversions
altogether. If you can't avoid them, then add a runtime check to detect whether the
value being converted is greater than or equal to zero and less than or equal to the
maximum value of the signed type. Values in this range will transfer from signed to
unsigned or from unsigned to signed without being reinterpreted.
Pointer conversions
In many expressions, a C-style array is implicitly converted to a pointer to the first
element in the array, and constant conversions can happen silently. Although this is
convenient, it's also potentially error-prone. For example, the following badly designed
code example seems nonsensical, and yet it will compile and produces a result of 'p'.
First, the "Help" string constant literal is converted to a char* that points to the first
element of the array; that pointer is then incremented by three elements so that it now
points to the last element 'p'.
C++
char* s = "Help" + 3;
In C-style programming, the same C-style cast operator is used for all kinds of casts.
C++
The C-style cast operator is identical to the call operator () and is therefore
inconspicuous in code and easy to overlook. Both are bad because they're difficult to
recognize at a glance or search for, and they're disparate enough to invoke any
combination of static , const , and reinterpret_cast . Figuring out what an old-style
cast actually does can be difficult and error-prone. For all these reasons, when a cast is
required, we recommend that you use one of the following C++ cast operators, which in
some cases are significantly more type-safe, and which express much more explicitly the
programming intent:
static_cast , for casts that are checked at compile time only. static_cast returns
an error if the compiler detects that you are trying to cast between types that are
completely incompatible. You can also use it to cast between pointer-to-base and
pointer-to-derived, but the compiler can't always tell whether such conversions will
be safe at runtime.
C++
double d = 1.58947;
int i = d; // warning C4244 possible loss of data
int j = static_cast<int>(d); // No warning.
string s = static_cast<string>(d); // Error C2440:cannot convert from
// double to std:string
C++
//Output: d3 is null;
For more information, see dynamic_cast.
const_cast , for casting away the const -ness of a variable, or converting a non-
const variable to be const . Casting away const -ness by using this operator is just
as error-prone as is using a C-style cast, except that with const_cast you are less
likely to perform the cast accidentally. Sometimes you have to cast away the
const -ness of a variable, for example, to pass a const variable to a function that
takes a non- const parameter. The following example shows how to do this.
C++
reinterpret_cast , for casts between unrelated types such as a pointer type and an
int .
7 Note
This cast operator isn't used as often as the others, and it's not guaranteed to
be portable to other compilers.
C++
See also
C++ type system
Welcome back to C++
C++ Language Reference
C++ Standard Library
Standard conversions
Article • 11/11/2021 • 12 minutes to read
The C++ language defines conversions between its fundamental types. It also defines
conversions for pointer, reference, and pointer-to-member derived types. These
conversions are called standard conversions.
Integral promotions
Integral conversions
Floating conversions
Arithmetic conversions
Pointer conversions
Reference conversions
Pointer-to-member conversions
7 Note
The following code causes conversions (in this example, integral promotions):
C++
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:
Enumeration types
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
These operators rely on sign for determining the result. Value-preserving and sign-
preserving promotions produce different results when applied to these operands.
Integral conversions
Integral conversions are conversions between integral types. The integral types are char ,
short (or short int ), int , long , and long long . These types may be qualified with
signed or unsigned , and unsigned can be used as shorthand for unsigned int .
Signed to unsigned
Objects of signed integral types can be converted to corresponding unsigned types.
When these conversions occur, the actual bit pattern doesn't change. However, the
interpretation of the data changes. Consider this code:
C++
#include <iostream>
Unsigned to signed
Objects of unsigned integral types can be converted to corresponding signed types.
However, if the unsigned value is outside the representable range of the signed type,
the result won't have the correct value, as demonstrated in the following example:
C++
#include <iostream>
An object of a floating type can also be converted to a less precise type, if it's in a range
representable by that type. (See Floating Limits for the ranges of floating types.) If the
original value isn't representable precisely, it can be converted to either the next higher
or the next lower representable value. The result is undefined if no such value exists.
Consider the following example:
C++
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.
The following code illustrates the conversion rules described in the table:
C++
double dVal;
float fVal;
int iVal;
unsigned long ulVal;
int main() {
// iVal converted to unsigned long
// result of multiplication converted to double
dVal = iVal * ulVal;
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.
The following table shows the base-class accessibility for the situation illustrated in the
figure.
B* to A* Legal?
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.
C++
// C2039 expected
class A
{
public:
int AComponent;
int AMemberFunc();
};
class B : public A
{
public:
int BComponent;
int BMemberFunc();
};
int main()
{
B bObject;
A *pA = &bObject;
B *pB = &bObject;
pA->AMemberFunc(); // OK in class A
pB->AMemberFunc(); // OK: inherited from class A
pA->BMemberFunc(); // Error: not in class A
}
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 * .
7 Note
C++ pointers to members, except pointers to static members, are different from
normal pointers and don't have the same standard conversions. Pointers to static
members are normal pointers and have the same conversions as normal pointers.
In C++11, the nullptr type should be preferred to the C-style null pointer.
C++
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:
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.
C++
class A
{
public:
int i;
};
int A::*pai = 0;
int main()
{
}
See also
C++ language reference
Built-in types (C++)
Article • 08/17/2021 • 5 minutes to read
Built-in types (also called fundamental types) are specified by the C++ language
standard and are built into the compiler. Built-in types aren't defined in any header file.
Built-in types are divided into three main categories: integral, floating-point, and void.
Integral types represent whole numbers. Floating-point types can specify values that
may have fractional parts. Most built-in types are treated as distinct types by the
compiler. However, some types are synonyms, or treated as equivalent types by the
compiler.
Void type
The void type describes an empty set of values. No variable of type void can be
specified. The void type is used primarily to declare functions that return no values or to
declare generic pointers to untyped or arbitrarily typed data. Any expression can be
explicitly converted or cast to type void . However, such expressions are restricted to the
following uses:
The left operand of the comma operator. (For more information, see Comma
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.
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
The char16_t type is used for UTF-16 character representation. It must be large enough
to represent any UTF-16 code unit. It's treated as a distinct type by the compiler.
The char32_t type is used for UTF-32 character representation. It must be large enough
to represent any UTF-32 code unit. It's treated as a distinct type by the compiler.
Floating-point types
Floating-point types use an IEEE-754 representation to provide an approximation of
fractional values over a wide range of magnitudes. The following table lists the floating-
point types in C++ and the comparative restrictions on floating-point type sizes. These
restrictions are mandated by the C++ standard and are independent of the Microsoft
implementation. The absolute size of built-in floating-point types isn't specified in the
standard.
Type Contents
double Type double is a floating point type that is larger than or equal to type float , but
shorter than or equal to the size of type long double .
long Type long double is a floating point type that is larger than or equal to type double .
double
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:
An implementation must maintain both the minimum size requirements and the size
relationship for each type. However, the actual sizes can and do vary between
implementations. See Sizes of built-in types for Microsoft-specific implementation
details.
The int keyword may be omitted when signed , unsigned , or size modifiers are
specified. The modifiers and int type, if present, may appear in any order. For example,
short unsigned and unsigned int short refer to the same type.
long long , long long int , signed long long , signed long long int
long long .
Type Size
char32_t , float , __int32 , int , unsigned int , long , unsigned long 4 bytes
double , __int64 , long double , long long , unsigned long long 8 bytes
See Data type ranges for a summary of the range of values of each type.
The Microsoft C++ 32-bit and 64-bit compilers recognize the types in the table later in
this article.
The ranges that are specified in the following table are inclusive-inclusive.
signed and unsigned are modifiers that you can use with any integral type except bool .
Note that char , signed char , and unsigned char are three distinct types for the
purposes of mechanisms like overloading and templates.
The int and unsigned int types have a size of four bytes. However, portable code
should not depend on the size of int because the language standard allows this to be
implementation-specific.
C/C++ in Visual Studio also supports sized integer types. For more information, see
__int8, __int16, __int32, __int64 and Integer Limits.
For more information about the restrictions of the sizes of each type, see Built-in types.
The range of enumerated types varies depending on the language context and specified
compiler flags. For more information, see C Enumeration Declarations and
Enumerations.
See also
Keywords
Built-in types
nullptr
Article • 08/03/2021 • 2 minutes to read
The nullptr keyword specifies a null pointer constant of type std::nullptr_t , which is
convertible to any raw pointer type. Although you can use the keyword nullptr without
including any headers, if your code uses the type std::nullptr_t , then you must define
it by including the header <cstddef> .
7 Note
The nullptr keyword is also defined in C++/CLI for managed code applications
and is not interchangeable with the ISO Standard C++ keyword. If your code might
be compiled by using the /clr compiler option, which targets managed code, then
use __nullptr in any line of code where you must guarantee that the compiler uses
the native C++ interpretation. For more information, see nullptr (C++/CLI and
C++/CX).
Remarks
Avoid using NULL or zero ( 0 ) as a null pointer constant; nullptr is less vulnerable to
misuse and works better in most situations. For example, given func(std::pair<const
char *, double>) , then calling func(std::make_pair(NULL, 3.14)) causes a compiler
error. The macro NULL expands to 0 , so that the call std::make_pair(0, 3.14) returns
std::pair<int, double> , which isn't convertible to the std::pair<const char *, double>
See also
Keywords
nullptr (C++/CLI and C++/CX)
void (C++)
Article • 12/14/2022 • 2 minutes to read
When used as a function return type, the void keyword specifies that the function
doesn't return a value. When used for a function's parameter list, void specifies that the
function takes no parameters. When used in the declaration of a pointer, void specifies
that the pointer is "universal."
If a pointer's type is void* , the pointer can point to any variable that's not declared with
the const or volatile keyword. A void* pointer can't be dereferenced unless it's cast
to another type. A void* pointer can be converted into any other type of data pointer.
In C++, a void pointer can point to a free function (a function that's not a member of a
class), or to a static member function, but not to a non-static member function.
As a matter of style, the C++ Core Guidelines recommend you don't use void to specify
an empty formal parameter list. For more information, see C++ Core Guidelines NL.25:
Don't use void as an argument type .
Example
C++
// void.cpp
void return_nothing()
{
// A void function can have a return with no argument,
// or no return statement.
}
This keyword is a built-in type. A variable of this type can have values true and false.
Conditional expressions have the type bool and so have values of type bool . For
example, i != 0 now has true or false depending on the value of i .
Visual Studio 2017 version 15.3 and later (Available with /std:c++17 and later): The
operand of a postfix or prefix increment or decrement operator may not be of type
bool . In other words, given a variable b of type bool , these expressions are no longer
allowed:
C++
b++;
++b;
b--;
--b;
C++
!false == true
!true == false
C++
if (condexpr1) statement1;
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.
See also
Keywords
Built-in types
false (C++)
Article • 08/03/2021 • 2 minutes to read
The keyword is one of the two values for a variable of type bool or a conditional
expression (a conditional expression is now a true Boolean expression). For example, if
i is a variable of type bool , the i = false; statement assigns false to i .
Example
C++
// bool_false.cpp
#include <stdio.h>
int main()
{
bool bb = true;
printf_s("%d\n", bb);
bb = false;
printf_s("%d\n", bb);
}
Output
1
0
See also
Keywords
true (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
bool-identifier = true ;
bool-expression logical-operator true ;
Remarks
This keyword is one of the two values for a variable of type bool or a conditional
expression (a conditional expression is now a true boolean expression). If i is of type
bool , then the statement i = true; assigns true to i .
Example
C++
// bool_true.cpp
#include <stdio.h>
int main()
{
bool bb = true;
printf_s("%d\n", bb);
bb = false;
printf_s("%d\n", bb);
}
Output
1
0
See also
Keywords
char, wchar_t, char8_t, char16_t, char32_t
Article • 08/17/2021 • 2 minutes to read
The types char , wchar_t , char8_t , char16_t , and char32_t are built-in types that
represent alphanumeric characters, non-alphanumeric glyphs, and non-printing
characters.
Syntax
C++
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 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,
In the C++ standard library, the basic_string type is specialized for both narrow and
wide strings. Use std::string when the characters are of type char , std::u8string
when the characters are of type char8_t , std::u16string when the characters are of
type char16_t , std::u32string when the characters are of type char32_t , and
std::wstring when the characters are of type wchar_t . Other types that represent text,
including std::stringstream and std::cout have specializations for narrow and wide
strings.
__int8, __int16, __int32, __int64
Article • 08/03/2021 • 2 minutes to read
Microsoft-specific
Microsoft C/C++ features support for sized integer types. You can declare 8-, 16-, 32-,
or 64-bit integer variables by using the __intN type specifier, where N is 8, 16, 32, or 64.
The following example declares one variable for each of these types of sized integers:
C++
The types __int8 , __int16 , and __int32 are synonyms for the ANSI types that have the
same size, and are useful for writing portable code that behaves identically across
multiple platforms. The __int8 data type is synonymous with type char , __int16 is
synonymous with type short , and __int32 is synonymous with type int . The __int64
type is synonymous with type long long .
For compatibility with previous versions, _int8 , _int16 , _int32 , and _int64 are
synonyms for __int8 , __int16 , __int32 , and __int64 unless compiler option /Za
(Disable language extensions) is specified.
Example
The following sample shows that an __intN parameter will be promoted to int :
C++
// sized_int_types.cpp
#include <stdio.h>
void func(int i) {
printf_s("%s\n", __FUNCTION__);
}
int main()
{
__int8 i8 = 100;
func(i8); // no void func(__int8 i8) function
// __int8 will be promoted to int
}
Output
func
See also
Keywords
Built-in types
Data Type Ranges
__m64
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The __m64 data type is for use with the MMX and 3DNow! intrinsics, and is defined in
<xmmintrin.h>.
C++
// data_types__m64.cpp
#include <xmmintrin.h>
int main()
{
__m64 x;
}
Remarks
You should not access the __m64 fields directly. You can, however, see these types in the
debugger. A variable of type __m64 maps to the MM[0-7] registers.
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.
See also
Keywords
Built-in types
Data Type Ranges
__m128
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The __m128 data type, for use with the Streaming SIMD Extensions and Streaming SIMD
Extensions 2 instructions intrinsics, is defined in <xmmintrin.h>.
C++
// data_types__m128.cpp
#include <xmmintrin.h>
int main() {
__m128 x;
}
Remarks
You should not access the __m128 fields directly. You can, however, see these types in
the debugger. A variable of type __m128 maps to the XMM[0-7] registers.
See also
Keywords
Built-in types
Data Type Ranges
__m128d
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The __m128d data type, for use with the Streaming SIMD Extensions 2 instructions
intrinsics, is defined in <emmintrin.h>.
C++
// data_types__m128d.cpp
#include <emmintrin.h>
int main() {
__m128d x;
}
Remarks
You should not access the __m128d fields directly. You can, however, see these types in
the debugger. A variable of type __m128 maps to the XMM[0-7] registers.
See also
Keywords
Built-in types
Data Type Ranges
__m128i
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The __m128i data type, for use with the Streaming SIMD Extensions 2 (SSE2) instructions
intrinsics, is defined in <emmintrin.h>.
C++
// data_types__m128i.cpp
#include <emmintrin.h>
int main() {
__m128i x;
}
Remarks
You should not access the __m128i fields directly. You can, however, see these types in
the debugger. A variable of type __m128i maps to the XMM[0-7] registers.
7 Note
Using variables of type __m128i will cause the compiler to generate the SSE2
movdqa instruction. This instruction does not cause a fault on Pentium III processors
but will result in silent failure, with possible side effects caused by whatever
instructions movdqa translates into on Pentium III processors.
See also
Keywords
Built-in types
Data Type Ranges
__ptr32, __ptr64
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The following example shows how to declare each of these pointer types:
C++
7 Note
You cannot use __ptr32 or __ptr64 when compiling with /clr:pure. Otherwise,
Compiler Error C2472 will be generated. The /clr:pure and /clr:safe compiler
options are deprecated in Visual Studio 2015 and unsupported in Visual Studio
2017.
For compatibility with previous versions, _ptr32 and _ptr64 are synonyms for __ptr32
and __ptr64 unless compiler option /Za (Disable language extensions) is specified.
Example
The following example shows how to declare and allocate pointers with the __ptr32 and
__ptr64 keywords.
C++
#include <cstdlib>
#include <iostream>
int main()
{
using namespace std;
int * __ptr32 p32;
int * __ptr64 p64;
Output
32
64
See also
Built-in types
Numerical Limits (C++)
Article • 08/03/2021 • 2 minutes to read
The two standard include files, <limits.h> and <float.h>, define the numerical limits, or
minimum and maximum values that a variable of a given type can hold. These
minimums and maximums are guaranteed to be portable to any C++ compiler that uses
the same data representation as ANSI C. The <limits.h> include file defines the
numerical limits for integral types, and <float.h> defines the numerical limits for floating
types.
See also
Basic Concepts
Integer Limits
Article • 08/03/2021 • 2 minutes to read
Microsoft-specific
The limits for integer types are listed in the following table. Preprocessor macros for
these limits are also defined when you include the standard header file <climits>.
CHAR_MIN Minimum value for a variable of type char . -128; 0 if /J option used
CHAR_MAX Maximum value for a variable of type char . 127; 255 if /J option used
If a value exceeds the largest integer representation, the Microsoft compiler generates
an error.
See also
Floating Limits
Floating Limits
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The following table lists the limits on the values of floating-point constants. These limits
are also defined in the standard header file <float.h>.
FLT_GUARD 0
FLT_NORMALIZE 0
7 Note
The information in the table may differ in future versions of the product.
See also
Integer Limits
Declarations and definitions (C++)
Article • 02/23/2022 • 4 minutes to read
A C++ program consists of various entities such as variables, functions, types, and
namespaces. Each of these entities must be declared before they can be used. A
declaration specifies a unique name for the entity, along with information about its type
and other characteristics. In C++ the point at which a name is declared is the point at
which it becomes visible to the compiler. You can't refer to a function or class that is
declared at some later point in the compilation unit. Variables should be declared as
close as possible before the point at which they're used.
C++
#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{/*...*/};
}
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.
C++
// Declare and define int variables i and j.
int i;
int j = 10;
C++
extern int i;
char *strchr( const char *Str, const char Target );
and not the actual name. In modern C++, the using keyword is preferred over typedef ,
but the idea is the same: a new name is declared for an entity, which is already declared
and defined.
extern declarations
A C++ program might contain more than one compilation unit. To declare an entity
that's defined in a separate compilation unit, use the extern keyword. The information in
the declaration is sufficient for the compiler. However, if the definition of the entity can't
be found in the linking step, then the linker will raise an error.
In this section
Storage classes
const
constexpr
extern
Initializers
Aliases and typedefs
using declaration
volatile
decltype
Attributes in C++
See also
Basic Concepts
Storage classes
Article • 02/15/2022 • 8 minutes to read
A storage class in the context of C++ variable declarations is a type specifier that
governs the lifetime, linkage, and memory location of objects. A given object can have
only one storage class. Variables defined within a block have automatic storage unless
otherwise specified using the extern , static , or thread_local specifiers. Automatic
objects and variables have no linkage; they aren't visible to code outside the block.
Memory is allocated for them automatically when execution enters the block, and it's
de-allocated when the block is exited.
Notes
The mutable keyword may be considered a storage class specifier. However, it's
only available in the member list of a class definition.
Visual Studio 2010 and later: The auto keyword is no longer a C++ storage-class
specifier, and the register keyword is deprecated. Visual Studio 2017 version 15.7
and later: (available in /std:c++17 mode and later): The register keyword is
removed from the C++ language. Its use causes a diagnostic message:
C++
// c5033.cpp
// compile by using: cl /c /std:c++17 c5033.cpp
register int value; // warning C5033: 'register' is no longer a
supported storage class
static
The static keyword can be used to declare variables and functions at global scope,
namespace scope, and class scope. Static variables can also be declared at local scope.
Static duration means that the object or variable is allocated when the program starts
and is deallocated when the program ends. External linkage means that the name of the
variable is visible from outside the file where the variable is declared. Conversely,
internal linkage means that the name isn't visible outside the file where the variable is
declared. By default, an object or variable that is defined in the global namespace has
static duration and external linkage. The static keyword can be used in the following
situations.
1. When you declare a variable or function at file scope (global and/or namespace
scope), the static keyword specifies that the variable or function has internal
linkage. When you declare a variable, the variable has static duration and the
compiler initializes it to 0 unless you specify another value.
2. When you declare a variable in a function, the static keyword specifies that the
variable retains its state between calls to that function.
3. When you declare a data member in a class declaration, the static keyword
specifies that one copy of the member is shared by all instances of the class. A
static data member must be defined at file scope. An integral data member that
you declare as const static can have an initializer.
4. When you declare a member function in a class declaration, the static keyword
specifies that the function is shared by all instances of the class. A static member
function can't access an instance member because the function doesn't have an
implicit this pointer. To access an instance member, declare the function with a
parameter that's an instance pointer or reference.
5. You can't declare the members of a union as static . However, a globally declared
anonymous union must be explicitly declared static .
This example shows how a variable declared static in a function retains its state
between calls to that function.
C++
// static1.cpp
// compile with: /EHsc
#include <iostream>
int main() {
for ( int i = 0; i < 5; i++ )
showstat( i );
}
Output
nStatic is 0
nStatic is 1
nStatic is 3
nStatic is 6
nStatic is 10
C++
// 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;
}
Output
0
0
1
1
2
2
3
3
The following example shows a local variable declared static in a member function.
The static variable is available to the whole program; all instances of the type share the
same copy of the static variable.
C++
// static3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
struct C {
void Test(int value) {
static int var = 0;
if (var == value)
cout << "var == value" << endl;
else
cout << "var != value" << endl;
var = value;
}
};
int main() {
C c1;
C c2;
c1.Test(100);
c2.Test(100);
}
Output
var != value
var == value
extern
Objects and variables declared as extern declare an object that is defined in another
translation unit or in an enclosing scope as having external linkage. For more
information, see extern and Translation units and linkage.
thread_local (C++11)
A variable declared with the thread_local specifier is accessible only on the thread on
which it's created. The variable is created when the thread is created, and it's destroyed
when the thread is destroyed. Each thread has its own copy of the variable. On
Windows, thread_local is functionally equivalent to the Microsoft-specific __declspec(
thread ) attribute.
C++
void DoSomething()
{
// Apply thread_local to a local variable.
// Implicitly "thread_local static S my_struct".
thread_local S my_struct;
}
You can specify thread_local only on data items with static storage duration,
which includes global data objects (both static and extern ), local static objects,
and static data members of classes. Any local variable declared thread_local is
implicitly static if no other storage class is provided; in other words, at block scope
thread_local is equivalent to thread_local static .
You must specify thread_local for both the declaration and the definition of a
thread local object, whether the declaration and definition occur in the same file or
separate files.
We don't recommend you use thread_local variables with std::launch::async .
For more information, see <future> functions.
register
Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): The
register keyword is no longer a supported storage class. Its use causes a diagnostic.
The keyword is still reserved in the standard for future use.
C++
Consider the following example, which defines a class that logs initialization and
destruction of objects and then defines three objects, I1 , I2 , and I3 :
C++
// initialization_of_objects.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>
using namespace std;
private:
char *szObjName;
size_t sizeofObjName;
};
Output
Initializing: Auto I1
In block.
Initializing: Auto I2
Initializing: Static I3
Destroying: Auto I2
Exited block.
Destroying: Auto I1
Destroying: Static I3
This example demonstrates how and when the objects I1 , I2 , and I3 are initialized and
when they're destroyed.
There are several points to note about the program:
First, I1 and I2 are automatically destroyed when the flow of control exits the
block in which they're defined.
Finally, static local variables such as I3 retain their values while the program runs,
but are destroyed as the program terminates.
See also
Declarations and Definitions
auto (C++)
Article • 11/30/2022 • 6 minutes to read
7 Note
The C++ standard defines an original and a revised meaning for this keyword.
Before Visual Studio 2010, the auto keyword declares a variable in the automatic
storage class; that is, a variable that has a local lifetime. Starting with Visual Studio
2010, the auto keyword declares a variable whose type is deduced from the
initialization expression in its declaration. The /Zc:auto[-] compiler option controls
the meaning of the auto keyword.
Syntax
auto declarator initializer ;
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:
Usability: You don't have to worry about type name spelling difficulties and typos.
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.
For more information, see Initializers and the code examples later in this document.
When auto is used to declare the loop parameter in a range-based for statement, it
uses a different initialization syntax, for example for (auto& i : iterable)
do_action(i); . For more information, see Range-based for Statement (C++).
The auto keyword is a placeholder for a type, but it isn't itself a type. Therefore, the
auto keyword can't be used in casts or operators such as sizeof and (for C++/CLI)
typeid.
Usefulness
The auto keyword is a simple way to declare a variable that has a complicated type. For
example, you can use auto to declare a variable where the initialization expression
involves templates, pointers to functions, or pointers to members.
You can also use auto to declare and initialize a variable to a lambda expression. You
can't declare the type of the variable yourself because the type of a lambda expression
is known only to the compiler. For more information, see Examples of Lambda
Expressions.
C++
int main( )
{
int count = 10;
int& countRef = count;
auto myAuto = countRef;
countRef = 11;
cout << count << " ";
myAuto = 12;
cout << count << endl;
}
In the previous example, myAuto is an int , not an int reference, so the output is 11
11 , not 11 12 as would be the case if the reference qualifier hadn't been dropped by
auto .
C++
#include <initializer_list>
int main()
{
// std::initializer_list<int>
auto A = { 1, 2 };
// std::initializer_list<int>
auto B = { 3 };
// int
auto C{ 4 };
return 0;
}
Error Description
number
C3530 The auto keyword can't be combined with any other type-specifier.
C3531 A symbol that is declared with the auto keyword must have an initializer.
C3532 You incorrectly used the auto keyword to declare a type. For example, you declared a
method return type or an array.
C3533, A parameter or template argument can't be declared with the auto keyword.
C3539
C3535 A method or template parameter can't be declared with the auto keyword.
C3536 A symbol can't be used before it's initialized. In practice, it means that a variable can't
be used to initialize itself.
C3537 You can't cast to a type that is declared with the auto keyword.
C3538 All the symbols in a declarator list that is declared with the auto keyword must resolve
to the same type. For more information, see Declarations and Definitions.
C3540, The sizeof and typeid operators can't be applied to a symbol that is declared with the
C3541 auto keyword.
Examples
These code fragments illustrate some of the ways in which the auto keyword can be
used.
The following declarations are equivalent. In the first statement, variable j is declared to
be type int . In the second statement, variable k is deduced to be type int because the
initialization expression (0) is an integer.
C++
The following declarations are equivalent, but the second declaration is simpler than the
first. One of the most compelling reasons to use the auto keyword is simplicity.
C++
map<int,list<string>>::iterator i = m.begin();
auto i = m.begin();
The following code fragment declares the type of variables iter and elem when the
for and range for loops start.
C++
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.
C++
double x = 12.34;
auto *y = new auto(x), **z = new auto(&x);
The next code fragment declares multiple symbols in each declaration statement. Notice
that all of the symbols in each statement resolve to the same type.
C++
C++
The following code fragment initializes variable x to type int , variable y to a reference
to type const int , and variable fp to a pointer to a function that returns type int .
C++
See also
Keywords
/Zc:auto (Deduce variable type)
sizeof operator
typeid
operator new
Declarations and definitions
Examples of lambda expressions
Initializers
decltype
const (C++)
Article • 03/13/2023 • 3 minutes to read
When it modifies a data declaration, the const keyword specifies that the object or
variable isn't modifiable.
Syntax
declarator :
ptr-declarator
noptr-declarator parameters-and-qualifiers trailing-return-type
ptr-declarator :
noptr-declarator
ptr-operator ptr-declarator
noptr-declarator :
declarator-id attribute-specifier-seq opt
noptr-declarator parameters-and-qualifiers
noptr-declarator [ constant-expression opt ] attribute-specifier-seq opt
( ptr-declarator )
parameters-and-qualifiers :
-> type-id
ptr-operator :
cv-qualifier :
const
volatile
ref-qualifier :
&
&&
declarator-id :
const values
The const keyword specifies that a variable's value is constant and tells the compiler to
prevent the programmer from modifying it.
C++
// constant_values1.cpp
int main() {
const int i = 5;
i = 10; // C3892
i++; // C2105
}
In C++, you can use the const keyword instead of the #define preprocessor directive to
define constant values. Values defined with const are subject to type checking, and can
be used in place of constant expressions. In C++, you can specify the size of an array
with a const variable as follows:
C++
// constant_values2.cpp
// compile with: /c
const int maxarray = 255;
char store_char[maxarray]; // allowed in C++; not allowed in C
In C, constant values default to external linkage, so they can appear only in source files.
In C++, constant values default to internal linkage, which allows them to appear in
header files.
C++
// constant_values3.cpp
int main() {
char this_char{'a'}, that_char{'b'};
char *mybuf = &this_char, *yourbuf = &that_char;
char *const aptr = mybuf;
*aptr = 'c'; // OK
aptr = yourbuf; // C3892
}
A pointer to a variable declared as const can be assigned only to a pointer that is also
declared as const .
C++
// constant_values4.cpp
#include <stdio.h>
int main() {
const char *mybuf = "test";
char *yourbuf = "test2";
printf_s("%s\n", mybuf);
You can use pointers to constant data as function parameters to prevent the function
from modifying a parameter passed through a pointer.
For objects that are declared as const , you can only call constant member functions.
The compiler ensures that the constant object is never modified.
C++
birthday.getMonth(); // Okay
birthday.setMonth( 4 ); // Error
You can call either constant or non-constant member functions for a non-constant
object. You can also overload a member function using the const keyword; this feature
allows a different version of the function to be called for constant and non-constant
objects.
// 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 define your const variable as:
C++
extern const int i = 2;
Similar to C, you can then use this variable in another module as follows:
C++
If you wish to define an extern variable in a C++ source code file for use in a C source
code file, use:
C++
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.
volatile
#define
See also
Keywords
constexpr (C++)
Article • 02/22/2023 • 5 minutes to read
The keyword constexpr was introduced in C++11 and improved in C++14. It means
constant expression. Like const , it can be applied to variables: A compiler error is raised
when any code attempts to modify the value. Unlike const , constexpr can also be
applied to functions and class constructors. constexpr indicates that the value, or return
value, is constant and, where possible, is computed at compile time.
A constexpr integral value can be used wherever a const integer is required, such as in
template arguments and array declarations. And when a value is computed at compile
time instead of run time, it helps your program run faster and use less memory.
Syntax
constexpr literal-type identifier = constant-expression ;
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.
C++
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.
C++
Tip
In the Visual Studio debugger, when debugging a non-optimised Debug build, you
can tell whether a constexpr function is being evaluated at compile time by putting
a breakpoint inside it. If the breakpoint is hit, the function was called at run-time. If
not, then the function was called at compile time.
extern constexpr
The /Zc:externConstexpr compiler option causes the compiler to apply external linkage
to variables declared by using extern constexpr. In earlier versions of Visual Studio,
either by default or when /Zc:externConstexpr- is specified, Visual Studio applies
internal linkage to constexpr variables even when the extern keyword is used. The
/Zc:externConstexpr option is available starting in Visual Studio 2017 Update 15.6, and
is off by default. The /permissive- option doesn't enable /Zc:externConstexpr.
Example
The following example shows constexpr variables, functions, and a user-defined type. In
the last statement in main() , the constexpr member function GetValue() is a run-time
call because the value isn't required to be known at compile time.
C++
// constexpr.cpp
// Compile with: cl /EHsc /W4 constexpr.cpp
#include <iostream>
// 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;
}
int main()
{
// foo is const:
constexpr Foo foo(5);
// foo = Foo(6); //Error!
// Compile time:
constexpr float x = exp(5, 3);
constexpr float y { exp(2, 5) };
constexpr int val = foo.GetValue();
constexpr int f5 = fac(5);
const int nums[] { 1, 2, 3, 4 };
const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };
// Run time:
cout << "The value of foo is " << foo.GetValue() << endl;
}
Requirements
Visual Studio 2015 or later.
See also
Declarations and definitions
const
extern (C++)
Article • 12/03/2021 • 4 minutes to read
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.
C++
//fileA.cpp
int i = 42; // declaration and definition
//fileB.cpp
extern int i; // declaration only. same as i in FileA
//fileC.cpp
extern int i; // declaration only. same as i in FileA
//fileD.cpp
int i = 43; // LNK2005! 'i' already has a definition.
extern int i = 43; // same error (extern is ignored on definitions)
C++
//fileA.cpp
extern const int i = 42; // extern const definition
//fileB.cpp
extern const int i; // declaration only. same as i in FileA
C++
extern constexpr int x = 10; //error LNK2005: "int const x" already defined
C++
Microsoft C++ supports the strings "C" and "C++" in the string-literal field. All of the
standard include files use the extern "C" syntax to allow the run-time library functions
to be used in C++ programs.
Example
The following example shows how to declare names that have C linkage:
C++
If a function has more than one linkage specification, they must agree. It's an error to
declare functions as having both C and C++ linkage. Furthermore, if two declarations for
a function occur in a program, one with a linkage specification and one without, the
declaration with the linkage specification must be first. Any redundant declarations of
functions that already have linkage specification are given the linkage specified in the
first declaration. For example:
C++
int CFunc2();
...
extern "C" int CFunc2(); // Error: not the first declaration of
// CFunc2; cannot contain linkage
// specifier.
Starting in Visual Studio 2019, when /permissive- is specified, the compiler checks that
the declarations of extern "C" function parameters also match. You can't overload a
function declared as extern "C" . Starting in Visual Studio 2019 version 16.3, you can
override this check by using the /Zc:externC- compiler option after the /permissive-
option.
See also
Keywords
Translation units and linkage
extern Storage-Class Specifier in C
Behavior of Identifiers in C
Linkage in C
Initializers
Article • 04/04/2023 • 12 minutes to read
An initializer specifies the initial value of a variable. You can initialize variables in these
contexts:
C++
int i = 3;
Point p1{ 1, 2 };
C++
set_point(Point{ 5, 6 });
C++
C++
C++
string s = "hello";
A braced initializer list. The list may be empty or may consist of a set of lists, as in
the following example:
C++
struct Point{
int x;
int y;
};
class PointConsumer{
public:
void set_point(Point p){};
void set_points(initializer_list<Point> my_list){};
};
int main() {
PointConsumer pc{};
pc.set_point({});
pc.set_point({ 3, 4 });
pc.set_points({ { 3, 4 }, { 5, 6 } });
}
Kinds of initialization
There are several kinds of initialization, which may occur at different points in program
execution. Different kinds of initialization aren't mutually exclusive—for example, list
initialization can trigger value initialization and in other circumstances, it can trigger
aggregate initialization.
Zero initialization
Zero initialization is the setting of a variable to a zero value implicitly converted to the
type:
Arrays, POD classes, structs, and unions have their members initialized to a zero
value.
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.
C++
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:
C++
MyClass mc1;
MyClass* mc3 = new MyClass;
If the class, struct, or union doesn't have a default constructor, the compiler emits an
error.
Scalar variables are default initialized when they're defined with no initialization
expression. They have indeterminate values.
C++
int i1;
float f;
char c;
Arrays are default initialized when they're defined with no initialization expression. When
an array is default-initialized, its members are default initialized and have indeterminate
values, as in the following example:
C++
int int_arr[3];
If the array members don't have a default constructor, the compiler emits an error.
Constant variables must be declared together with an initializer. If they're scalar types
they cause a compiler error, and if they're class types that have a default constructor
they cause a warning:
C++
class MyClass{};
int main() {
//const int i2; // compiler error C2734: const object must be
initialized if not extern
//const char c2; // same error
const MyClass mc1; // compiler error C4269: 'const automatic data
initialized with compiler generated default constructor produces unreliable
results
}
Static variables that are declared with no initializer are initialized to 0 (implicitly
converted to the type).
C++
class MyClass {
private:
int m_int;
char m_char;
};
int main() {
static int int1; // 0
static char char1; // '\0'
static bool bool1; // false
static MyClass mc1; // {0, '\0'}
}
For more information about initialization of global static objects, see main function and
command-line arguments.
Value initialization
Value initialization occurs in the following cases:
an object is initialized with the new keyword plus empty parentheses or braces
for classes with at least one public constructor, the default constructor is called
C++
class BaseClass {
private:
int m_int;
};
int main() {
BaseClass bc{}; // class is initialized
BaseClass* bc2 = new BaseClass(); // class is initialized, m_int value
is 0
int int_arr[3]{}; // value of all members is 0
int a{}; // value of a is 0
double b{}; // value of b is 0.00000000000000000
}
Copy initialization
Copy initialization is the initialization of one object using a different object. It occurs in
the following cases:
a variable is initialized using an equals sign
class, struct, and union members are initialized by copy initialization during
aggregate initialization. See Aggregate initialization for examples.
C++
#include <iostream>
using namespace std;
class MyClass{
public:
MyClass(int myInt) {}
void set_int(int myInt) { m_int = myInt; }
int get_int() const { return m_int; }
private:
int m_int = 7; // copy initialization of m_int
};
class MyException : public exception{};
int main() {
int i = 5; // copy initialization of i
MyClass mc1{ i };
MyClass mc2 = mc1; // copy initialization of mc2 from mc1
MyClass mc1.set_int(i); // copy initialization of parameter from i
int i2 = mc2.get_int(); // copy initialization of i2 from return value
of get_int()
try{
throw MyException();
}
catch (MyException ex){ // copy initialization of ex
cout << ex.what();
}
}
C++
vector<int> v = 10; // the constructor is explicit; compiler error C2440:
can't convert from 'int' to 'std::vector<int,std::allocator<_Ty>>'
regex r = "a.*b"; // the constructor is explicit; same error
shared_ptr<int> sp = new int(1729); // the constructor is explicit; same
error
In some cases, if the copy constructor of the class is deleted or inaccessible, copy
initialization causes a compiler error.
Direct initialization
Direct initialization is initialization using (non-empty) braces or parentheses. Unlike copy
initialization, it can invoke explicit constructors. It occurs in the following cases:
C++
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
C++
class MyClass {
public:
MyClass(int myInt, char myChar) {}
private:
int m_int[]{ 3 };
char m_char;
};
class MyClassConsumer{
public:
void set_class(MyClass c) {}
MyClass get_class() { return MyClass{ 0, '\0' }; }
};
struct MyStruct{
int my_int;
char my_char;
MyClass my_class;
};
int main() {
MyClass mc1{ 1, 'a' };
MyClass* mc2 = new MyClass{ 2, 'b' };
MyClass mc3 = { 3, 'c' };
MyClassConsumer mcc;
mcc.set_class(MyClass{ 3, 'c' });
mcc.set_class({ 4, 'd' });
Aggregate initialization
Aggregate initialization is a form of list initialization for arrays or class types (often
structs or unions) that have:
no base classes
7 Note
In Visual Studio 2015 and earlier, an aggregate is not allowed to have brace-or-
equal initializers for non-static members. This restriction was removed in the
C++14 standard and implemented in Visual Studio 2017.
Aggregate initializers consist of a braced initialization list, with or without an equals sign,
as in the following example:
C++
#include <iostream>
using namespace std;
struct MyAggregate{
int myInt;
char myChar;
};
struct MyAggregate2{
int myInt;
char myChar = 'Z'; // member-initializer OK in C++14
};
int main() {
MyAggregate agg1{ 1, 'c' };
MyAggregate2 agg2{2};
cout << "agg1: " << agg1.myChar << ": " << agg1.myInt << endl;
cout << "agg2: " << agg2.myChar << ": " << agg2.myInt << endl;
int myArr1[]{ 1, 2, 3, 4 };
int myArr2[3] = { 5, 6, 7 };
int myArr3[5] = { 8, 9, 10 };
Output
agg1: c: 1
agg2: Z: 2
myArr1: 1 2 3 4
myArr3: 8 9 10 0 0
) Important
Array members that are declared but not explicitly initialized during aggregate
initialization are zero-initialized, as in myArr3 above.
C++
struct MyStruct {
int myInt;
char myChar;
};
union MyUnion {
int my_int;
char my_char;
bool my_bool;
MyStruct my_struct;
};
int main() {
MyUnion mu1{ 'a' }; // my_int = 97, my_char = 'a', my_bool = true,
{myInt = 97, myChar = '\0'}
MyUnion mu2{ 1 }; // my_int = 1, my_char = 'x1', my_bool = true,
{myInt = 1, myChar = '\0'}
MyUnion mu3{}; // my_int = 0, my_char = '\0', my_bool = false,
{myInt = 0, myChar = '\0'}
MyUnion mu4 = mu3; // my_int = 0, my_char = '\0', my_bool = false,
{myInt = 0, myChar = '\0'}
//MyUnion mu5{ 1, 'a', true }; // compiler error: C2078: too many
initializers
//MyUnion mu6 = 'a'; // compiler error: C2440: cannot convert
from 'char' to 'MyUnion'
//MyUnion mu7 = 1; // compiler error: C2440: cannot convert
from 'int' to 'MyUnion'
C++
struct MyStruct {
int myInt;
char myChar;
};
int main() {
int intArr1[2][2]{{ 1, 2 }, { 3, 4 }};
int intArr3[2][2] = {1, 2, 3, 4};
MyStruct structArr[]{ { 1, 'a' }, { 2, 'b' }, {3, 'c'} };
}
Reference initialization
Variables of reference type must be initialized with an object of the type from which the
reference type is derived, or with an object of a type that can be converted to the type
from which the reference type is derived. For example:
C++
// initializing_references.cpp
int iVar;
long lVar;
int main()
{
long& LongRef1 = lVar; // No conversion required.
long& LongRef2 = iVar; // Error C2440
const long& LongRef3 = iVar; // OK
LongRef1 = 23L; // Change lVar through a reference.
LongRef2 = 11L; // Change iVar through a reference.
LongRef3 = 11L; // Error C3892
}
The only way to initialize a reference with a temporary object is to initialize a constant
temporary object. Once initialized, a reference-type variable always points to the same
object; it can't be modified to point to another object.
Although the syntax can be the same, initialization of reference-type variables and
assignment to reference-type variables are semantically different. In the preceding
example, the assignments that change iVar and lVar look similar to the initializations,
but have different effects. The initialization specifies the object to which the reference-
type variable points; the assignment assigns to the referred-to object through the
reference.
Because both passing an argument of reference type to a function and returning a value
of reference type from a function are initializations, the formal arguments to a function
are initialized correctly, as are the references returned.
C++
C++
C++
C++
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
C++
Remarks
identifier
The name of the alias.
type
The type identifier you're creating an alias for.
An alias doesn't introduce a new type and can't change the meaning of an existing type
name.
The simplest form of an alias is equivalent to the typedef mechanism from C++03:
C++
// C++11
using counter = long;
// C++03 equivalent:
// typedef long counter;
Both of these forms enable the creation of variables of type counter . Something more
useful would be a type alias like this one for std::ios_base::fmtflags :
C++
// C++11
using fmtfl = std::ios_base::fmtflags;
// C++03 equivalent:
// typedef std::ios_base::fmtflags fmtfl;
Aliases also work with function pointers, but are much more readable than the
equivalent typedef:
C++
// C++11
using func = void(*)(int);
// C++03 equivalent:
// typedef void (*func)(int);
A limitation of the typedef mechanism is that it doesn't work with templates. However,
the type alias syntax in C++11 enables the creation of alias templates:
C++
Example
The following example demonstrates how to use an alias template with a custom
allocator—in this case, an integer vector type. You can substitute any type for int to
create a convenient alias to hide the complex parameter lists in your main functional
code. By using the custom allocator throughout your code, you can improve readability
and reduce the risk of introducing bugs caused by typos.
C++
#include <stdlib.h>
#include <new>
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;
}
Output
1701 1764 1664
Typedefs
A typedef declaration introduces a name that, within its scope, becomes a synonym for
the type given by the type-declaration portion of the declaration.
You can use typedef declarations to construct shorter or more meaningful names for
types already defined by the language or for types that you've declared. Typedef names
allow you to encapsulate implementation details that may change.
In contrast to the class , struct , union , and enum declarations, typedef declarations
don't introduce new types; they introduce new names for existing types.
Names declared using typedef occupy the same namespace as other identifiers (except
statement labels). Therefore, they can't use the same identifier as a previously declared
name, except in a class-type declaration. Consider the following example:
C++
// typedef_names1.cpp
// C2377 expected
typedef unsigned long UL; // Declare a typedef name, UL.
int UL; // C2377: redefined.
The name-hiding rules that pertain to other identifiers also govern the visibility of
names declared using typedef . Therefore, the following example is legal in C++:
C++
// typedef_names2.cpp
typedef unsigned long UL; // Declare a typedef name, UL
int main()
{
unsigned int UL; // Redeclaration hides typedef name
}
C++
// 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:
C++
To reuse the FlagType name for an identifier, a structure member, or a union member,
the type must be provided:
C++
C++
because the FlagType is taken to be part of the type, not an identifier that's being
redeclared. This declaration is taken to be an illegal declaration, similar to:
C++
You can declare any type with typedef , including pointer, function, and array types. You
can declare a typedef name for a pointer to a structure or union type before you define
the structure or union type, as long as the definition has the same visibility as the
declaration.
Examples
One use of typedef declarations is to make declarations more uniform and compact. For
example:
C++
To use typedef to specify fundamental and derived types in the same declaration, you
can separate declarators with commas. For example:
C++
The following example provides the type DRAWF for a function returning no value and
taking two int arguments:
C++
C++
DRAWF box;
C++
typedef is often combined with struct to declare and name user-defined types:
C++
// 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);
}
Output
10 0.990000
Redeclaration of typedefs
The typedef declaration can be used to redeclare the same name to refer to the same
type. For example:
C++
// file1.h
typedef char CHAR;
C++
// file2.h
typedef char CHAR;
C++
// prog.cpp
#include "file1.h"
#include "file2.h" // OK
The file prog.cpp includes two header files, both of which contain typedef declarations
for the name CHAR . As long as both declarations refer to the same type, such
redeclaration is acceptable.
A typedef can't redefine a name that was previously declared as a different type.
Consider this alternative file2.h :
C++
// file2.h
typedef int CHAR; // Error
The compiler issues an error in prog.cpp because of the attempt to redeclare the name
CHAR to refer to a different type. This policy extends to constructs such as:
C++
C++
// typedef_with_class_types1.cpp
// compile with: /c
typedef struct { // Declare an unnamed structure and give it the
// typedef name POINT.
unsigned x;
unsigned y;
} POINT;
The advantage of such a declaration is that it enables declarations like:
C++
POINT ptOrigin;
instead of:
C++
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
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.
In summary, this syntax doesn't provide any mechanism for inheritance, construction, or
destruction.
using declaration
Article • 08/03/2021 • 5 minutes to read
The using declaration introduces a name into the declarative region in which the using
declaration appears.
Syntax
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.
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.
// using_declaration1.cpp
#include <stdio.h>
class B {
public:
void f(char) {
printf_s("In B::f()\n");
}
void g(char) {
printf_s("In B::g()\n");
}
};
class D : B {
public:
using B::f; // B::f(char) is now visible as D::f(char)
using B::g; // B::g(char) is now visible as D::g(char)
void f(int) {
printf_s("In D::f()\n");
f('c'); // Invokes B::f(char) instead of recursing
}
void g(int) {
printf_s("In D::g()\n");
g('c'); // Invokes B::g(char) instead of recursing
}
};
int main() {
D myD;
myD.f(1);
myD.g('a');
}
Output
In D::f()
In B::f()
In B::g()
// using_declaration2.cpp
#include <stdio.h>
class B {
public:
void f(char) {
printf_s("In B::f()\n");
}
void g(char) {
printf_s("In B::g()\n");
}
};
class C {
public:
int g();
};
class D2 : public B {
public:
using B::f; // ok: B is a base of D2
// using C::g; // error: C isn't a base of D2
};
int main() {
D2 MyD2;
MyD2.f('a');
}
Output
In B::f()
C++
// using_declaration3.cpp
#include <stdio.h>
void f() {
printf_s("In f\n");
}
namespace A {
void g() {
printf_s("In A::g\n");
}
}
namespace X {
using ::f; // global f is also visible as X::f
using A::g; // A's g is now visible as X::g
}
void h() {
printf_s("In h\n");
X::f(); // calls ::f
X::g(); // calls A::g
}
int main() {
h();
}
Output
In h
In f
In A::g
A name defined by a using declaration is an alias for its original name. It does not affect
the type, linkage or other attributes of the original declaration.
C++
// post_declaration_namespace_additions.cpp
// compile with: /c
namespace A {
void f(int) {}
}
using A::f; // f is a synonym for A::f(int) only
namespace A {
void f(char) {}
}
void f() {
f('a'); // refers to A::f(int), even though A::f(char) exists
}
void b() {
using A::f; // refers to A::f(int) AND A::f(char)
f('a'); // calls A::f(char);
}
C++
// functions_in_namespaces1.cpp
// C2874 expected
namespace B {
int i;
void f(int);
void f(double);
}
void g() {
int i;
using B::i; // error: i declared twice
void f(char);
using B::f; // ok: each f is a function
}
In the example above, the using B::i statement causes a second int i to be declared
in the g() function. The using B::f statement does not conflict with the f(char)
function because the function names introduced by B::f have different parameter
types.
Example: Local function declarations and using
declarations
A local function declaration cannot have the same name and type as a function
introduced by using declaration. For example:
C++
// functions_in_namespaces2.cpp
// C2668 expected
namespace B {
void f(int);
void f(double);
}
namespace C {
void f(int);
void f(double);
void f(char);
}
void h() {
using B::f; // introduces B::f(int) and B::f(double)
using C::f; // C::f(int), C::f(double), and C::f(char)
f('h'); // calls C::f(char)
f(1); // C2668 ambiguous: B::f(int) or C::f(int)?
void f(int); // C2883 conflicts with B::f(int) and C::f(int)
}
C++
// using_declaration_inheritance1.cpp
#include <stdio.h>
struct B {
virtual void f(int) {
printf_s("In B::f(int)\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);
}
Output
In D::f(int)
In B::f(char)
In B::g
In D::g(char)
// using_declaration_inheritance2.cpp
// C2876 expected
class A {
private:
void f(char);
public:
void f(int);
protected:
void g();
};
class B : public A {
using A::f; // C2876: A::f(char) is inaccessible
public:
using A::g; // B::g is a public synonym for A::g
};
See also
Namespaces
Keywords
volatile (C++)
Article • 09/21/2021 • 3 minutes to read
A type qualifier that you can use to declare that an object can be modified in the
program by the hardware.
Syntax
volatile declarator ;
Remarks
You can use the /volatile compiler switch to modify how the compiler interprets this
keyword.
Visual Studio interprets the volatile keyword differently depending on the target
architecture. For ARM, if no /volatile compiler option is specified, the compiler performs
as if /volatile:iso were specified. For architectures other than ARM, if no /volatile
compiler option is specified, the compiler performs as if /volatile:ms were specified;
therefore, for architectures other than ARM we strongly recommend that you specify
/volatile:iso, and use explicit synchronization primitives and compiler intrinsics when
you are dealing with memory that is shared across threads.
You can use the volatile qualifier to provide access to memory locations that are used
by asynchronous processes such as interrupt handlers.
When volatile is used on a variable that also has the __restrict keyword, volatile
takes precedence.
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.
When the /volatile:ms compiler option is used—by default when architectures other
than ARM are targeted—the compiler generates extra code to maintain ordering among
references to volatile objects in addition to maintaining ordering to references to other
global objects. In particular:
A write to a volatile object (also known as volatile write) has Release semantics;
that is, a reference to a global or static object that occurs before a write to a
volatile object in the instruction sequence will occur before that volatile write in
the compiled binary.
A read of a volatile object (also known as volatile read) has Acquire semantics; that
is, a reference to a global or static object that occurs after a read of volatile
memory in the instruction sequence will occur after that volatile read in the
compiled binary.
This enables volatile objects to be used for memory locks and releases in multithreaded
applications.
7 Note
When it relies on the enhanced guarantee that's provided when the /volatile:ms
compiler option is used, the code is non-portable.
See also
Keywords
const
const and volatile Pointers
decltype (C++)
Article • 09/28/2022 • 5 minutes to read
The decltype type specifier yields the type of a specified expression. The decltype type
specifier, together with the auto keyword, is useful primarily to developers who write
template libraries. Use auto and decltype to declare a function template whose return
type depends on the types of its template arguments. Or, use auto and decltype to
declare a function template that wraps a call to another function, and then returns the
return type of the wrapped function.
Syntax
decltype( expression )
Parameters
expression
An expression. For more information, see Expressions.
Return value
The type of the expression parameter.
Remarks
The decltype type specifier is supported in Visual Studio 2010 or later versions, and can
be used with native or managed code. decltype(auto) (C++14) is supported in Visual
Studio 2015 and later.
The compiler uses the following rules to determine the type of the expression
parameter.
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.
The following code example demonstrates some uses of the decltype type specifier.
First, assume that you've coded the following statements.
C++
int var;
const int&& fx();
struct A { double x; }
const A* a = new A();
Next, examine the types that are returned by the four decltype statements in the
following table.
In C++11, you can use the decltype type specifier on a trailing return type, together
with the auto keyword, to declare a function template whose return type depends on
the types of its template arguments. For example, consider the following code example
in which the return type of the function template depends on the types of the template
arguments. In the code example, the UNKNOWN placeholder indicates that the return type
can't be specified.
C++
The introduction of the decltype type specifier enables a developer to obtain the type
of the expression that the function template returns. Use the alternative function
declaration syntax that is shown later, the auto keyword, and the decltype type specifier
to declare a late-specified return type. The late-specified return type is determined when
the declaration is compiled, instead of when it's coded.
The following prototype illustrates the syntax of an alternative function declaration. The
const and volatile qualifiers, and the throw exception specification are optional. The
function_body placeholder represents a compound statement that specifies what the
function does. As a best coding practice, the expression placeholder in the decltype
statement should match the expression specified by the return statement, if any, in the
function_body .
auto function_name ( parameters opt ) const opt volatile opt -> decltype( expression
) noexcept opt { function_body };
In the following code example, the late-specified return type of the myFunc function
template is determined by the types of the t and u template arguments. As a best
coding practice, the code example also uses rvalue references and the forward function
template, which support perfect forwarding. For more information, see Rvalue reference
declarator: &&.
C++
//C++11
template<typename T, typename U>
auto myFunc(T&& t, U&& u) -> decltype (forward<T>(t) + forward<U>(u))
{ return forward<T>(t) + forward<U>(u); };
//C++14
template<typename T, typename U>
decltype(auto) myFunc(T&& t, U&& u)
{ return forward<T>(t) + forward<U>(u); };
In this scenario, you can't write an appropriate type expression without the decltype
type specifier. The decltype type specifier enables generic forwarding functions because
it doesn't lose required information about whether a function returns a reference type.
For a code example of a forwarding function, see the previous myFunc function template
example.
Examples
The following code example declares the late-specified return type of function template
Plus() . The Plus function processes its two operands with the operator+ overload. So,
the interpretation of the plus operator ( + ) and the return type of the Plus function
depends on the types of the function arguments.
C++
// decltype_1.cpp
// compile with: cl /EHsc decltype_1.cpp
#include <iostream>
#include <string>
#include <utility>
#include <iomanip>
class X
{
friend X operator+(const X& x1, const X& x2)
{
return X(x1.m_data + x2.m_data);
}
public:
X(int data) : m_data(data) {}
int Dump() const { return m_data;}
private:
int m_data;
};
int main()
{
// Integer
int i = 4;
cout <<
"Plus(i, 9) = " <<
Plus(i, 9) << endl;
// Floating point
float dx = 4.0;
float dy = 9.5;
cout <<
setprecision(3) <<
"Plus(dx, dy) = " <<
Plus(dx, dy) << endl;
// String
string hello = "Hello, ";
string world = "world!";
cout << Plus(hello, world) << endl;
// Custom type
X x1(20);
X x2(22);
X x3 = Plus(x1, x2);
cout <<
"x3.Dump() = " <<
x3.Dump() << endl;
}
Output
Plus(i, 9) = 13
Plus(dx, dy) = 13.5
Hello, world!
x3.Dump() = 42
Visual Studio 2017 and later: The compiler parses decltype arguments when the
templates are declared rather than instantiated. So, if a non-dependent specialization is
found in the decltype argument, it won't be deferred to instantiation-time; it's
processed immediately and any resulting errors are diagnosed at that time.
The following example shows such a compiler error that is raised at the point of
declaration:
C++
#include <utility>
template <class T, class ReturnT, class... ArgsT> class IsCallable
{
public:
struct BadType {};
template <class U>
static decltype(std::declval<T>()(std::declval<ArgsT>()...)) Test(int);
//C2064. Should be declval<U>
template <class U>
static BadType Test(...);
static constexpr bool value = std::is_convertible<decltype(Test<T>(0)),
ReturnT>::value;
};
Requirements
Visual Studio 2010 or later versions.
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.
Visual Studio 2017 version 15.3 and later (Available with /std:c++17 and later): In the
scope of an attribute list, you can specify the namespace for all names with a single
using introducer:
C++
void g() {
[[using rpr: kernel, target(cpu,gpu)]] // equivalent to [[ rpr::kernel,
rpr::target(cpu,gpu) ]]
do task();
}
C++
[[deprecated]]
void Foo(int);
Attributes represent a standardized alternative to vendor-specific extensions such as
#pragma directives, __declspec() (Visual C++), or __attribute__ (GNU). However, you'll
still need to use the vendor-specific constructs for most purposes. The standard
currently specifies the following attributes that a conforming compiler should recognize.
[[carries_dependency]]
[[deprecated]]
Visual Studio 2015 and later: The [[deprecated]] attribute specifies that a function isn't
intended for use. Or, that it might not exist in future versions of a library interface. The
[[deprecated]] attribute can be applied to declaration of a class, a typedef-name, a
variable, a nonstatic data member, a function, a namespace, an enumeration, an
enumerator, or a template specialization. The compiler can use this attribute to generate
an informational message when client code attempts to call the function. When the
Microsoft C++ compiler detects the use of a [[deprecated]] item, it raises compiler
warning C4996.
[[fallthrough]]
Visual Studio 2017 and later: (Available with /std:c++17 and later.) The [[fallthrough]]
attribute can be used in the context of switch statements as a hint to the compiler (or
anyone reading the code) that the fallthrough behavior is intended. The Microsoft C++
compiler currently doesn't warn on fallthrough behavior, so this attribute has no effect
on compiler behavior.
[[likely]]
Visual Studio 2019 version 16.6 and later: (Available with /std:c++20 and later.) The
[[likely]] attribute specifies a hint to the compiler that the code path for the
attributed label or statement is more likely to execute than alternatives. In the Microsoft
compiler, the [[likely]] attribute marks blocks as "hot code", which increments an
internal optimization score. The score is incremented more when optimizing for speed,
and not as much when optimizing for size. The net score affects the likelihood of
inlining, loop unrolling, and vectorizing optimizations. The effect of [[likely]] and
[[unlikely]] is similar to Profile-guided optimization, but limited in scope to the
current translation unit. The block reordering optimization isn't implemented yet for this
attribute.
[[maybe_unused]]
Visual Studio 2017 version 15.3 and later: (Available with /std:c++17 and later.) The
[[maybe_unused]] attribute specifies that a variable, function, class, typedef, nonstatic
[[nodiscard]]
Visual Studio 2017 version 15.3 and later: (Available with /std:c++17 and later.)
Specifies that a function's return value isn't intended to be discarded. Raises warning
C4834, as shown in this example:
C++
[[nodiscard]]
int foo(int i) { return i * i; }
int main()
{
foo(42); //warning C4834: discarding return value of function with
'nodiscard' attribute
return 0;
}
[[noreturn]]
The [[noreturn]] attribute specifies that a function never returns; in other words, it
always throws an exception or exits. The compiler can adjust its compilation rules for
[[noreturn]] entities.
[[unlikely]]
Visual Studio 2019 version 16.6 and later: (Available with /std:c++20 and later.) The
[[unlikely]] attribute specifies a hint to the compiler that the code path for the
attributed label or statement is less likely to execute than alternatives. In the Microsoft
compiler, the [[unlikely]] attribute marks blocks as "cold code", which decrements an
internal optimization score. The score is decremented more when optimizing for size,
and not as much when optimizing for speed. The net score affects the likelihood of
inlining, loop unrolling, and vectorizing optimizations. The block reordering optimization
isn't implemented yet for this attribute.
Microsoft-specific attributes
[[gsl::suppress(rules)]]
C++
int main()
{
int arr[10]; // GSL warning C26494 will be fired
int* p = arr; // GSL warning C26485 will be fired
[[gsl::suppress(bounds.1)]] // This attribute suppresses Bounds rule #1
{
int* q = p + 1; // GSL warning C26481 suppressed
p = q--; // GSL warning C26481 suppressed
}
}
C26481 (Bounds Rule 1: Don't use pointer arithmetic. Use span instead.)
The first two warnings fire when you compile this code with the CppCoreCheck code
analysis tool installed and activated. But the third warning doesn't fire because of the
attribute. You can suppress the entire bounds profile by writing
[[gsl::suppress(bounds)]] without including a specific rule number. The C++ Core
Guidelines are designed to help you write better and safer code. The suppress attribute
makes it easy to turn off the warnings when they aren't wanted.
[[msvc::flatten]]
[[msvc::forceinline]]
[[msvc::forceinline_calls]]
C++
void f() {
[[msvc::forceinline_calls]]
{
foo();
bar();
}
...
[[msvc::forceinline_calls]]
bar();
foo();
}
The first call to foo , and both calls to bar , are treated as if they were declared
__forceinline . The second call to foo isn't treated as __forceinline .
[[msvc::intrinsic]]
The Microsoft-specific [[msvc::intrinsic]] attribute tells the compiler to inline a
metafunction that acts as a named cast from the parameter type to the return type.
When the attribute is present on a function definition, the compiler replaces all calls to
that function with a simple cast. The [[msvc::intrinsic]] attribute is available in Visual
Studio 2022 version 17.5 preview 2 and later versions. This attribute applies only to the
specific function that follows it.
The [[msvc::intrinsic]] attribute has three constraints on the function it's applied to:
The function can't be recursive; its body must only have a return statement with a
cast.
The function can only accept a single parameter.
The /permissive- compiler option is required. (The /std:c++20 and later options
imply /permissive- by default.)
Example
In this sample code, the [[msvc::intrinsic]] attribute applied to the my_move function
makes the compiler replace calls to the function with the inlined static cast in its body:
C++
void f() {
int i = 0;
i = my_move(i);
}
[[msvc::noinline]]
[[msvc::noinline_calls]]
than force-inlining all calls in that block, it has the effect of turning off inlining for the
scope it's applied to.
[[msvc::no_tls_guard]]
The 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.
Scope resolution ::
Array subscript []
Operator Description Operator Alternative
Function call ()
Postfix increment ++
Postfix decrement --
Prefix increment ++
Prefix decrement --
Unary negation -
Unary plus +
Address-of &
Indirection *
Cast ()
Multiplication *
Division /
Operator Description Operator Alternative
Modulus %
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
Article • 04/22/2022 • 2 minutes to read
The alignof operator returns the alignment in bytes of the specified type as a value of
type size_t .
Syntax
C++
alignof( type )
Remarks
For example:
Expression Value
alignof( char ) 1
alignof( short ) 2
alignof( int ) 4
alignof( float ) 4
alignof( double ) 8
The alignof value is the same as the value for sizeof for basic types. Consider,
however, this example:
C++
In this case, the alignof value is the alignment requirement of the largest element in
the structure.
Similarly, for
C++
alignof(S) is equal to 32 .
One use for alignof would be as a parameter to one of your own memory-allocation
routines. For example, given the following defined structure S , you could call a
memory-allocation routine named aligned_malloc to allocate memory on a particular
alignment boundary.
C++
pack
align
__unaligned
/Zp (Struct member alignment)
x64 structure alignment examples
For more information on differences in alignment in code for x86 and x64, see:
Microsoft-specific
alignof and __alignof are synonyms in the Microsoft compiler. Before it became part
For compatibility with previous versions, _alignof is a synonym for __alignof unless
compiler option /Za (Disable language extensions) is specified.
See also
Expressions with Unary Operators
Keywords
__uuidof Operator
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
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.
7 Note
For compatibility with previous versions, _uuidof is a synonym for __uuidof unless
compiler option /Za (Disable language extensions) is specified.
Example
The following code (compiled with ole32.lib) will display the uuid of a library block
created with the module attribute:
C++
// expre_uuidof.cpp
// compile with: ole32.lib
#include "stdio.h"
#include "windows.h"
[emitidl];
[module(name="MyLib")];
[export]
struct stuff {
int i;
};
int main() {
LPOLESTR lpolestr;
StringFromCLSID(__uuidof(MyLib), &lpolestr);
wprintf_s(L"%s", lpolestr);
CoTaskMemFree(lpolestr);
}
Comments
In cases where the library name is no longer in scope, you can use __LIBID_ instead of
__uuidof . For example:
C++
StringFromCLSID(__LIBID_, &lpolestr);
See also
Expressions with Unary Operators
Keywords
Additive Operators: + and -
Article • 08/03/2021 • 2 minutes to read
Syntax
expression + expression
expression - expression
Remarks
The additive operators are:
Addition (+)
Subtraction (-)
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.
Type Meaning
arithmetic Integral and floating types are collectively called "arithmetic" types.
integral Types char and int of all sizes (long, short) and enumerations are "integral" types.
scalar + integral
integral + scalar
arithmetic - arithmetic
scalar - scalar
Example
C++
// expre_Additive_Operators.cpp
// compile with: /EHsc
#include <iostream>
#define SIZE 5
using namespace std;
int main() {
int i = 5, j = 10;
int n[SIZE] = { 0, 1, 2, 3, 4 };
cout << "5 + 10 = " << i + j << endl
<< "5 - 10 = " << i - j << endl;
Pointer addition
If one of the operands in an addition operation is a pointer to an array of objects, the
other must be of integral type. The result is a pointer that is of the same type as the
original pointer and that points to another array element. The following code fragment
illustrates this concept:
C++
Although the integral value 1 is added to pIntArray , it does not mean "add 1 to the
address"; rather it means "adjust the pointer to point to the next object in the array" that
happens to be 2 bytes (or sizeof( int ) ) away.
7 Note
Pointer subtraction
If both operands are pointers, the result of subtraction is the difference (in array
elements) between the operands. The subtraction expression yields a signed integral
result of type ptrdiff_t (defined in the standard include file <stddef.h>).
One of the operands can be of integral type, as long as it is the second operand. The
result of the subtraction is of the same type as the original pointer. The value of the
subtraction is a pointer to the (n - i)th array element, where n is the element pointed to
by the original pointer and i is the integral value of the second operand.
See also
Expressions with Binary Operators
C++ Built-in Operators, Precedence and Associativity
C Additive Operators
Address-of operator: &
Article • 01/05/2022 • 2 minutes to read
Syntax
address-of-expression :
& cast-expression
Remarks
The unary address-of operator ( & ) returns the address of (that is, a pointer to) its
operand. The operand of the address-of operator can be a function designator or an
lvalue that refers to an object that's not a bit field.
The address-of operator can only be applied to certain lvalue expressions: either to
variables of fundamental, structure, class, or union types, or to subscripted array
references. In these expressions, a constant expression (one that doesn't include the
address-of operator) can be added to or subtracted from the address-of expression.
When applied to functions or lvalues, the result of the expression is a pointer type (an
rvalue) derived from the type of the operand. For example, if the operand is of type
char , the result of the expression is of type pointer to char . The address-of operator,
applied to const or volatile objects, evaluates to const type * or volatile type * ,
where type is the type of the original object.
You can only take the address of an overloaded function when it's clear which version of
the function is referenced. For more information about how to obtain the address of a
particular overloaded function, see Function overloading.
When the address-of operator is applied to a qualified name, the result depends on
whether the qualified-name specifies a static member. If so, the result is a pointer to the
type specified in the declaration of the member. For a member that isn't static, the result
is a pointer to the member name of the class indicated by qualified-class-name. For
more information about qualified-class-name, see Primary expressions.
// 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.
C++
// expre_Address_Of_Operator2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main() {
double d; // Define an object of type double.
double& rd = d; // Define a reference to the object.
Output
C++
// 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
}
Output
25
See also
Expressions with unary operators
C++ built-in operators, precedence, and associativity
Lvalue reference declarator: &
Indirection and address-of operators
Assignment operators
Article • 01/25/2023 • 5 minutes to read
Syntax
expression assignment-operator expression
assignment-operator : one of
= *= /= %= += -= <<= >>= &= ^= |=
Remarks
Assignment operators store a value in the object specified by the left operand. There are
two kinds of assignment operations:
simple assignment, in which the value of the second operand is stored in the object
specified by the first operand.
All assignment operators in the following table except the = operator are compound
assignment operators.
Operator Meaning
= Store the value of the second operand in the object specified by the first operand
(simple assignment).
*= Multiply the value of the first operand by the value of the second operand; store the
result in the object specified by the first operand.
/= Divide the value of the first operand by the value of the second operand; store the
result in the object specified by the first operand.
%= Take modulus of the first operand specified by the value of the second operand; store
the result in the object specified by the first operand.
+= Add the value of the second operand to the value of the first operand; store the result
in the object specified by the first operand.
Operator Meaning
-= Subtract the value of the second operand from the value of the first operand; store
the result in the object specified by the first operand.
<<= Shift the value of the first operand left the number of bits specified by the value of
the second operand; store the result in the object specified by the first operand.
>>= Shift the value of the first operand right the number of bits specified by the value of
the second operand; store the result in the object specified by the first operand.
&= Obtain the bitwise AND of the first and second operands; store the result in the
object specified by the first operand.
^= Obtain the bitwise exclusive OR of the first and second operands; store the result in
the object specified by the first operand.
|= Obtain the bitwise inclusive OR of the first and second operands; store the result in
the object specified by the first operand.
Operator keywords
Three of the compound assignment operators have keyword equivalents. They are:
Operator Equivalent
&= and_eq
|= or_eq
^= xor_eq
C++ specifies these operator keywords as alternative spellings for the compound
assignment operators. In C, the alternative spellings are provided as macros in the
<iso646.h> header. In C++, the alternative spellings are keywords; use of <iso646.h> or
the C++ equivalent <ciso646> is deprecated. In Microsoft C++, the /permissive- or /Za
compiler option is required to enable the alternative spelling.
Example
C++
// expre_Assignment_Operators.cpp
// compile with: /EHsc
// Demonstrate assignment operators
#include <iostream>
using namespace std;
int main() {
int a = 3, b = 6, c = 10, d = 0xAAAA, e = 0x5555;
a += b; // a is 9
b %= a; // b is 6
c >>= 1; // c is 5
d |= e; // Bitwise--d is 0xFFFF
Simple assignment
The simple assignment operator ( = ) causes the value of the second operand to be
stored in the object specified by the first operand. If both objects are of arithmetic types,
the right operand is converted to the type of the left, before storing the value.
Objects of const and volatile types can be assigned to l-values of types that are only
volatile , or that aren't const or volatile .
Assignment to objects of class type ( struct , union , and class types) is performed by a
function named operator= . The default behavior of this operator function is to perform
a bitwise copy; however, this behavior can be modified using overloaded operators. For
more information, see Operator overloading. Class types can also have copy assignment
and move assignment operators. For more information, see Copy constructors and copy
assignment operators and Move constructors and move assignment operators.
An object of any unambiguously derived class from a given base class can be assigned
to an object of the base class. The reverse isn't true because there's an implicit
conversion from derived class to base class, but not from base class to derived class. For
example:
C++
// expre_SimpleAssignment.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class ABase
{
public:
ABase() { cout << "constructing ABase\n"; }
};
class ADerived : public ABase
{
public:
ADerived() { cout << "constructing ADerived\n"; }
};
int main()
{
ABase aBase;
ADerived aDerived;
aBase = aDerived; // OK
aDerived = aBase; // C2679
}
Assignments to reference types behave as if the assignment were being made to the
object to which the reference points.
C++
UserType1 A;
UserType2 B = A;
The preceding code shows an initializer; it calls the constructor for UserType2 that takes
an argument of type UserType1 . Given the code
C++
UserType1 A;
UserType2 B;
B = A;
C++
B = A;
Call the function operator= for UserType2 , provided operator= is provided with a
UserType1 argument.
Call the explicit conversion function UserType1::operator UserType2 , if such a
function exists.
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 -
In ANSI C, the result of an assignment expression isn't an l-value. That means the legal
C++ expression (a += b) += c isn't allowed in C.
See also
Expressions with binary operators
C++ built-in operators, precedence, and associativity
C assignment operators
Bitwise AND operator: &
Article • 11/23/2021 • 2 minutes to read
Syntax
and-expression :
equality-expression
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
C++
// expre_Bitwise_AND_Operator.cpp
// compile with: /EHsc
// Demonstrate bitwise AND
#include <iostream>
using namespace std;
int main() {
unsigned short a = 0xCCCC; // pattern 1100 ...
unsigned short b = 0xAAAA; // pattern 1010 ...
cout << hex << ( a & b ) << endl; // prints "8888", pattern 1000 ...
}
See also
C++ built-in operators, precedence, and associativity
C bitwise operators
Bitwise exclusive OR operator: ^
Article • 08/03/2021 • 2 minutes to read
Syntax
expression ^ expression
Remarks
The bitwise exclusive OR operator ( ^ ) compares each bit of its first operand to the
corresponding bit of its second operand. If the bit in one of the operands is 0 and the
bit in the other operand is 1, the corresponding result bit is set to 1. Otherwise, the
corresponding result bit is set to 0.
Both operands to the operator must have integral types. The usual arithmetic
conversions covered in Standard Conversions are applied to the operands.
For more information on the alternate usage of the ^ character in C++/CLI and
C++/CX, see Handle to Object Operator (^) (C++/CLI and C++/CX).
Example
C++
// expre_Bitwise_Exclusive_OR_Operator.cpp
// compile with: /EHsc
// Demonstrate bitwise exclusive OR
#include <iostream>
using namespace std;
int main() {
unsigned short a = 0x5555; // pattern 0101 ...
unsigned short b = 0xFFFF; // pattern 1111 ...
cout << hex << ( a ^ b ) << endl; // prints "aaaa" pattern 1010 ...
}
See also
C++ built-in operators, precedence, and associativity
Bitwise inclusive OR operator: |
Article • 02/17/2022 • 2 minutes to read
Syntax
expression1 | expression2
Remarks
The bitwise inclusive OR operator ( | ) compares each bit of its first operand to the
corresponding bit of its second operand. If either bit is 1, the corresponding result bit is
set to 1. Otherwise, the corresponding result bit is set to 0.
Both operands to the operator must have integral types. The usual arithmetic
conversions covered in Standard Conversions are applied to the operands.
Example
C++
// expre_Bitwise_Inclusive_OR_Operator.cpp
// compile with: /EHsc
// Demonstrate bitwise inclusive OR
#include <iostream>
using namespace std;
int main() {
unsigned short a = 0x5555; // pattern 0101 ...
unsigned short b = 0xAAAA; // pattern 1010 ...
cout << hex << ( a | b ) << endl; // prints "ffff" pattern 1111 ...
}
See also
C++ built-in operators, precedence, and associativity
C bitwise operators
Cast operator: ()
Article • 07/01/2022 • 2 minutes to read
A type cast provides a method for explicit conversion of the type of an object in a
specific situation.
Syntax
cast-expression :
unary-expression
( type-name ) cast-expression
Remarks
Any unary expression is considered a cast expression.
The compiler treats cast-expression as type type-name after a type cast has been made.
Casts can be used to convert objects of any scalar type to or from any other scalar type.
Explicit type casts are constrained by the same rules that determine the effects of
implicit conversions. Other restraints on casts may result from the actual sizes or
representation of specific types.
Examples
A standard cast conversion between built-in types:
C++
// expre_CastOperator.cpp
// compile with: /EHsc
// Demonstrate cast operator
#include <iostream>
int main()
{
double x = 3.1;
int i;
cout << "x = " << x << endl;
i = (int)x; // assign i the integer part of x
cout << "i = " << i << endl;
}
A cast operator defined in a user-defined type:
C++
// expre_CastOperator2.cpp
// The following sample shows how to define and use a cast operator.
#include <string.h>
#include <stdio.h>
class CountedAnsiString
{
public:
// Assume source is not null terminated
CountedAnsiString(const char *pStr, size_t nSize) :
m_nSize(nSize)
{
m_pStr = new char[sizeOfBuffer];
//
// operator to cast to a const char *
//
operator const char *()
{
m_pStr[m_nSize] = '\0';
return(m_pStr);
}
enum
{
sizeOfBuffer = 20
} size;
private:
char *m_pStr;
const size_t m_nSize;
};
int main()
{
const char *kStr = "Excitinggg";
CountedAnsiString myStr(kStr, 8);
const char *pRaw = myStr.GetRawBytes();
printf_s("RawBytes truncated to 10 chars: %.10s\n", pRaw);
Output
See also
Expressions with unary operators
C++ built-in operators, precedence and associativity
Explicit type conversion operator: ()
Casting operators (C++)
Cast operators (C)
Comma Operator: ,
Article • 08/03/2021 • 2 minutes to read
Syntax
expression , expression
Remarks
The comma operator has left-to-right associativity. Two expressions separated by a
comma are evaluated left to right. The left operand is always evaluated, and all side
effects are completed before the right operand is evaluated.
Commas can be used as separators in some contexts, such as function argument lists.
Do not confuse the use of the comma as a separator with its use as an operator; the two
uses are completely different.
Consider the expression e1, e2 . The type and value of the expression are the type and
value of e2; the result of evaluating e1 is discarded. The result is an l-value if the right
operand is an l-value.
Where the comma is normally used as a separator (for example in actual arguments to
functions or aggregate initializers), the comma operator and its operands must be
enclosed in parentheses. For example:
C++
func_one( x, y + 2, z );
func_two( (x--, y + 2), z );
In the function call to func_one above, three arguments, separated by commas, are
passed: x , y + 2 , and z . In the function call to func_two , parentheses force the
compiler to interpret the first comma as the sequential-evaluation operator. This
function call passes two arguments to func_two . The first argument is the result of the
sequential-evaluation operation (x--, y + 2) , which has the value and type of the
expression y + 2 ; the second argument is z .
Example
C++
// cpp_comma_operator.cpp
#include <stdio.h>
int main () {
int i = 10, b = 20, c= 30;
i = b, c;
printf("%i\n", i);
i = (b, c);
printf("%i\n", i);
}
Output
20
30
See also
Expressions with Binary Operators
C++ Built-in Operators, Precedence and Associativity
Sequential-Evaluation Operator
Conditional Operator: ?:
Article • 12/06/2021 • 2 minutes to read
Syntax
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.
If both operands are of the same type, the result is of that 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 type void, the common type is type void.
If both operands are of the same user-defined type, the common type is that type.
If the operands have different types and at least one of the operands has user-
defined type then the language rules are used to determine the common type.
(See warning below.)
Any combinations of second and third operands not in the preceding list are illegal. The
type of the result is the common type, and it is an l-value if both the second and third
operands are of the same type and both are l-values.
2 Warning
If the types of the second and third operands are not identical, then complex type
conversion rules, as specified in the C++ Standard, are invoked. These conversions
may lead to unexpected behavior including construction and destruction of
temporary objects. For this reason, we strongly advise you to either (1) avoid using
user-defined types as operands with the conditional operator or (2) if you do use
user-defined types, then explicitly cast each operand to a common type.
Example
C++
// expre_Expressions_with_the_Conditional_Operator.cpp
// compile with: /EHsc
// Demonstrate conditional operator
#include <iostream>
using namespace std;
int main() {
int i = 1, j = 2;
cout << ( i > j ? i : j ) << " is greater." << endl;
}
See also
C++ Built-in Operators, Precedence and Associativity
Conditional-Expression Operator
delete Operator (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
[ :: ] delete cast-expression
[ :: ] delete [] cast-expression
Remarks
The cast-expression argument must be a pointer to a block of memory previously
allocated for an object created with the new operator. The delete operator has a result
of type void and therefore does not return a value. For example:
C++
Using delete on a pointer to an object not allocated with new gives unpredictable
results. You can, however, use delete on a pointer with the value 0. This provision
means that, when new returns 0 on failure, deleting the result of a failed new operation
is harmless. For more information, see The new and delete Operators.
The new and delete operators can also be used for built-in types, including arrays. If
pointer refers to an array, place empty brackets ( [] ) before pointer :
C++
Using the delete operator on an object deallocates its memory. A program that
dereferences a pointer after the object is deleted can have unpredictable results or
crash.
When delete is used to deallocate memory for a C++ class object, the object's
destructor is called before the object's memory is deallocated (if the object has a
destructor).
If the operand to the delete operator is a modifiable l-value, its value is undefined after
the object is deleted.
If the /sdl (Enable additional security checks) compiler option is specified, the operand
to the delete operator is set to an invalid value after the object is deleted.
Using delete
There are two syntactic variants for the delete operator: one for single objects and the
other for arrays of objects. The following code fragment shows how they differ:
C++
// expre_Using_delete.cpp
struct UDType
{
};
int main()
{
// Allocate a user-defined object, UDObject, and an object
// of type double on the free store using the
// new operator.
UDType *UDObject = new UDType;
double *dObject = new double;
// Delete the two objects.
delete UDObject;
delete dObject;
// Allocate an array of user-defined objects on the
// free store using the new operator.
UDType (*UDArr)[7] = new UDType[5][7];
// Use the array syntax to delete the array of objects.
delete [] UDArr;
}
The following two cases produce undefined results: using the array form of delete
( delete [] ) on an object, and using the nonarray form of delete on an array.
Example
For examples of using delete , see new operator.
How delete works
The delete operator invokes the function operator delete.
For objects not of class type (class, struct, or union), the global delete operator is
invoked. For objects of class type, the name of the deallocation function is resolved in
global scope if the delete expression begins with the unary scope resolution operator
( :: ). Otherwise, the delete operator invokes the destructor for an object prior to
deallocating memory (if the pointer is not null). The delete operator can be defined on a
per-class basis; if there is no such definition for a given class, the global operator delete
is invoked. If the delete expression is used to deallocate a class object whose static type
has a virtual destructor, the deallocation function is resolved through the virtual
destructor of the dynamic type of the object.
See also
Expressions with Unary Operators
Keywords
new and delete Operators
Equality operators: == and !=
Article • 08/03/2021 • 2 minutes to read
Syntax
expression == expression
expression != expression
Remarks
The binary equality operators compare their operands for strict equality or inequality.
The equality operators, equal to ( == ) and not equal to ( != ), have lower precedence than
the relational operators, but they behave similarly. The result type for these operators is
bool .
The equal-to operator ( == ) returns true if both operands have the same value;
otherwise, it returns false . The not-equal-to operator ( != ) returns true if the operands
don't have the same value; otherwise, it returns false .
Example
C++
// 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: ()
Article • 08/03/2021 • 2 minutes to read
C++ allows explicit type conversion using syntax similar to the function-call syntax.
Syntax
simple-type-name ( expression-list )
Remarks
A simple-type-name followed by an expression-list enclosed in parentheses constructs an
object of the specified type using the specified expressions. The following example
shows an explicit type conversion to type int:
C++
int i = int( d );
Example
C++
// expre_Explicit_Type_Conversion_Operator.cpp
// compile with: /EHsc
#include <iostream>
int main()
{
Point Point1, Point2;
Output
Output
x = 20, y = 10
x = 0, y = 0
Although the preceding example demonstrates explicit type conversion using constants,
the same technique works to perform these conversions on objects. The following code
fragment demonstrates this:
C++
int i = 7;
float d;
d = float( i );
Explicit type conversions can also be specified using the "cast" syntax. The previous
example, rewritten using the cast syntax, is:
C++
d = (float)i;
Both cast and function-style conversions have the same results when converting from
single values. However, in the function-style syntax, you can specify more than one
argument for conversion. This difference is important for user-defined types. Consider a
Point class and its conversions:
C++
struct Point
{
Point( short x, short y ) { _x = x; _y = y; }
...
short _x, _y;
};
...
Point pt = Point( 3, 10 );
The preceding example, which uses function-style conversion, shows how to convert two
values (one for x and one for y) to the user-defined type Point .
U Caution
Use the explicit type conversions with care, since they override the C++ compiler's
built-in type checking.
The cast notation must be used for conversions to types that do not have a simple-type-
name (pointer or reference types, for example). Conversion to types that can be
expressed with a simple-type-name can be written in either form.
See also
Postfix Expressions
C++ Built-in Operators, Precedence and Associativity
Function Call Operator: ()
Article • 08/03/2021 • 3 minutes to read
Syntax
postfix-expression :
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.
T func( int i );
C++
T (*func)( int i );
C++
T (&func)(int i);
C++
(pObject->*pmf)();
(Object.*pmf)();
Example
The following example calls the standard library function strcat_s with three
arguments:
C++
// expre_Function_Call_Operator.cpp
// compile with: /EHsc
#include <iostream>
#include <string>
int main()
{
enum
{
sizeOfBuffer = 20
};
Output
Welcome to C++
C++
// expre_Function_Call_Results.cpp
// compile with: /EHsc
#include <iostream>
class Point
{
public:
// Define "accessor" functions as
// reference types.
unsigned& x() { return _x; }
unsigned& y() { return _y; }
private:
unsigned _x;
unsigned _y;
};
Functions that return class types, pointers to class types, or references to class types can
be used as the left operand to member-selection operators. The following code is legal:
C++
// expre_Function_Results2.cpp
class A {
public:
A() {}
A(int i) {}
int SetA( int i ) {
return (I = i);
}
int GetA() {
return I;
}
private:
int I;
};
A func1() {
A a = 0;
return a;
}
A* func2() {
A *a = new A();
return a;
}
A& func3() {
A *a = new A();
A &b = *a;
return b;
}
int main() {
int iResult = func1().GetA();
func2()->SetA( 3 );
func3().SetA( 7 );
}
Functions can be called recursively. For more information about function declarations,
see Functions. Related material is in Translation units and linkage.
See also
Postfix expressions
C++ built-in operators, precedence, and associativity
Function call
Indirection Operator: *
Article • 08/03/2021 • 2 minutes to read
Syntax
* cast-expression
Remarks
The unary indirection operator (*) dereferences a pointer; that is, it converts a pointer
value to an l-value. The operand of the indirection operator must be a pointer to a type.
The result of the indirection expression is the type from which the pointer type is
derived. The use of the * operator in this context is different from its meaning as a
binary operator, which is multiplication.
C++
// expre_Indirection_Operator.cpp
// compile with: /EHsc
// Demonstrate indirection operator
#include <iostream>
using namespace std;
int main() {
int n = 5;
int *pn = &n;
int **ppn = &pn;
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.
See also
Expressions with Unary Operators
C++ Built-in Operators, Precedence and Associativity
Address-of Operator: &
Indirection and Address-of Operators
Left shift and right shift operators ( <<
and >> )
Article • 03/13/2023 • 5 minutes to read
The bitwise shift operators are the right-shift operator ( >> ), which moves the bits of an
integer or enumeration type expression to the right, and the left-shift operator ( << ),
which moves the bits to the left. 1
Syntax
shift-expression :
additive-expression
Remarks
) Important
The following descriptions and examples are valid on Windows for x86 and x64
architectures. The implementation of left-shift and right-shift operators is
significantly different on Windows for ARM devices. For more information, see the
"Shift Operators" section of the Hello ARM blog post.
Left Shifts
The left-shift operator causes the bits in shift-expression to be shifted to the left by
the number of positions specified by additive-expression . The bit positions that have
been vacated by the shift operation are zero-filled. A left shift is a logical shift (the bits
that are shifted off the end are discarded, including the sign bit). For more information
about the kinds of bitwise shifts, see Bitwise shifts .
The following example shows left-shift operations using unsigned numbers. The
example shows what is happening to the bits by representing the value as a bitset. For
more information, see bitset Class.
C++
#include <iostream>
#include <bitset>
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.
C++
#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
C++
#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.
C++
#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.
C++
#include <iostream>
#include <bitset>
int main() {
short neg1 = -16;
bitset<16> bn1(neg1);
cout << bn1 << endl; // 0b11111111'11110000
#include <iostream>
#include <typeinfo>
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.
C++
#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 × 2E2, reduced modulo one more
than the maximum value representable in the result type. Otherwise, if E1 has a signed
type and non-negative value, and E1 × 2E2 is representable in the corresponding
unsigned type of the result type, then that value, converted to the result type, is the
resulting value; otherwise, the behavior is undefined.
See also
Expressions with binary operators
C++ built-in operators, precedence, and associativity
Logical AND operator: &&
Article • 11/23/2021 • 2 minutes to read
Syntax
logical-and-expression :
equality-expression
Remarks
The logical AND operator ( && ) returns true if both operands are true and returns
false otherwise. The operands are implicitly converted to type bool before evaluation,
and the result is of type bool . Logical AND has left-to-right associativity.
The operands to the logical AND operator don't need to have the same type, but they
must have boolean, integral, or pointer type. The operands are commonly relational or
equality expressions.
The first operand is completely evaluated and all side effects are completed before
evaluation of the logical AND expression continues.
The second operand is evaluated only if the first operand evaluates to true (nonzero).
This evaluation eliminates needless evaluation of the second operand when the logical
AND expression is false . You can use this short-circuit evaluation to prevent null-
pointer dereferencing, as shown in the following example:
C++
char *pch = 0;
// ...
(pch) && (*pch = 'a');
If pch is null (0), the right side of the expression is never evaluated. This short-circuit
evaluation makes the assignment through a null pointer impossible.
Example
C++
// 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: !
Article • 08/03/2021 • 2 minutes to read
Syntax
! cast-expression
Remarks
The logical negation operator ( ! ) reverses the meaning of its operand. The operand
must be of arithmetic or pointer type (or an expression that evaluates to arithmetic or
pointer type). The operand is implicitly converted to type bool . The result is true if the
converted operand is false ; the result is false if the converted operand is true . The
result is of type bool .
Example
C++
// expre_Logical_NOT_Operator.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main() {
int i = 0;
if (!i)
cout << "i is zero" << endl;
}
See also
Expressions with unary operators
C++ built-in operators, precedence, and associativity
Unary arithmetic operators
Logical OR operator: ||
Article • 02/17/2022 • 2 minutes to read
Syntax
logical-or-expression || logical-and-expression
Remarks
The logical OR operator ( || ) returns the boolean value true if either or both operands
is true and returns false otherwise. The operands are implicitly converted to type bool
before evaluation, and the result is of type bool . Logical OR has left-to-right
associativity.
The operands to the logical OR operator don't have to have the same type, but they
must be of boolean, integral, or pointer type. The operands are commonly relational or
equality expressions.
The first operand is completely evaluated and all side effects are completed before
continuing evaluation of the logical OR expression.
The second operand is evaluated only if the first operand evaluates to false , because
evaluation isn't needed when the logical OR expression is true . It's known as short-
circuit evaluation.
C++
printf( "%d" , (x == w || x == y || x == z) );
Example
C++
// expre_Logical_OR_Operator.cpp
// compile with: /EHsc
// Demonstrate logical OR
#include <iostream>
using namespace std;
int main() {
int a = 5, b = 10, c = 15;
cout << boolalpha
<< "The true expression "
<< "a < b || b > c yields "
<< (a < b || b > c) << endl
<< "The false expression "
<< "a > b || b > c yields "
<< (a > b || b > c) << endl;
}
See also
C++ built-in operators, precedence, and associativity
C logical operators
Member access operators: . and ->
Article • 12/08/2021 • 2 minutes to read
Syntax
postfix-expression :
postfix-expression . template opt id-expression
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.
postfix-expression is an l-value.
Example
The following example demonstrates both forms of the member access operator.
C++
// expre_Selection_Operator.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
struct Date {
Date(int i, int j, int k) : day(i), month(j), year(k){}
int month;
int day;
int year;
};
int main() {
Date mydate(1,1,1900);
mydate.month = 2;
cout << mydate.month << "/" << mydate.day
<< "/" << mydate.year << endl;
Output
2/1/1900
2/1/2000
See also
Postfix expressions
C++ built-in operators, precedence, and associativity
Classes and Structs
Structure and union members
Multiplicative Operators and the
Modulus Operator
Article • 08/03/2021 • 2 minutes to read
Syntax
expression * expression
expression / expression
expression % expression
Remarks
The multiplicative operators are:
Multiplication (*)
Division (/)
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.
i % 0
f / 0.0
If both operands to a multiplication, division, or modulus expression have the same sign,
the result is positive. Otherwise, the result is negative. The result of a modulus
operation's sign is implementation-defined.
7 Note
Since the conversions performed by the multiplicative operators do not provide for
overflow or underflow conditions, information may be lost if the result of a
multiplicative operation cannot be represented in the type of the operands after
conversion.
Microsoft Specific
In Microsoft C++, the result of a modulus expression is always the same as the sign of
the first operand.
If the computed division of two integers is inexact and only one operand is negative, the
result is the largest integer (in magnitude, disregarding the sign) that is less than the
exact value the division operation would yield. For example, the computed value of -11 /
3 is -3.666666666. The result of that integral division is -3.
The relationship between the multiplicative operators is given by the identity (e1 / e2) *
e2 + e1 % e2 == e1.
Example
The following program demonstrates the multiplicative operators. Note that either
operand of 10 / 3 must be explicitly cast to type float to avoid truncation so that both
operands are of type float before division.
C++
// expre_Multiplicative_Operators.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main() {
int x = 3, y = 6, z = 10;
cout << "3 * 6 is " << x * y << endl
<< "6 / 3 is " << y / x << endl
<< "10 % 3 is " << z % x << endl
<< "10 / 3 is " << (float) z / x << endl;
}
See also
Expressions with Binary Operators
C++ Built-in Operators, Precedence and Associativity
C Multiplicative Operators
new operator (C++)
Article • 01/05/2022 • 8 minutes to read
Syntax
new-expression :
new-placement :
( expression-list )
new-type-id :
new-declarator :
ptr-operator new-declarator opt
noptr-new-declarator
noptr-new-declarator :
new-initializer :
( expression-list opt )
braced-init-list
Remarks
If unsuccessful, new returns zero or throws an exception. For more information, see The
new and delete Operators. You can change this default behavior by writing a custom
exception-handling routine and calling the _set_new_handler run-time library function
with your function name as its argument.
For information on how to create an object on the managed heap in C++/CLI and
C++/CX, see gcnew.
7 Note
Microsoft C++ Component Extensions (C++/CX) provides support for the new
keyword to add vtable slot entries. For more information, see new (new slot in
vtable)
When new is used to allocate memory for a C++ class object, the object's constructor is
called after the memory is allocated.
Use the delete operator to deallocate the memory allocated by the new operator. Use
the delete[] operator to delete an array allocated by the new operator.
The following example allocates and then frees a two-dimensional array of characters of
size dim by 10. When allocating a multidimensional array, all dimensions except the first
must be constant expressions that evaluate to positive values. The leftmost array
dimension can be any expression that evaluates to a positive value. When allocating an
array using the new operator, the first dimension can be zero; the new operator returns a
unique pointer.
C++
C++
The new operator doesn't allocate reference types because they're not objects.
The new operator can't be used to allocate a function, but it can be used to allocate
pointers to functions. The following example allocates and then frees an array of seven
pointers to functions that return integers.
C++
new-placement
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
C++
// expre_new_Operator.cpp
// compile with: /EHsc
#include <string.h>
class CName {
public:
enum {
sizeOfBuffer = 256
};
char m_szFirst[sizeOfBuffer];
char m_szLast[sizeOfBuffer];
public:
void SetName(char* pszFirst, char* pszLast) {
strcpy_s(m_szFirst, sizeOfBuffer, pszFirst);
strcpy_s(m_szLast, sizeOfBuffer, pszLast);
}
};
int main() {
// Allocate memory for the array
char* pCharArray = new char[CName::sizeOfBuffer];
strcpy_s(pCharArray, CName::sizeOfBuffer, "Array of characters");
C++
// expre_new_Operator2.cpp
// C2660 expected
class A {
public:
A(int) { throw "Fail!"; }
};
void F(void) {
try {
// heap memory pointed to by pa1 will be deallocated
// by calling ::operator delete(void*).
A* pa1 = new A(10);
} catch (...) {
}
try {
// This will call ::operator new(size_t, char*, int).
// When A::A(int) does a throw, we should call
// ::operator delete(void*, char*, int) to deallocate
// the memory pointed to by pa2. Since
// ::operator delete(void*, char*, int) has not been implemented,
// memory will be leaked when the deallocation can't occur.
int main() {
A a;
}
C++
// expre_Initializing_Objects_Allocated_with_new.cpp
class Acct
{
public:
// Define default constructor and a constructor that accepts
// an initial balance.
Acct() { balance = 0.0; }
Acct( double init_balance ) { balance = init_balance; }
private:
double balance;
};
int main()
{
Acct *CheckingAcct = new Acct;
Acct *SavingsAcct = new Acct ( 34.98 );
double *HowMuch = new double { 43.0 };
// ...
}
In this example, the object CheckingAcct is allocated using the new operator, but no
default initialization is specified. So, the default constructor for the class, Acct() , is
called. Then the object SavingsAcct is allocated the same way, except that it's explicitly
initialized to 34.98. Because 34.98 is of type double , the constructor that takes an
argument of that type is called to handle the initialization. Finally, the non-class type
HowMuch is initialized to 43.0.
If an object is of a class type and that class has constructors (as in the preceding
example), the object can be initialized by the new operator only if one of these
conditions is met:
The 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.
C++
// expre_Lifetime_of_Objects_Allocated_with_new.cpp
// C2541 expected
int main()
{
// Use new operator to allocate an array of 20 characters.
char *AnArray = new char[20];
Once the pointer AnotherArray goes out of scope in the example, the object can no
longer be deleted.
Locates and reserves storage for the object or objects to be allocated. When this
stage is complete, the correct amount of storage is allocated, but it's not yet an
object.
The new operator invokes the function operator new . For arrays of any type, and for
objects that aren't class , struct , or union types, a global function, ::operator new , is
called to allocate storage. Class-type objects can define their own operator new static
member function on a per-class basis.
When the compiler encounters the new operator to allocate an object of type T , it
issues a call to T::operator new( sizeof(T) ) or, if no user-defined operator new is
defined, ::operator new( sizeof(T) ) . It's how the new operator can allocate the
correct amount of memory for the object.
7 Note
7 Note
Although the preceding example shows only one argument in the new-placement
field, there's no restriction on how many extra arguments can be passed to
operator new this way.
Even when operator new has been defined for a class type T , you can use the global
operator new explicitly, as in this example:
C++
See also
Expressions with unary operators
Keywords
new and delete operators
One's complement operator: ~
Article • 08/03/2021 • 2 minutes to read
Syntax
C++
~ cast-expression
Remarks
The one's complement operator ( ~ ), sometimes called the bitwise complement operator,
yields a bitwise one's complement of its operand. That is, every bit that is 1 in the
operand is 0 in the result. Conversely, every bit that is 0 in the operand is 1 in the result.
The operand to the one's complement operator must be an integral type.
Example
C++
// 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.
See also
Expressions with unary operators
C++ built-in operators, precedence, and associativity
Unary arithmetic operators
Pointer-to-member operators: .* and -
>*
Article • 12/08/2021 • 2 minutes to read
Syntax
pm-expression :
cast-expression
pm-expression .* cast-expression
Remarks
The pointer-to-member operators .* and ->* return the value of a specific class
member for the object specified on the left side of the expression. The right side must
specify a member of the class. The following example shows how to use these operators:
C++
// expre_Expressions_with_Pointer_Member_Operators.cpp
// compile with: /EHsc
#include <iostream>
class Testpm {
public:
void m_func1() { cout << "m_func1\n"; }
int m_num;
};
int main() {
Testpm ATestpm;
Testpm *pTestpm = new Testpm;
Output
Output
m_func1
m_func1
1
2
In the preceding example, a pointer to a member, pmfn , is used to invoke the member
function m_func1 . Another pointer to a member, pmd , is used to access the m_num
member.
The binary operator .* combines its first operand, which must be an object of class
type, with its second operand, which must be a pointer-to-member type.
The binary operator ->* combines its first operand, which must be a pointer to an
object of class type, with its second operand, which must be a pointer-to-member type.
In an expression containing the .* operator, the first operand must be of the class type
of, and be accessible to, the pointer to member specified in the second operand or of an
accessible type unambiguously derived from and accessible to that class.
In an expression containing the ->* operator, the first operand must be of the type
"pointer to the class type" of the type specified in the second operand, or it must be of a
type unambiguously derived from that class.
Example
Consider the following classes and program fragment:
C++
// expre_Expressions_with_Pointer_Member_Operators2.cpp
// C2440 expected
class BaseClass {
public:
BaseClass(); // Base class constructor.
void Func1();
};
int main() {
BaseClass ABase;
Derived ADerived;
7 Note
See also
C++ built-in operators, precedence, and associativity
Postfix Increment and Decrement
Operators: ++ and --
Article • 08/17/2021 • 2 minutes to read
Syntax
postfix-expression ++
postfix-expression --
Remarks
C++ provides prefix and postfix increment and decrement operators; this section
describes only the postfix increment and decrement operators. (For more information,
see Prefix Increment and Decrement Operators.) The difference between the two is that
in the postfix notation, the operator appears after postfix-expression, whereas in the
prefix notation, the operator appears before expression. The following example shows a
postfix-increment operator:
C++
i++;
The effect of applying the postfix increment operator (++) is that the operand's value is
increased by one unit of the appropriate type. Similarly, the effect of applying the
postfix decrement operator (--) is that the operand's value is decreased by one unit of
the appropriate type.
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 .
C++
// expre_Postfix_Increment_and_Decrement_Operators.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main() {
int i = 10;
cout << i++ << endl;
cout << i << endl;
}
C++
See also
Postfix Expressions
C++ Built-in Operators, Precedence and Associativity
C Postfix Increment and Decrement Operators
Prefix Increment and Decrement
Operators: ++ and --
Article • 08/17/2021 • 2 minutes to read
Syntax
++ unary-expression
-- unary-expression
Remarks
The prefix increment operator (++) adds one to its operand; this incremented value is
the result of the expression. The operand must be an l-value not of type const . The
result is an l-value of the same type as the operand.
The prefix decrement operator (--) is analogous to the prefix increment operator, except
that the operand is decremented by one and the result is this decremented value.
Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): The
operand of an increment or decrement operator may not be of type bool .
Both the prefix and postfix increment and decrement operators affect their operands.
The key difference between them is the order in which the increment or decrement
takes place in the evaluation of an expression. (For more information, see Postfix
Increment and Decrement Operators.) In the prefix form, the increment or decrement
takes place before the value is used in expression evaluation, so the value of the
expression is different from the value of the operand. In the postfix form, the increment
or decrement takes place after the value is used in expression evaluation, so the value of
the expression is the same as the value of the operand. For example, the following
program prints " ++i = 6 ":
C++
// expre_Increment_and_Decrement_Operators.cpp
// compile with: /EHsc
#include <iostream>
Because increment and decrement operators have side effects, using expressions with
increment or decrement operators in a preprocessor macro can have undesirable
results. Consider this example:
C++
// expre_Increment_and_Decrement_Operators2.cpp
#define max(a,b) ((a)<(b))?(b):(a)
int main()
{
int i = 0, j = 0, k;
k = max( ++i, j );
}
C++
k = ((++i)<(j))?(j):(++i);
7 Note
C++ inline functions are preferable to macros in many cases because they eliminate
side effects such as those described here, and allow the language to perform more
complete type checking.
See also
Expressions with Unary Operators
C++ Built-in Operators, Precedence and Associativity
Prefix Increment and Decrement Operators
Relational Operators: < , > , <= , and >=
Article • 12/06/2021 • 2 minutes to read
Syntax
Remarks
The binary relational operators determine the following relationships:
Example
C++
// 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:
C++
(cout << "The true expression 3 > 2 yields: " << 3) < (2 << "\n");
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
At least one of the pointers is explicitly converted (cast) to type void * . (The other
pointer is implicitly converted to type void * for the conversion.)
Two pointers of the same type that point to the same object are guaranteed to compare
equal. If two pointers to nonstatic members of an object are compared, the following
rules apply:
If the class type is not a union , and if the two members are not separated by an
access-specifier, such as public , protected , or private , the pointer to the member
declared last will compare greater than the pointer to the member declared earlier.
If the two members are separated by an access-specifier, the results are undefined.
If the class type is a union , pointers to different data members in that union
compare equal.
If two pointers point to elements of the same array or to the element one beyond the
end of the array, the pointer to the object with the higher subscript compares higher.
Comparison of pointers is guaranteed valid only when the pointers refer to objects in
the same array or to the location one past the end of the array.
See also
Expressions with Binary Operators
C++ Built-in Operators, Precedence and Associativity
C Relational and Equality Operators
Scope resolution operator: ::
Article • 10/17/2022 • 2 minutes to read
The scope resolution operator :: is used to identify and disambiguate identifiers used
in different scopes. For more information about scope, see Scope.
Syntax
qualified-id :
nested-name-specifier :
::
type-name ::
namespace-name ::
decltype-specifier ::
nested-name-specifier identifier ::
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.
namespace NamespaceA{
int x;
class ClassA {
public:
int x;
};
}
int main() {
A scope resolution operator without a scope qualifier refers to the global namespace.
C++
namespace NamespaceA{
int x;
}
int x;
int main() {
int x;
// the x in main()
x = 0;
// The x in the global namespace
::x = 1;
You can use the scope resolution operator to identify a member of a namespace , or to
identify a namespace that nominates the member's namespace in a using directive. In
the example below, you can use NamespaceC to qualify ClassB , even though ClassB was
declared in namespace NamespaceB , because NamespaceB was nominated in NamespaceC
by a using directive.
C++
namespace NamespaceB {
class ClassB {
public:
int x;
};
}
namespace NamespaceC{
using namespace NamespaceB;
}
int main() {
NamespaceB::ClassB b_b;
NamespaceC::ClassB c_b;
b_b.x = 3;
c_b.x = 4;
}
You can use chains of scope resolution operators. In the following example,
NamespaceD::NamespaceD1 identifies the nested namespace NamespaceD1 , and
C++
namespace NamespaceD{
namespace NamespaceD1{
int x;
}
}
namespace NamespaceE{
class ClassE{
public:
class ClassE1{
public:
int x;
};
};
}
int main() {
NamespaceD:: NamespaceD1::x = 6;
NamespaceE::ClassE::ClassE1 e1;
e1.x = 7 ;
}
C++
class ClassG {
public:
static int get_x() { return x;}
static int x;
};
int ClassG::x = 6;
int main() {
C++
int main() {
EnumA enum_value = EnumA::First;
}
See also
C++ built-in operators, precedence, and associativity
Namespaces
sizeof Operator
Article • 08/03/2021 • 2 minutes to read
Yields the size of its operand with respect to the size of type char .
7 Note
For information about the sizeof ... operator, see Ellipsis and variadic templates.
Syntax
sizeof unary-expression
sizeof ( type-name )
Remarks
The result of the sizeof operator is of type size_t , an integral type defined in the
include file <stddef.h>. This operator allows you to avoid specifying machine-
dependent data sizes in your programs.
A type name. To use sizeof with a type name, the name must be enclosed in
parentheses.
When the sizeof operator is applied to an object of type char , it yields 1. When the
sizeof operator is applied to an array, it yields the total number of bytes in that array,
not the size of the pointer represented by the array identifier. To obtain the size of the
pointer represented by the array identifier, pass it as a parameter to a function that uses
sizeof . For example:
Example
C++
#include <iostream>
using namespace std;
int main()
{
char szHello[] = "Hello, world!";
Sample Output
Output
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.
Bit fields.
Undefined classes.
External arrays.
Incomplete types.
When the sizeof operator is applied to a reference, the result is the same as if sizeof
had been applied to the object itself.
If an unsized array is the last element of a structure, the sizeof operator returns the size
of the structure without the array.
The sizeof operator is often used to calculate the number of elements in an array using
an expression of the form:
C++
See also
Expressions with Unary Operators
Keywords
Subscript Operator []
Article • 08/03/2021 • 3 minutes to read
Syntax
postfix-expression [ expression ]
Remarks
A postfix expression (which can also be a primary expression) followed by the subscript
operator, [ ], specifies array indexing.
C++
int nArray[5] = { 0, 1, 2, 3, 4 };
cout << nArray[2] << endl; // prints "2"
cout << 2[nArray] << endl; // prints "2"
*((e2) + (e1))
The address yielded by the expression is not e2 bytes from the address e1. Rather, the
address is scaled to yield the next object in the array e2. For example:
C++
double aDbl[2];
The addresses of aDb[0] and aDb[1] are 8 bytes apart — the size of an object of type
double . This scaling according to object type is done automatically by the C++
language and is defined in Additive Operators where addition and subtraction of
operands of pointer type is discussed.
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.
C++
// 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.
See also
Postfix Expressions
C++ Built-in Operators, Precedence and Associativity
Arrays
One-Dimensional Arrays
Multidimensional Arrays
typeid Operator
Article • 08/03/2021 • 2 minutes to read
Syntax
typeid(type-id)
typeid(expression)
Remarks
The typeid operator allows the type of an object to be determined at run time.
The 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
If the expression points to a base class type, yet the object is actually of a type derived
from that base class, a type_info reference for the derived class is the result. The
expression must point to a polymorphic type (a class with virtual functions). Otherwise,
the result is the type_info for the static class referred to in the expression. Further, the
pointer must be dereferenced so that the object used is the one it points to. Without
dereferencing the pointer, the result will be the type_info for the pointer, not what it
points to. For example:
C++
// expre_typeid_Operator.cpp
// compile with: /GR /EHsc
#include <iostream>
#include <typeinfo>
class Base {
public:
virtual void vvfunc() {}
};
If the expression is dereferencing a pointer, and that pointer's value is zero, typeid
throws a bad_typeid exception. If the pointer doesn't point to a valid object, a
__non_rtti_object exception is thrown. It indicates an attempt to analyze the RTTI that
triggered a fault because the object is somehow invalid. (For example, it's a bad pointer,
or the code wasn't compiled with /GR).
If the expression is not a pointer, and not a reference to a base class of the object, the
result is a type_info reference representing the static type of the expression. The static
type of an expression refers to the type of an expression as it is known at compile time.
Execution semantics are ignored when evaluating the static type of an expression.
Furthermore, references are ignored when possible when determining the static type of
an expression:
C++
// expre_typeid_Operator_2.cpp
#include <typeinfo>
int main()
{
typeid(int) == typeid(int&); // evaluates to true
}
typeid can also be used in templates to determine the type of a template parameter:
C++
// expre_typeid_Operator_3.cpp
// compile with: /c
#include <typeinfo>
template < typename T >
T max( T arg1, T arg2 ) {
cout << typeid( T ).name() << "s compared." << endl;
return ( arg1 > arg2 ? arg1 : arg2 );
}
See also
Run-Time Type Information
Keywords
Unary Plus and Negation Operators: +
and -
Article • 08/03/2021 • 2 minutes to read
Syntax
+ cast-expression
- cast-expression
+ operator
The result of the unary plus operator (+) is the value of its operand. The operand to the
unary plus operator must be of an arithmetic type.
Integral promotion is performed on integral operands. The resultant type is the type to
which the operand is promoted. Thus, the expression +ch , where ch is of type char ,
results in type int ; the value is unmodified. See Standard Conversions for more
information about how the promotion is done.
- operator
The unary negation operator (-) produces the negative of its operand. The operand to
the unary negation operator must be an arithmetic type.
Integral promotion is performed on integral operands, and the resultant type is the type
to which the operand is promoted. See Standard Conversions for more information
about how the promotion is performed.
Microsoft Specific
This section describes C++ expressions. Expressions are sequences of operators and
operands that are used for one or more of these purposes:
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
Postfix expressions
Conditional operator
Constant expressions
Casting operators
Overloaded operators
typeid (C++/CLI)
7 Note
Operators for built-in types cannot be overloaded; their behavior is
predefined.
See also
C++ Language Reference
Types of Expressions
Article • 08/03/2021 • 2 minutes to read
Primary expressions. These are the building blocks from which all other expressions
are formed.
Expressions formed with unary operators. Unary operators act on only one
operand in an expression.
Expressions formed with binary operators. Binary operators act on two operands in
an expression.
Expressions with explicit type conversions. Explicit type conversions, or "casts," can
be used in expressions.
See also
Expressions
Primary Expressions
Article • 08/03/2021 • 2 minutes to read
Primary expressions are the building blocks of more complex expressions. They may be
literals, names, and names qualified by the scope-resolution operator ( :: ). A primary
expression may have any of the following forms:
primary-expression
literal
this
name
:: name ( expression )
A literal is a constant primary expression. Its type depends on the form of its
specification. For complete information about specifying literals, see Literals .
The this keyword is a pointer to a class object. It's available within nonstatic member
functions. It points to the instance of the class for which the function was invoked. The
this keyword can't be used outside the body of a class-member function.
The type of the this pointer is type * const (where type is the class name) within
functions that don't specifically modify the this pointer. The following example shows
member function declarations and the types of this :
C++
// expre_Primary_Expressions.cpp
// compile with: /LD
class Example
{
public:
void Func(); // * const this
void Func() const; // const * const this
void Func() volatile; // volatile * const this
};
For more information about modifying the type of the this pointer, see this pointer.
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.
C++
100 // literal
'c' // literal
this // in a member function, a pointer to the class instance
::func // a global function
::operator + // a global operator function
::A::B // a global qualified name
( i + 1 ) // a parenthesized expression
These examples are all considered names, and as such, primary expressions, in various
forms:
C++
MyClass // an identifier
MyClass::f // a qualified name
operator = // an operator function name
operator char* // a conversion operator function name
~MyClass // a destructor name
A::B // a qualified name
A<int> // a template id
See also
Types of Expressions
Ellipsis and variadic templates
Article • 09/28/2022 • 3 minutes to read
This article shows how to use the ellipsis ( ... ) with C++ variadic templates. The ellipsis
has had many uses in C and C++. These include variable argument lists for functions.
The printf() function from the C Runtime Library is one of the most well-known
examples.
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.
C++
For both parameter packs and expansions, you can add whitespace around the ellipsis,
based on your preference, as shown in this example:
C++
Or this example:
C++
This article uses the convention that's shown in the first example (the ellipsis is attached
to typename ).
In the preceding examples, Arguments is a parameter pack. The class classname can
accept a variable number of arguments, as in these examples:
C++
By using a variadic class template definition, you can also require at least one parameter:
C++
C++
The Arguments parameter pack is then expanded for use, as shown in the next section.
Other forms of variadic function template syntax are possible—including, but not limited
to, these examples:
C++
C++
C++
Variadic templates use the sizeof...() operator (unrelated to the older sizeof()
operator):
C++
template<typename... Arguments>
void tfunc(const Arguments&... args)
{
constexpr auto numargs{ sizeof...(Arguments) };
helper_func(xobj, args...);
}
C++
Example
A good way to illustrate the variadic function template mechanism is to use it in a
rewrite of some of the functionality of printf :
C++
#include <iostream>
void print() {
cout << endl;
}
int main()
{
print(); // calls first overload, outputting only a newline
print(1); // calls second overload
Output
Output
1
10, 20
100, 200, 300
first, 2, third, 3.14159
7 Note
Postfix Operators
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 )
C++
func(1)->GetValue()++
The expressions listed above are assignment expressions, meaning that the result of
these expressions must be an r-value.
C++
simple-type-name ( expression-list )
All actual arguments (those supplied by the caller) are evaluated. There is no
implied order in which these arguments are evaluated, but all arguments are
evaluated and all side effects completed prior to entry to the function.
Each formal argument is initialized with its corresponding actual argument in the
expression list. (A formal argument is an argument that is declared in the function
header and used in the body of a function.) Conversions are done as if by
initialization — both standard and user-defined conversions are performed in
converting an actual argument to the correct type. The initialization performed is
illustrated conceptually by the following code:
C++
void Func( int i ); // Function prototype
...
Func( 7 ); // Execute function call
C++
int Temp_i = 7;
Func( Temp_i );
Note that the initialization is performed as if using the equal-sign syntax instead of
the parentheses syntax. A copy of i is made prior to passing the value to the
function. (For more information, see Initializers and Conversions).
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.)
C++
// 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).
C++
// expre_Treatment_of_Argument_Types.cpp
int func1( const int i, int j, char *c ) {
i = 7; // C3892 i is const.
j = i; // value of j is lost at return
*c = 'a' + j; // changes value of c in calling function
return i;
}
Ellipsis denotes that arguments may be required but that the number and types are not
specified in the declaration. This is normally poor C++ programming practice because it
defeats one of the benefits of C++: type safety. Different conversions are applied to
functions declared with ellipsis than to those functions for which the formal and actual
argument types are known:
If the actual argument is of type float , it is promoted to type double prior to the
function call.
Any signed char or unsigned char , signed short or unsigned short , enumerated
type, or bit field is converted to either a signed int or an unsigned int using
integral promotion.
Any argument of class type is passed by value as a data structure; the copy is
created by binary copying instead of by invoking the class's copy constructor (if
one exists).
Ellipsis, if used, must be declared last in the argument list. For more information about
passing a variable number of arguments, see the discussion of va_arg, va_start, and
va_list in the Run-Time Library Reference.
For information on default arguments in CLR programming, see Variable Argument Lists
(...) (C++/CLI).
Default arguments enable you to specify the value an argument should assume if none
is supplied in the function call. The following code fragment shows how default
arguments work. For more information about restrictions on specifying default
arguments, see Default Arguments.
C++
// expre_Ellipsis_and_Default_Arguments.cpp
// compile with: /EHsc
#include <iostream>
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
Output
hello,
world!
good morning, sunshine.
See also
Types of Expressions
Expressions with Unary Operators
Article • 12/01/2021 • 2 minutes to read
Unary operators act on only one operand in an expression. The unary operators are as
follows:
Cast operator ()
sizeof operator
alignof operator
noexcept expression
new operator
delete operator
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 new-expression refers to the new operator. The delete-expression refers to the
delete operator. For more information, see new operator and delete operator.
See also
Types of expressions
Expressions with Binary Operators
Article • 02/17/2022 • 2 minutes to read
Binary operators act on two operands in an expression. The binary operators are:
Multiplicative operators
Multiplication (*)
Division (/)
Modulus (%)
Additive operators
Addition (+)
Subtraction (-)
Shift operators
Equal to (==)
Bitwise operators
Logical operators
Logical AND (&&)
Logical OR (||)
Assignment operators
Assignment (=)
See also
Types of Expressions
C++ Constant Expressions
Article • 08/03/2021 • 2 minutes to read
A constant value is one that doesn't change. C++ provides two keywords to enable you
to express the intent that an object is not intended to be modified, and to enforce that
intent.
Array bounds
Enumeration initializers
Literals
Enumeration constants
sizeof expressions
C++
Explicit conversions to integral types are legal in constant expressions; all other types
and derived types are illegal except when used as operands to the sizeof operator.
The comma operator and assignment operators cannot be used in constant expressions.
See also
Types of Expressions
Semantics of Expressions
Article • 02/17/2022 • 4 minutes to read
Expressions are evaluated according to the precedence and grouping of their operators.
(Operator Precedence and Associativity in Lexical Conventions, shows the relationships
the C++ operators impose on expressions.)
Order of evaluation
Consider this example:
C++
// Order_of_Evaluation.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
int a = 2, b = 4, c = 9;
Output
38
38
54
Expression-evaluation order
The order in which the expression shown in the above figure is evaluated is determined
by the precedence and associativity of the operators:
1. Multiplication (*) has the highest precedence in this expression; hence the
subexpression b * c is evaluated first.
2. Addition (+) has the next highest precedence, so a is added to the product of b
and c .
3. Left shift (<<) has the lowest precedence in the expression, but there are two
occurrences. Because the left-shift operator groups left-to-right, the left
subexpression is evaluated first and then the right one.
When parentheses are used to group the subexpressions, they alter the precedence and
also the order in which the expression is evaluated, as shown in the following figure.
Expressions such as those in the above figure are evaluated purely for their side effects
— in this case, to transfer information to the standard output device.
Notation in expressions
The C++ language specifies certain compatibilities when specifying operands. The
following table shows the types of operands acceptable to operators that require
operands of type type.
type * type *
const type *
volatile type *
volatile const type *
Type expected Types allowed
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.
The C++ language definition does not currently specify sequence points. Microsoft C++
uses the same sequence points as ANSI C for any expression involving C operators and
not involving overloaded operators. When operators are overloaded, the semantics
change from operator sequencing to function-call sequencing. Microsoft C++ uses the
following sequence points:
Left operand of the logical AND operator ( && ). The left operand of the logical AND
operator is completely evaluated and all side effects completed before continuing.
There's no guarantee that the right operand of the logical AND operator will be
evaluated.
Left operand of the logical OR operator ( || ). The left operand of the logical OR
operator is completely evaluated and all side effects completed before continuing.
There's no guarantee that the right operand of the logical OR operator will be
evaluated.
Left operand of the comma operator. The left operand of the comma operator is
completely evaluated and all side effects completed before continuing. Both
operands of the comma operator are always evaluated.
First operand of the conditional operator. The first operand of the conditional
operator is completely evaluated and all side effects completed before continuing.
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
Using run-time type information, it is possible to check whether a pointer actually points
to a complete object and can be safely cast to point to another object in its hierarchy.
The dynamic_cast operator can be used to make these types of casts. It also performs
the run-time check necessary to make the operation safe.
For conversion of nonpolymorphic types, you can use the static_cast operator (this topic
explains the difference between static and dynamic casting conversions, and when it is
appropriate to use each).
Casting operators
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:
Use const_cast and reinterpret_cast as a last resort, since these operators present the
same dangers as old style casts. However, they are still necessary in order to completely
replace old style casts.
See also
Casting
dynamic_cast Operator
Article • 04/04/2023 • 8 minutes to read
Syntax
Remarks
The type-id must be a pointer or a reference to a previously defined class type or a
"pointer to void". The type of expression must be a pointer if type-id is a pointer, or an
l-value if type-id is a reference.
See static_cast for an explanation of the difference between static and dynamic casting
conversions, and when it's appropriate to use each.
There are two breaking changes in the behavior of dynamic_cast in managed code:
pointer to a value type; instead, the cast fails at runtime. The cast returns the 0
pointer value instead of throwing.
example:
C++
// dynamic_cast_1.cpp
// compile with: /c
class B { };
class C : public B { };
class D : public C { };
example:
C++
// dynamic_cast_2.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};
void f() {
A* pa = new A;
B* pb = new B;
void* pv = dynamic_cast<void*>(pa);
// pv now points to an object of type A
pv = dynamic_cast<void*>(pb);
// pv now points to an object of type B
}
If type-id isn't void* , a run-time check is made to see if the object pointed to by
expression can be converted to the type pointed to by type-id .
If the type of expression is a base class of the type of type-id , a run-time check is
made to see if expression actually points to a complete object of the type of type-id . If
this is true, the result is a pointer to a complete object of the type of type-id . For
example:
C++
// dynamic_cast_3.cpp
// compile with: /c /GR
class B {virtual void f();};
class D : public B {virtual void f();};
void f() {
B* pb = new D; // unclear but ok
B* pb2 = new B;
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.
C++
// 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.
In this hierarchy, A is a virtual base class. Given an instance of class E and a pointer to
the A subobject, a dynamic_cast to a pointer to B fails due to ambiguity. You must first
cast back to the complete E object, then work your way back up the hierarchy, in an
unambiguous manner, to reach the correct B object.
Given an object of type E and a pointer to the D subobject, to navigate from the D
subobject to the left-most A subobject, three conversions can be made. You can
perform a dynamic_cast conversion from the D pointer to an E pointer, then a
conversion (either dynamic_cast or an implicit conversion) from E to B , and finally an
implicit conversion from B to A . For example:
C++
// dynamic_cast_5.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};
The dynamic_cast operator can also be used to perform a "cross cast." Using the same
class hierarchy, it's possible to cast a pointer, for example, from the B subobject to the
D subobject, as long as the complete object is of type E .
C++
// dynamic_cast_6.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};
A null pointer value is converted to the null pointer value of the destination type by
dynamic_cast .
When you use dynamic_cast < type-id > ( expression ) , if expression can't be safely
converted to type type-id , the run-time check causes the cast to fail. For example:
C++
// dynamic_cast_7.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};
void f() {
A* pa = new A;
B* pb = dynamic_cast<B*>(pa); // fails at runtime, not safe;
// B not derived from A
}
The value of a failed cast to pointer type is the null pointer. A failed cast to reference
type throws a bad_cast Exception. If expression doesn't point to or reference a valid
object, a __non_rtti_object exception is thrown.
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.
C++
// dynamic_cast_8.cpp
// compile with: /GR /EHsc
#include <stdio.h>
#include <iostream>
struct A {
virtual void test() {
printf_s("in A\n");
}
};
struct B : A {
virtual void test() {
printf_s("in B\n");
}
void test2() {
printf_s("test2 in B\n");
}
};
struct C : B {
virtual void test() {
printf_s("in C\n");
}
void test2() {
printf_s("test2 in C\n");
}
};
void Globaltest(A& a) {
try {
C &c = dynamic_cast<C&>(a);
printf_s("in GlobalTest\n");
}
catch(std::bad_cast) {
printf_s("Can't cast to C\n");
}
}
int main() {
A *pa = new C;
A *pa2 = new B;
pa->test();
B * pb = dynamic_cast<B *>(pa);
if (pb)
pb->test2();
C * pc = dynamic_cast<C *>(pa2);
if (pc)
pc->test2();
C ConStack;
Globaltest(ConStack);
Output
in C
test2 in B
in GlobalTest
Can't cast to C
See also
Casting Operators
Keywords
bad_cast exception
Article • 08/03/2021 • 2 minutes to read
The bad_cast exception is thrown by the dynamic_cast operator as the result of a failed
cast to a reference type.
Syntax
catch (bad_cast)
statement
Remarks
The interface for bad_cast is:
C++
The following code contains an example of a failed dynamic_cast that throws the
bad_cast exception.
C++
// expre_bad_cast_Exception.cpp
// compile with: /EHsc /GR
#include <typeinfo>
#include <iostream>
class Shape {
public:
virtual void virtualfunc() const {}
};
The exception is thrown because the object being cast (a Shape) isn't derived from the
specified cast type (Circle). To avoid the exception, add these declarations to main :
C++
Circle circle_instance;
Circle& ref_circle = circle_instance;
Then reverse the sense of the cast in the try block as follows:
C++
Members
Constructors
Constructor Description
Functions
Function Description
what TBD
Operators
Operator Description
C++
operator=
An assignment operator that assigns one bad_cast object to another.
C++
what
C++
See also
dynamic_cast Operator
Keywords
Modern C++ best practices for exceptions and error handling
static_cast Operator
Article • 08/03/2021 • 4 minutes to read
Converts an expression to the type of type-id, based only on the types that are present in
the expression.
Syntax
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
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 =
C++
// static_cast_Operator.cpp
// compile with: /LD
class B {};
C++
// 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:
C++
// static_cast_Operator_3.cpp
// compile with: /LD /GR
typedef unsigned char BYTE;
void f() {
char ch;
int i = 65;
float f = 2.5;
double dbl;
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.
Syntax
Remarks
A pointer to any object type or a pointer to a data member can be explicitly converted
to a type that is identical except for the const , volatile , and __unaligned qualifiers. For
pointers and references, the result will refer to the original object. For pointers to data
members, the result will refer to the same member as the original (uncast) pointer to
data member. Depending on the type of the referenced object, a write operation
through the resulting pointer, reference, or pointer to data member might produce
undefined behavior.
You cannot use the const_cast operator to directly override a constant variable's
constant status.
The const_cast operator converts a null pointer value to the null pointer value of the
destination type.
Example
C++
// expre_const_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>
int main() {
CCTest X;
X.setNumber( 8 );
X.printNumber();
}
On the line containing the const_cast , the data type of the this pointer is const CCTest
* . The const_cast operator changes the data type of the this pointer to CCTest * ,
allowing the member number to be modified. The cast lasts only for the remainder of the
statement in which it appears.
See also
Casting Operators
Keywords
reinterpret_cast Operator
Article • 08/03/2021 • 2 minutes to read
Allows any pointer to be converted into any other pointer type. Also allows any integral
type to be converted into any pointer type and vice versa.
Syntax
Remarks
Misuse of the reinterpret_cast operator can easily be unsafe. Unless the desired
conversion is inherently low-level, you should use one of the other cast operators.
The reinterpret_cast operator can be used for conversions such as char* to int* , or
One_class* to Unrelated_class* , which are inherently unsafe.
The result of a reinterpret_cast cannot safely be used for anything other than being
cast back to its original type. Other uses are, at best, nonportable.
The reinterpret_cast operator cannot cast away the const , volatile , or __unaligned
attributes. See const_cast Operator for information on removing these attributes.
The reinterpret_cast operator converts a null pointer value to the null pointer value of
the destination type.
C++
#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
Article • 08/03/2021 • 2 minutes to read
Run-time type information (RTTI) is a mechanism that allows the type of an object to be
determined during program execution. RTTI was added to the C++ language because
many vendors of class libraries were implementing this functionality themselves. This
caused incompatibilities between libraries. Thus, it became obvious that support for run-
time type information was needed at the language level.
For the sake of clarity, this discussion of RTTI is almost completely restricted to pointers.
However, the concepts discussed also apply to references.
There are three main C++ language elements to run-time type information:
See also
Casting
bad_typeid exception
Article • 08/03/2021 • 2 minutes to read
The bad_typeid exception is thrown by the typeid operator when the operand for
typeid is a NULL pointer.
Syntax
catch (bad_typeid)
statement
Remarks
The interface for bad_typeid is:
C++
The following example shows the typeid operator throwing a bad_typeid exception.
C++
// expre_bad_typeid.cpp
// compile with: /EHsc /GR
#include <typeinfo>
#include <iostream>
class A{
public:
// object for class needs vtable
// for RTTI
virtual ~A();
};
try {
cout << typeid(*a).name() << endl; // Error condition
}
catch (bad_typeid){
cout << "Object is NULL" << endl;
}
}
Output
Output
Object is NULL
See also
Run-Time Type Information
Keywords
type_info Class
Article • 08/03/2021 • 2 minutes to read
The type_info class describes type information generated within the program by the
compiler. Objects of this class effectively store a pointer to a name for the type. The
type_info class also stores an encoded value suitable for comparing two types for
equality or collating order. The encoding rules and collating sequence for types are
unspecified and may differ between programs.
The <typeinfo> header file must be included in order to use the type_info class. The
interface for the type_info class is:
C++
class type_info {
public:
type_info(const type_info& rhs) = delete; // cannot be copied
virtual ~type_info();
size_t hash_code() const;
_CRTIMP_PURE bool operator==(const type_info& rhs) const;
type_info& operator=(const type_info& rhs) = delete; // cannot be copied
_CRTIMP_PURE bool operator!=(const type_info& rhs) const;
_CRTIMP_PURE int before(const type_info& rhs) const;
size_t hash_code() const noexcept;
_CRTIMP_PURE const char* name() const;
_CRTIMP_PURE const char* raw_name() const;
};
You cannot instantiate objects of the type_info class directly, because the class has only
a private copy constructor. The only way to construct a (temporary) type_info object is
to use the typeid operator. Since the assignment operator is also private, you cannot
copy or assign objects of class type_info.
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.