CPP CPP MSVC 170
CPP CPP MSVC 170
CPP CPP MSVC 170
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.
Type information is generated for polymorphic classes only if the /GR (Enable Run-Time
Type Information) compiler option is specified.
See also
Run-Time Type Information
Statements (C++)
Article • 08/03/2021 • 2 minutes to read
C++ statements are the program elements that control how and in what order objects
are manipulated. This section includes:
Overview
Labeled Statements
Categories of Statements
Selection statements. These statements perform a test; they then execute one
section of code if the test evaluates to true (nonzero). They may execute
another section of code if the test evaluates to false.
See also
C++ Language Reference
Overview of C++ Statements
Article • 08/03/2021 • 2 minutes to read
labeled-statement
expression-statement
compound-statement
selection-statement
iteration-statement
jump-statement
declaration-statement
try-throw-catch
In most cases, the C++ statement syntax is identical to that of ANSI C89. The primary
difference between the two is that in C89, declarations are allowed only at the start of a
block; C++ adds the declaration-statement , which effectively removes this restriction.
This enables you to introduce variables at a point in the program where a precomputed
initialization value can be calculated.
Declaring variables inside blocks also allows you to exercise precise control over the
scope and lifetime of those variables.
break
case
catch
continue
default
do
else
__except
__finally
for
goto
if
__if_exists
__if_not_exists
__leave
return
switch
throw
__try
try
while
See also
Statements
Labeled statements
Article • 10/05/2021 • 2 minutes to read
Labels are used to transfer program control directly to the specified statement.
Syntax
labeled-statement :
identifier : statement
case constant-expression : statement
default : statement
Remarks
There are three types of labeled statements. All use a colon ( : ) to separate some type of
label from the statement. The case and default labels are specific to case statements.
C++
#include <iostream>
using namespace std;
void test_label(int x) {
if (x == 1){
goto label1;
}
goto label2;
label1:
cout << "in label1" << endl;
return;
label2:
cout << "in label2" << endl;
return;
}
int main() {
test_label(1); // in label1
test_label(2); // in label2
}
Labels and the goto statement
The appearance of an identifier label in the source program declares a label. Only a
goto statement can transfer control to an identifier label. The following code
fragment illustrates use of the goto statement and an identifier label:
A label can't appear by itself but must always be attached to a statement. If a label is
needed by itself, place a null statement after the label.
The label has function scope and can't be redeclared within the function. However, the
same name can be used as a label in different functions.
C++
// labels_with_goto.cpp
// compile with: /EHsc
#include <iostream>
int main() {
using namespace std;
goto Test2;
Test2:
cerr << "At Test2 label." << endl;
}
C++
case WM_CLOSE:
KillTimer( hWnd, TIMER1 );
DestroyWindow( hWnd );
if ( hWnd == hWndMain )
PostQuitMessage( 0 ); // Quit the application.
break;
default:
// This choice is taken for all messages not specifically
// covered by a case statement.
return DefWindowProc( hWnd, Message, wParam, lParam );
break;
}
See also
Overview of C++ statements
switch statement (C++)
Expression Statement
Article • 08/03/2021 • 2 minutes to read
Syntax
[expression ] ;
Remarks
All expressions in an expression statement are evaluated and all side effects are
completed before the next statement is executed. The most common expression
statements are assignments and function calls. Since the expression is optional, a
semicolon alone is considered an empty expression statement, referred to as the null
statement.
See also
Overview of C++ Statements
Null Statement
Article • 08/03/2021 • 2 minutes to read
The "null statement" is an expression statement with the expression missing. It is useful
when the syntax of the language calls for a statement but no expression evaluation. It
consists of a semicolon.
The following code fragment shows how to copy one string to another and incorporates
the null statement:
C++
// null_statement.cpp
char *myStrCpy( char *Dest, const char *Source )
{
char *DestStart = Dest;
return DestStart;
}
int main()
{
}
See also
Expression Statement
Compound Statements (Blocks)
Article • 08/03/2021 • 2 minutes to read
Syntax
{ [ statement-list ] }
Remarks
The following example uses a compound statement as the statement part of the if
statement (see The if Statement for details about the syntax):
C++
7 Note
See also
Overview of C++ Statements
Selection Statements (C++)
Article • 08/03/2021 • 2 minutes to read
The C++ selection statements, if and switch, provide a means to conditionally execute
sections of code.
The __if_exists and __if_not_exists statements allow you to conditionally include code
depending on the existence of a symbol.
See the individual topics for the syntax for each statement.
See also
Overview of C++ Statements
if-else statement (C++)
Article • 08/03/2021 • 3 minutes to read
true
a non-null pointer,
any non-zero arithmetic value, or
a class type that defines an unambiguous conversion to an arithmetic, boolean, or
pointer type. (For information about conversions, see Standard Conversions.)
Syntax
init-statement :
expression-statement
simple-declaration
condition :
expression
statement :
expression-statement
compound-statement
expression-statement :
expression opt ;
compound-statement :
{ statement-seq opt }
statement-seq :
statement
statement-seq statement
if-branch :
statement
else-branch :
statement
selection-statement :
if-else statements
In all forms of the if statement, condition , which can have any value except a
structure, is evaluated, including all side effects. Control passes from the if statement
to the next statement in the program unless the executed if-branch or else-branch
contains a break, continue, or goto.
The else clause of an if...else statement is associated with the closest previous if
statement in the same scope that doesn't have a corresponding else statement.
Example
This sample code shows several if statements in use, both with and without else :
C++
// if_else_statement.cpp
#include <iostream>
class C
{
public:
void do_something(){}
};
void init(C){}
bool is_true() { return true; }
int x = 10;
int main()
{
if (is_true())
{
cout << "b is true!\n"; // executed
}
else
{
cout << "b is false!\n";
}
// no else statement
if (x == 10)
{
x = 0;
}
C* c;
init(c);
if (c)
{
c->do_something();
}
else
{
cout << "c is null!\n";
}
}
Example
C++
#include <iostream>
#include <mutex>
#include <map>
#include <string>
#include <algorithm>
map<int, string> m;
mutex mx;
bool shared_flag; // guarded by mx
void unsafe_operation() {}
int main()
{
string s{ "if" };
if (auto keywords = { "if", "for", "while" }; any_of(keywords.begin(),
keywords.end(), [&s](const char* kw) { return s == kw; }))
{
cout << "Error! Token must not be a keyword\n";
}
}
if constexpr statements
Starting in C++17, you can use an if constexpr statement in function templates to
make compile-time branching decisions without having to resort to multiple function
overloads. Microsoft-specific: This form is available starting in Visual Studio 2017
version 15.3, and requires at least the /std:c++17 compiler option.
Example
This example shows how you can write a single function that handles parameter
unpacking. No zero-parameter overload is needed:
C++
// handle r conditionally
if constexpr (sizeof...(r))
{
f(r...);
}
else
{
g(r...);
}
}
See also
Selection Statements
Keywords
switch Statement (C++)
__if_exists Statement
Article • 08/03/2021 • 2 minutes to read
The __if_exists statement tests whether the specified identifier exists. If the identifier
exists, the specified statement block is executed.
Syntax
__if_exists ( identifier ) {
statements
};
Parameters
identifier
The identifier whose existence you want to test.
statements
One or more statements to execute if identifier exists.
Remarks
U Caution
To achieve the most reliable results, use the __if_exists statement under the
following constraints.
Use the __if_exists statement only in the body of a function. Outside of the body
of a function, the __if_exists statement can test only fully defined types.
When you test for overloaded functions, you cannot test for a specific form of the
overload.
The complement to the __if_exists statement is the __if_not_exists statement.
Example
Notice that this example uses templates, which is not advised.
C++
// the__if_exists_statement.cpp
// compile with: /EHsc
#include <iostream>
template<typename T>
class X : public T {
public:
void Dump() {
std::cout << "In X<T>::Dump()" << std::endl;
__if_exists(T::Dump) {
T::Dump();
}
__if_not_exists(T::Dump) {
std::cout << "T::Dump does not exist" << std::endl;
}
}
};
class A {
public:
void Dump() {
std::cout << "In A::Dump()" << std::endl;
}
};
class B {};
class C {
public:
void f(int);
void f(double);
};
int main() {
X<A> x1;
X<B> x2;
x1.Dump();
x2.Dump();
__if_exists(::g_bFlag) {
std::cout << "g_bFlag = " << g_bFlag << std::endl;
}
__if_exists(C::f) {
std::cout << "C::f exists" << std::endl;
}
return 0;
}
Output
Output
In X<T>::Dump()
In A::Dump()
In X<T>::Dump()
T::Dump does not exist
g_bFlag = 1
C::f exists
See also
Selection Statements
Keywords
__if_not_exists Statement
__if_not_exists Statement
Article • 08/03/2021 • 2 minutes to read
The __if_not_exists statement tests whether the specified identifier exists. If the
identifier does not exist, the specified statement block is executed.
Syntax
__if_not_exists ( identifier ) {
statements
};
Parameters
identifier
The identifier whose existence you want to test.
statements
One or more statements to execute if identifier does not exist.
Remarks
U Caution
To achieve the most reliable results, use the __if_not_exists statement under the
following constraints.
Use the __if_not_exists statement only in the body of a function. Outside of the
body of a function, the __if_not_exists statement can test only fully defined
types.
When you test for overloaded functions, you cannot test for a specific form of the
overload.
Example
For an example about how to use __if_not_exists , see __if_exists Statement.
See also
Selection Statements
Keywords
__if_exists Statement
switch statement (C++)
Article • 01/25/2023 • 4 minutes to read
Allows selection among multiple sections of code, depending on the value of an integral
expression.
Syntax
selection-statement :
init-statement :
expression-statement
simple-declaration
condition :
expression
attribute-specifier-seq opt decl-specifier-seq declarator brace-or-equal-
initializer
labeled-statement :
Remarks
A switch statement causes control to transfer to one labeled-statement in its statement
body, depending on the value of condition .
The condition must have an integral type, or be a class type that has an unambiguous
conversion to integral type. Integral promotion takes place as described in Standard
conversions.
The switch statement body consists of a series of case labels and an optional default
label. A labeled-statement is one of these labels and the statements that follow. The
labeled statements aren't syntactic requirements, but the switch statement is
meaningless without them. No two constant-expression values in case statements may
evaluate to the same value. The default label may appear only once. The default
statement is often placed at the end, but it can appear anywhere in the switch
statement body. A case or default label can only appear inside a switch statement.
The constant-expression in each case label is converted to a constant value that's the
same type as condition . Then, it's compared with condition for equality. Control passes
to the first statement after the case constant-expression value that matches the value
of condition . The resulting behavior is shown in the following table.
Condition Action
Converted value matches that of the promoted Control is transferred to the statement
controlling expression. following that label.
None of the constants match the constants in the case Control is transferred to the default
labels; a default label is present. label.
None of the constants match the constants in the case Control is transferred to the statement
labels; no default label is present. after the switch statement.
If a matching expression is found, execution can continue through later case or default
labels. The break statement is used to stop execution and transfer control to the
statement after the switch statement. Without a break statement, every statement from
the matched case label to the end of the switch , including the default , is executed.
For example:
C++
// switch_statement1.cpp
#include <stdio.h>
int main() {
const char *buffer = "Any character stream";
int uppercase_A, lowercase_a, other;
char c;
uppercase_A = lowercase_a = other = 0;
Visual Studio 2017 and later (available in /std:c++17 mode and later): The
[[fallthrough]] attribute is specified in the C++17 standard. You can use it in a switch
statement. It's a hint to the compiler, or anyone who reads the code, that fall-through
behavior is intentional. The Microsoft C++ compiler currently doesn't warn on
fallthrough behavior, so this attribute has no effect on compiler behavior. In the
example, the attribute gets applied to an empty statement within the unterminated
labeled statement. In other words, the semicolon is necessary.
C++
int main()
{
int n = 5;
switch (n)
{
case 1:
a();
break;
case 2:
b();
d();
[[fallthrough]]; // I meant to do this!
case 3:
c();
break;
default:
d();
break;
}
return 0;
}
Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): A
switch statement may have an init-statement clause, which ends with a semicolon. It
introduces and initializes a variable whose scope is limited to the block of the switch
statement:
C++
An inner block of a switch statement can contain definitions with initializers as long as
they're reachable, that is, not bypassed by all possible execution paths. Names
introduced using these declarations have local scope. For example:
C++
// switch_statement2.cpp
// C2360 expected
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
switch( tolower( *argv[1] ) )
{
// Error. Unreachable declaration.
char szChEntered[] = "Character entered was: ";
case 'a' :
{
// Declaration of szChEntered OK. Local scope.
char szChEntered[] = "Character entered was: ";
cout << szChEntered << "a\n";
}
break;
case 'b' :
// Value of szChEntered undefined.
cout << szChEntered << "b\n";
break;
default:
// Value of szChEntered undefined.
cout << szChEntered << "neither a nor b\n";
break;
}
}
A switch statement can be nested. When nested, the case or default labels associate
with the closest switch statement that encloses them.
Microsoft-specific behavior
Microsoft C++ doesn't limit the number of case values in a switch statement. The
number is limited only by the available memory.
See also
Selection Statements
Keywords
Iteration Statements (C++)
Article • 08/03/2021 • 2 minutes to read
C++ provides four iteration statements — while, do, for, and range-based for. Each of
these iterates until its termination expression evaluates to zero (false), or until loop
termination is forced with a break statement. The following table summarizes these
statements and their actions; each is discussed in detail in the sections that follow.
Iteration Statements
do Bottom of loop No No
See also
Overview of C++ Statements
while Statement (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
while ( expression )
statement
Remarks
The test of expression takes place before each execution of the loop; therefore, a while
loop executes zero or more times. expression must be of an integral type, a pointer type,
or a class type with an unambiguous conversion to an integral or pointer type.
A while loop can also terminate when a break, goto, or return within the statement
body is executed. Use continue to terminate the current iteration without exiting the
while loop. continue passes control to the next iteration of the while loop.
The following code uses a while loop to trim trailing underscores from a string:
C++
// while_statement.cpp
#include <string.h>
#include <stdio.h>
char *trim( char *szSource )
{
char *pszEOS = 0;
return szSource;
}
int main()
{
char szbuf[] = "12345_____";
The termination condition is evaluated at the top of the loop. If there are no trailing
underscores, the loop never executes.
See also
Iteration Statements
Keywords
do-while Statement (C++)
for Statement (C++)
Range-based for Statement (C++)
do-while Statement (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
do
statement
while ( expression ) ;
Remarks
The test of the termination condition is made after each execution of the loop;
therefore, a do-while loop executes one or more times, depending on the value of the
termination expression. The do-while statement can also terminate when a break, goto,
or return statement is executed within the statement body.
The expression must have arithmetic or pointer type. Execution proceeds as follows:
Example
The following sample demonstrates the do-while statement:
C++
// do_while_statement.cpp
#include <stdio.h>
int main()
{
int i = 0;
do
{
printf_s("\n%d",i++);
} while (i < 3);
}
See also
Iteration Statements
Keywords
while Statement (C++)
for Statement (C++)
Range-based for Statement (C++)
for statement (C++)
Article • 04/22/2022 • 3 minutes to read
Executes a statement repeatedly until the condition becomes false. For information on
the range-based for statement, see Range-based for statement (C++). For information
on the C++/CLI for each statement, see for each, in.
Syntax
for ( init-expression ; cond-expression ; loop-expression )
statement
Remarks
Use the for statement to construct loops that must execute a specified number of
times.
The for statement consists of three optional parts, as shown in the following table.
init- Before any other element of the for Often used to initialize loop indices. It can
expression statement, init-expression is contain expressions or declarations.
executed only once. Control then
passes to cond-expression .
loop- At the end of each iteration of Normally used to increment loop indices.
expression statement . After loop-expression is
executed, cond-expression is
evaluated.
The following examples show different ways to use the for statement.
C++
#include <iostream>
using namespace std;
int main() {
// The counter variable can be declared in the init-expression.
for (int i = 0; i < 2; i++ ){
cout << i;
}
// Output: 01
// The counter variable can be declared outside the for loop.
int i;
for (i = 0; i < 2; i++){
cout << i;
}
// Output: 01
// These for loops are the equivalent of a while loop.
i = 0;
while (i < 2){
cout << i++;
}
// Output: 01
}
C++
#include <iostream>
using namespace std;
int main(){
int i, j;
for ( i = 5, j = 10 ; i + j < 20; i++, j++ ) {
cout << "i + j = " << (i + j) << '\n';
}
}
/* Output:
i + j = 15
i + j = 17
i + j = 19
*/
C++
#include <iostream>
using namespace std;
int main(){
for (int i = 10; i > 0; i--) {
cout << i << ' ';
}
// Output: 10 9 8 7 6 5 4 3 2 1
for (int i = 10; i < 20; i = i+2) {
cout << i << ' ';
}
}
// Output: 10 12 14 16 18
A for loop terminates when a break, return, or goto (to a labeled statement outside the
for loop) within statement is executed. A continue statement in a for loop terminates
If cond-expression is omitted, it's considered true , and the for loop won't terminate
without a break , return , or goto within statement .
Although the three fields of the for statement are normally used for initialization,
testing for termination, and incrementing, they're not restricted to these uses. For
example, the following code prints the numbers 0 through 4. In this case, statement is
the null statement:
C++
#include <iostream>
using namespace std;
int main()
{
int i;
for( i = 0; i < 5; cout << i << '\n', i++){
;
}
}
C++
By default, under /Ze, a variable declared in a for loop remains in scope until the for
loop's enclosing scope ends.
It's also possible to use the scoping differences of the for loop to redeclare variables
under /Ze as follows:
C++
// for_statement5.cpp
int main(){
int i = 0; // hidden by var with same name declared in for loop
for ( int i = 0 ; i < 3; i++ ) {}
This behavior more closely mimics the standard behavior of a variable declared in a for
loop, which requires variables declared in a for loop to go out of scope after the loop is
done. When a variable is declared in a for loop, the compiler internally promotes it to a
local variable in the for loop's enclosing scope. It's promoted even if there's already a
local variable with the same name.
See also
Iteration statements
Keywords
while statement (C++)
do-while statement (C++)
Range-based for statement (C++)
Range-based for Statement (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
for ( for-range-declaration : expression )
statement
Remarks
Use the range-based for statement to construct loops that must execute through a
range, which is defined as anything that you can iterate through—for example,
std::vector , or any other C++ Standard Library sequence whose range is defined by a
begin() and end() . The name that is declared in the for-range-declaration portion is
local to the for statement and cannot be re-declared in expression or statement . Note
that the auto keyword is preferred in the for-range-declaration portion of the
statement.
New in Visual Studio 2017: Range-based for loops no longer require that begin() and
end() return objects of the same type. This enables end() to return a sentinel object
such as used by ranges as defined in the Ranges-V3 proposal. For more information, see
Generalizing the Range-Based For Loop and the range-v3 library on GitHub .
This code shows how to use range-based for loops to iterate through an array and a
vector:
C++
// range-based-for.cpp
// compile by using: cl /EHsc /nologo /W4
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// Basic 10-element integer array.
int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Output
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
end of integer array test
0.14159 1.14159 2.14159 3.14159 4.14159 5.14159 6.14159 7.14159 8.14159
9.14159
end of vector test
See also
auto
Iteration Statements
Keywords
while Statement (C++)
do-while Statement (C++)
for Statement (C++)
Jump Statements (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
break;
continue;
return [expression];
goto identifier;
Remarks
See the following topics for a description of the C++ jump statements.
break Statement
continue Statement
return Statement
goto Statement
See also
Overview of C++ Statements
break Statement (C++)
Article • 08/03/2021 • 2 minutes to read
The break statement ends execution of the nearest enclosing loop or conditional
statement in which it appears. Control passes to the statement that follows the end of
the statement, if any.
Syntax
break;
Remarks
The break statement is used with the conditional switch statement and with the do, for,
and while loop statements.
In a switch statement, the break statement causes the program to execute the next
statement outside the switch statement. Without a break statement, every statement
from the matched case label to the end of the switch statement, including the default
clause, is executed.
In loops, the break statement ends execution of the nearest enclosing do , for , or
while statement. Control passes to the statement that follows the ended statement, if
any.
Within nested statements, the break statement ends only the do , for , switch , or while
statement that immediately encloses it. You can use a return or goto statement to
transfer control from more deeply nested structures.
Example
The following code shows how to use the break statement in a for loop.
C++
#include <iostream>
using namespace std;
int main()
{
// An example of a standard for loop
for (int i = 1; i < 10; i++)
{
if (i == 4) {
break;
}
cout << i << '\n';
}
Output
In each case:
1
2
3
The following code shows how to use break in a while loop and a do loop.
C++
#include <iostream>
using namespace std;
int main() {
int i = 0;
i = 0;
do {
if (i == 4) {
break;
}
cout << i << '\n';
i++;
} while (i < 10);
}
Output
In each case:
0123
The following code shows how to use break in a switch statement. You must use break
in every case if you want to handle each case separately; if you do not use break , the
code execution falls through to the next case.
C++
#include <iostream>
using namespace std;
int main() {
Suit hand;
. . .
// Assume that some enum value is set for hand
// In this example, each case is handled separately
switch (hand)
{
case Diamonds:
cout << "got Diamonds \n";
break;
case Hearts:
cout << "got Hearts \n";
break;
case Clubs:
cout << "got Clubs \n";
break;
case Spades:
cout << "got Spades \n";
break;
default:
cout << "didn't get card \n";
}
// In this example, Diamonds and Hearts are handled one way, and
// Clubs, Spades, and the default value are handled another way
switch (hand)
{
case Diamonds:
case Hearts:
cout << "got a red card \n";
break;
case Clubs:
case Spades:
default:
cout << "didn't get a red card \n";
}
}
See also
Jump Statements
Keywords
continue Statement
continue Statement (C++)
Article • 08/03/2021 • 2 minutes to read
Forces transfer of control to the controlling expression of the smallest enclosing do, for,
or while loop.
Syntax
continue;
Remarks
Any remaining statements in the current iteration are not executed. The next iteration of
the loop is determined as follows:
The following example shows how the continue statement can be used to bypass
sections of code and begin the next iteration of a loop.
Example
C++
// continue_statement.cpp
#include <stdio.h>
int main()
{
int i = 0;
do
{
i++;
printf_s("before the continue\n");
continue;
printf("after the continue, should never print\n");
} while (i < 3);
Output
See also
Jump Statements
Keywords
return Statement (C++)
Article • 08/03/2021 • 2 minutes to read
Terminates the execution of a function and returns control to the calling function (or to
the operating system if you transfer control from the main function). Execution resumes
in the calling function at the point immediately following the call.
Syntax
return [expression];
Remarks
The expression clause, if present, is converted to the type specified in the function
declaration, as if an initialization were being performed. Conversion from the type of the
expression to the return type of the function can create temporary objects. For more
information about how and when temporaries are created, see Temporary Objects.
The value of the expression clause is returned to the calling function. If the expression is
omitted, the return value of the function is undefined. Constructors and destructors, and
functions of type void ,cannot specify an expression in the return statement. Functions
of all other types must specify an expression in the return statement.
When the flow of control exits the block enclosing the function definition, the result is
the same as it would be if a return statement without an expression had been executed.
This is invalid for functions that are declared as returning a value.
The following example uses an expression with a return statement to obtain the largest
of two integers.
Example
C++
// return_statement2.cpp
#include <stdio.h>
int max ( int a, int b )
{
return ( a > b ? a : b );
}
int main()
{
int nOne = 5;
int nTwo = 7;
See also
Jump Statements
Keywords
goto Statement (C++)
Article • 08/03/2021 • 2 minutes to read
The goto statement unconditionally transfers control to the statement labeled by the
specified identifier.
Syntax
goto identifier;
Remarks
The labeled statement designated by identifier must be in the current function. All
identifier names are members of an internal namespace and therefore do not
A goto statement is not allowed to transfer control to a location that skips over the
initialization of any variable that is in scope in that location. The following example
raises C2362:
C++
int goto_fn(bool b)
{
if (!b)
{
goto exit; // C2362
}
else
{ /*...*/ }
exit:
return error_code;
}
It is good programming style to use the break , continue , and return statements
instead of the goto statement whenever possible. However, because the break
statement exits from only one level of a loop, you might have to use a goto statement
to exit a deeply nested loop.
For more information about labels and the goto statement, see Labeled Statements.
Example
In this example, a goto statement transfers control to the point labeled stop when i
equals 3.
C++
// goto_statement.cpp
#include <stdio.h>
int main()
{
int i, j;
stop:
printf_s( "Jumped to stop. i = %d\n", i );
}
Output
See also
Jump Statements
Keywords
Transfers of Control
Article • 08/03/2021 • 2 minutes to read
You can use the goto statement or a case label in a switch statement to specify a
program that branches past an initializer. Such code is illegal unless the declaration that
contains the initializer is in a block enclosed by the block in which the jump statement
occurs.
The following example shows a loop that declares and initializes the objects total , ch ,
and i . There is also an erroneous goto statement that transfers control past an
initializer.
C++
// transfers_of_control.cpp
// compile with: /W1
// Read input until a nonnumeric character is entered.
int main()
{
char MyArray[5] = {'2','2','a','c'};
int i = 0;
while( 1 )
{
int total = 0;
char ch = MyArray[i++];
int i = ch - '0';
Label1:
total += i; // C4700: transfers past initialization of i.
} // i would be destroyed here if goto error were not present
else
// Break statement transfers control out of loop,
// destroying total and ch.
break;
}
}
In the preceding example, the goto statement tries to transfer control past the
initialization of i . However, if i were declared but not initialized, the transfer would be
legal.
The objects total and ch , declared in the block that serves as the statement of the
while statement, are destroyed when that block is exited using the break statement.
Namespaces (C++)
Article • 08/03/2021 • 7 minutes to read
A namespace is a declarative region that provides a scope to the identifiers (the names
of types, functions, variables, etc) inside it. Namespaces are used to organize code into
logical groups and to prevent name collisions that can occur especially when your code
base includes multiple libraries. All identifiers at namespace scope are visible to one
another without qualification. Identifiers outside the namespace can access the
members by using the fully qualified name for each identifier, for example
std::vector<std::string> vec; , or else by a using Declaration for a single identifier
( using std::string ), or a using Directive for all the identifiers in the namespace ( using
namespace std; ). Code in header files should always use the fully qualified namespace
name.
The following example shows a namespace declaration and three ways that code
outside the namespace can accesses their members.
C++
namespace ContosoData
{
class ObjectManager
{
public:
void DoSomething() {}
};
void Func(ObjectManager) {}
}
C++
ContosoData::ObjectManager mgr;
mgr.DoSomething();
ContosoData::Func(mgr);
C++
using ContosoData::ObjectManager;
ObjectManager mgr;
mgr.DoSomething();
Use a using directive to bring everything in the namespace into scope:
C++
ObjectManager mgr;
mgr.DoSomething();
Func(mgr);
using directives
The using directive allows all the names in a namespace to be used without the
namespace-name as an explicit qualifier. Use a using directive in an implementation file
(i.e. *.cpp) if you are using several different identifiers in a namespace; if you are just
using one or two identifiers, then consider a using declaration to only bring those
identifiers into scope and not all the identifiers in the namespace. If a local variable has
the same name as a namespace variable, the namespace variable is hidden. It is an error
to have a namespace variable with the same name as a global variable.
7 Note
A using directive can be placed at the top of a .cpp file (at file scope), or inside a
class or function definition.
In general, avoid putting using directives in header files (*.h) because any file that
includes that header will bring everything in the namespace into scope, which can
cause name hiding and name collision problems that are very difficult to debug.
Always use fully qualified names in a header file. If those names get too long, you
can use a namespace alias to shorten them. (See below.)
C++
//contosoData.h
#pragma once
namespace ContosoDataServer
{
void Foo();
int Bar();
}
Function implementations in contosodata.cpp should use the fully qualified name, even
if you place a using directive at the top of the file:
C++
#include "contosodata.h"
using namespace ContosoDataServer;
A namespace can be declared in multiple blocks in a single file, and in multiple files. The
compiler joins the parts together during preprocessing and the resulting namespace
contains all the members declared in all the parts. An example of this is the std
namespace which is declared in each of the header files in the standard library.
Members of a named namespace can be defined outside the namespace in which they
are declared by explicit qualification of the name being defined. However, the definition
must appear after the point of declaration in a namespace that encloses the
declaration's namespace. For example:
C++
// defining_namespace_members.cpp
// C2039 expected
namespace V {
void f();
}
void V::f() { } // ok
void V::g() { } // C2039, g() is not yet a member of V
namespace V {
void g();
}
This error can occur when namespace members are declared across multiple header
files, and you have not included those headers in the correct order.
Nested namespaces
Namespaces may be nested. An ordinary nested namespace has unqualified access to its
parent's members, but the parent members do not have unqualified access to the
nested namespace (unless it is declared as inline), as shown in the following example:
C++
namespace ContosoDataServer
{
void Foo();
namespace Details
{
int CountImpl;
void Ban() { return Foo(); }
}
int Bar(){...};
int Baz(int i) { return Details::CountImpl; }
}
C++
//Header.h
#include <string>
namespace Test
{
namespace old_ns
{
std::string Func() { return std::string("Hello from old"); }
}
#include "header.h"
#include <string>
#include <iostream>
int main()
{
using namespace Test;
using namespace std;
string s = Func();
std::cout << s << std::endl; // "Hello from new"
return 0;
}
The following example shows how you can declare a specialization in a parent of a
template that is declared in an inline namespace:
C++
namespace Parent
{
inline namespace new_ns
{
template <typename T>
struct C
{
T member;
};
}
template<>
class C<int> {};
}
You can use inline namespaces as a versioning mechanism to manage changes to the
public interface of a library. For example, you can create a single parent namespace, and
encapsulate each version of the interface in its own namespace nested inside the parent.
The namespace that holds the most recent or preferred version is qualified as inline, and
is therefore exposed as if it were a direct member of the parent namespace. Client code
that invokes the Parent::Class will automatically bind to the new code. Clients that prefer
to use the older version can still access it by using the fully qualified path to the nested
namespace that has that code.
The inline keyword must be applied to the first declaration of the namespace in a
compilation unit.
The following example shows two versions of an interface, each in a nested namespace.
The v_20 namespace has some modification from the v_10 interface and is marked as
inline. Client code that uses the new library and calls Contoso::Funcs::Add will invoke
the v_20 version. Code that attempts to call Contoso::Funcs::Divide will now get a
compile time error. If they really need that function, they can still access the v_10
version by explicitly calling Contoso::v_10::Funcs::Divide .
C++
namespace Contoso
{
namespace v_10
{
template <typename T>
class Funcs
{
public:
Funcs(void);
T Add(T a, T b);
T Subtract(T a, T b);
T Multiply(T a, T b);
T Divide(T a, T b);
};
}
Namespace aliases
Namespace names need to be unique, which means that often they should not be too
short. If the length of a name makes code difficult to read, or is tedious to type in a
header file where using directives can't be used, then you can make a namespace alias
which serves as an abbreviation for the actual name. For example:
C++
C++
namespace
{
int MyFunc(){}
}
This is called an unnamed or anonymous namespace and it is useful when you want to
make variable declarations invisible to code in other files (i.e. give them internal linkage)
without having to create a named namespace. All code in the same file can see the
identifiers in an unnamed namespace but the identifiers, along with the namespace
itself, are not visible outside that file—or more precisely outside the translation unit.
See also
Declarations and Definitions
Enumerations (C++)
Article • 07/01/2022 • 5 minutes to read
7 Note
This article covers the ISO Standard C++ Language enum type and the scoped (or
strongly-typed) enum class type which is introduced in C++11. For information
about the public enum class or private enum class types in C++/CLI and C++/CX,
see enum class (C++/CLI and C++/CX).
Syntax
enum-name :
identifier
enum-specifier :
enum-head { enumerator-list opt }
enum-head { enumerator-list , }
enum-head :
enum-head-name :
nested-name-specifier opt identifier
opaque-enum-declaration :
enum-key attribute-specifier-seq opt enum-head-name enum-base opt ;
enum-key :
enum
enum class
enum struct
enum-base :
: type-specifier-seq
enumerator-list :
enumerator-definition
enumerator-list , enumerator-definition
enumerator-definition :
enumerator
enumerator = constant-expression
enumerator :
identifier attribute-specifier-seq opt
Usage
C++
// unscoped enum:
// enum [identifier] [: type] {enum-list};
// scoped enum:
// enum [class|struct] [identifier] [: type] {enum-list};
Parameters
identifier
type
The underlying type of the enumerators; all enumerators have the same underlying type.
May be any integral type.
enum-list
By using this keyword in the declaration, you specify the enum is scoped, and an
identifier must be provided. You can also use the struct keyword in place of class ,
Enumerator scope
An enumeration provides context to describe a range of values that are represented as
named constants. These named constants are also called enumerators. In the original C
and C++ enum types, the unqualified enumerators are visible throughout the scope in
which the enum is declared. In scoped enums, the enumerator name must be qualified
by the enum type name. The following example demonstrates this basic difference
between the two kinds of enums:
C++
namespace CardGame_Scoped
{
enum class Suit { Diamonds, Hearts, Clubs, Spades };
namespace CardGame_NonScoped
{
enum Suit { Diamonds, Hearts, Clubs, Spades };
Every name in an enumeration is assigned an integral value that corresponds to its place
in the order of the values in the enumeration. By default, the first value is assigned 0, the
next one is assigned 1, and so on, but you can explicitly set the value of an enumerator,
as shown here:
C++
enum Suit { Diamonds = 1, Hearts, Clubs, Spades };
Every enumerator is treated as a constant and must have a unique name within the
scope where the enum is defined (for unscoped enums) or within the enum itself (for
scoped enums). The values given to the names don't have to be unique. For example,
consider this declaration of an unscoped enum Suit :
C++
The values of Diamonds , Hearts , Clubs , and Spades are 5, 6, 4, and 5, respectively.
Notice that 5 is used more than once; it's allowed even though it may not be intended.
These rules are the same for scoped enums.
Casting rules
Unscoped enum constants can be implicitly converted to int , but an int is never
implicitly convertible to an enum value. The following example shows what happens if
you try to assign hand a value that isn't a Suit :
C++
C++
Using implicit conversions in this way can lead to unintended side-effects. To help
eliminate programming errors associated with unscoped enums, scoped enum values
are strongly typed. Scoped enumerators must be qualified by the enum type name
(identifier) and can't be implicitly converted, as shown in the following example:
C++
namespace ScopedEnumConversions
{
enum class Suit { Diamonds, Hearts, Clubs, Spades };
void AttemptConversions()
{
Suit hand;
hand = Clubs; // error C2065: 'Clubs' : undeclared identifier
hand = Suit::Clubs; //Correct.
int account_num = 135692;
hand = account_num; // error C2440: '=' : cannot convert from 'int'
to 'Suit'
hand = static_cast<Suit>(account_num); // OK, but probably a bug!!!
Notice that the line hand = account_num; still causes the error that occurs with unscoped
enums, as shown earlier. It's allowed with an explicit cast. However, with scoped enums,
the attempted conversion in the next statement, account_num = Suit::Hearts; , is no
longer allowed without an explicit cast.
C++
The new type is an exact copy of the underlying type, and therefore has the same calling
convention, which means it can be used across ABIs without any performance penalty.
No cast is required when variables of the type are initialized by using direct-list
initialization. The following example shows how to initialize enums with no enumerators
in various contexts:
C++
struct X
{
E e{ 0 };
X() : e{ 0 } { }
};
E* p = new E{ 0 };
int main()
{
f(E{ 0 });
byte i{ 42 };
byte j = byte{ 42 };
See also
C Enumeration declarations
Keywords
union
Article • 04/04/2023 • 8 minutes to read
7 Note
In C++17 and later, the std::variant class is a type-safe alternative for a union.
A union is a user-defined type in which all members share the same memory location.
This definition means that at any given time, a union can contain no more than one
object from its list of members. It also means that no matter how many members a
union has, it always uses only enough memory to store the largest member.
A union can be useful for conserving memory when you have lots of objects and limited
memory. However, a union requires extra care to use correctly. You're responsible for
ensuring that you always access the same member you assigned. If any member types
have a nontrivial constructor, then you must write code to explicitly construct and
destroy that member. Before you use a union, consider whether the problem you're
trying to solve could be better expressed by using a base class and derived class types.
Syntax
union tag opt { member-list };
Parameters
tag
member-list
Members that the union can contain.
Declare a union
Begin the declaration of a union by using the union keyword, and enclose the member
list in curly braces:
C++
// declaring_a_union.cpp
union RecordType // Declare a simple union type
{
char ch;
int i;
long l;
float f;
double d;
int *int_ptr;
};
int main()
{
RecordType t;
t.i = 5; // t holds an int
t.f = 7.25; // t now holds a float
}
Use a union
In the previous example, any code that accesses the union needs to know which
member holds the data. The most common solution to this problem is called a
discriminated union. It encloses the union in a struct, and includes an enum member that
indicates the member type currently stored in the union. The following example shows
the basic pattern:
C++
#include <queue>
struct TempData
{
int StationId;
time_t time;
double current;
double max;
double min;
};
struct WindData
{
int StationId;
time_t time;
int speed;
short direction;
};
struct Input
{
WeatherDataType type;
union
{
TempData temp;
WindData wind;
};
};
Input second;
second.type = WeatherDataType::Wind;
second.wind = { 204, 1418859354, 14, 27 };
inputs.push(second);
}
}
return 0;
}
In the previous example, the union in the Input struct has no name, so it's called an
anonymous union. Its members can be accessed directly as if they're members of the
struct. For more information about how to use an anonymous union, see the
Anonymous union section.
The previous example shows a problem that you could also solve by using class types
that derive from a common base class. You could branch your code based on the
runtime type of each object in the container. Your code might be easier to maintain and
understand, but it might also be slower than using a union. Also, with a union, you can
store unrelated types. A union lets you dynamically change the type of the stored value
without changing the type of the union variable itself. For example, you could create a
heterogeneous array of MyUnionType , whose elements store different values of different
types.
It's easy to misuse the Input struct in the example. It's up to the user to use the
discriminator correctly to access the member that holds the data. You can protect
against misuse by making the union private and providing special access functions, as
shown in the next example.
C++
// for MyVariant
#include <crtdbg.h>
#include <new>
#include <utility>
struct A
{
A() = default;
A(int i, const string& str) : num(i), name(str) {}
int num;
string name;
//...
};
struct B
{
B() = default;
B(int i, const string& str) : num(i), name(str) {}
int num;
string name;
vector<int> vec;
// ...
};
MyVariant(Kind kind)
: kind_(kind)
{
switch (kind_)
{
case Kind::None:
break;
case Kind::A:
new (&a_) A();
break;
case Kind::B:
new (&b_) B();
break;
case Kind::Integer:
i_ = 0;
break;
default:
_ASSERT(false);
break;
}
}
~MyVariant()
{
switch (kind_)
{
case Kind::None:
break;
case Kind::A:
a_.~A();
break;
case Kind::B:
b_.~B();
break;
case Kind::Integer:
break;
default:
_ASSERT(false);
break;
}
kind_ = Kind::None;
}
MyVariant(MyVariant&& other)
: kind_(other.kind_)
{
switch (kind_)
{
case Kind::None:
break;
case Kind::A:
new (&a_) A(move(other.a_));
break;
case Kind::B:
new (&b_) B(move(other.b_));
break;
case Kind::Integer:
i_ = other.i_;
break;
default:
_ASSERT(false);
break;
}
other.kind_ = Kind::None;
}
MyVariant(const A& a)
: kind_(Kind::A), a_(a)
{
}
MyVariant(A&& a)
: kind_(Kind::A), a_(move(a))
{
}
MyVariant& operator=(A&& a)
{
if (kind_ != Kind::A)
{
this->~MyVariant();
new (this) MyVariant(move(a));
}
else
{
a_ = move(a);
}
return *this;
}
MyVariant(const B& b)
: kind_(Kind::B), b_(b)
{
}
MyVariant(B&& b)
: kind_(Kind::B), b_(move(b))
{
}
MyVariant& operator=(B&& b)
{
if (kind_ != Kind::B)
{
this->~MyVariant();
new (this) MyVariant(move(b));
}
else
{
b_ = move(b);
}
return *this;
}
MyVariant(int i)
: kind_(Kind::Integer), i_(i)
{
}
MyVariant& operator=(int i)
{
if (kind_ != Kind::Integer)
{
this->~MyVariant();
new (this) MyVariant(i);
}
else
{
i_ = i;
}
return *this;
}
B& GetB()
{
_ASSERT(kind_ == Kind::B);
return b_;
}
int& GetInteger()
{
_ASSERT(kind_ == Kind::Integer);
return i_;
}
private:
Kind kind_;
union
{
A a_;
B b_;
int i_;
};
};
#pragma warning (pop)
int main()
{
A a(1, "Hello from A");
B b(2, "Hello from B");
MyVariant mv_1 = a;
cout << "mv_1 = a: " << mv_1.GetA().name << endl;
mv_1 = b;
cout << "mv_1 = b: " << mv_1.GetB().name << endl;
mv_1 = A(3, "hello again from A");
cout << R"aaa(mv_1 = A(3, "hello again from A"): )aaa" <<
mv_1.GetA().name << endl;
mv_1 = 42;
cout << "mv_1 = 42: " << mv_1.GetInteger() << endl;
b.vec = { 10,20,30,40,50 };
mv_1 = move(b);
cout << "After move, mv_1 = b: vec.size = " << mv_1.GetB().vec.size() <<
endl;
A union can't store a reference. A union also doesn't support inheritance. That means
you can't use a union as a base class, or inherit from another class, or have virtual
functions.
Initialize a union
You can declare and initialize a union in the same statement by assigning an expression
enclosed in braces. The expression is evaluated and assigned to the first field of the
union.
C++
#include <iostream>
using namespace std;
union NumericType
{
short iValue;
long lValue;
double dValue;
};
int main()
{
union NumericType Values = { 10 }; // iValue = 10
cout << Values.iValue << endl;
Values.dValue = 3.1416;
cout << Values.dValue << endl;
}
/* Output:
10
3.141600
*/
Anonymous union
An anonymous union is one declared without a class-name or declarator-list .
union { member-list }
Names declared in an anonymous union are used directly, like nonmember variables. It
implies that the names declared in an anonymous union must be unique in the
surrounding scope.
See also
Classes and Structs
Keywords
class
struct
Functions (C++)
Article • 02/14/2023 • 13 minutes to read
A function is a block of code that performs some operation. A function can optionally
define input parameters that enable callers to pass arguments into the function. A
function can optionally return a value as output. Functions are useful for encapsulating
common operations in a single reusable block, ideally with a name that clearly describes
what the function does. The following function accepts two integers from a caller and
returns their sum; a and b are parameters of type int .
C++
The function can be invoked, or called, from any number of places in the program. The
values that are passed to the function are the arguments, whose types must be
compatible with the parameter types in the function definition.
C++
int main()
{
int i = sum(10, 32);
int j = sum(i, 66);
cout << "The value of j is" << j << endl; // 108
}
There's no practical limit to function length, but good design aims for functions that
perform a single well-defined task. Complex algorithms should be broken up into easy-
to-understand simpler functions whenever possible.
Functions that are defined at class scope are called member functions. In C++, unlike
other languages, a function can also be defined at namespace scope (including the
implicit global namespace). Such functions are called free functions or non-member
functions; they're used extensively in the Standard Library.
Functions may be overloaded, which means different versions of a function may share
the same name if they differ by the number and/or type of formal parameters. For more
information, see Function Overloading.
Parts of a function declaration
A minimal function declaration consists of the return type, function name, and
parameter list (which may be empty), along with optional keywords that provide more
instructions to the compiler. The following example is a function declaration:
C++
A function definition consists of a declaration, plus the body, which is all the code
between the curly braces:
C++
1. The return type, which specifies the type of the value that the function returns, or
void if no value is returned. In C++11, auto is a valid return type that instructs the
compiler to infer the type from the return statement. In C++14, decltype(auto) is
also allowed. For more information, see Type Deduction in Return Types below.
2. The function name, which must begin with a letter or underscore and can't contain
spaces. In general, leading underscores in the Standard Library function names
indicate private member functions, or non-member functions that aren't intended
for use by your code.
C++
C++
3. inline , which instructs the compiler to replace every call to the function with the
function code itself. inlining can help performance in scenarios where a function
executes quickly and is invoked repeatedly in a performance-critical section of
code.
C++
4. A noexcept expression, which specifies whether or not the function can throw an
exception. In the following example, the function doesn't throw an exception if the
is_pod expression evaluates to true .
C++
#include <type_traits>
5. (Member functions only) The cv-qualifiers, which specify whether the function is
const or volatile .
7. (member functions only) static applied to a member function means that the
function isn't associated with any object instances of the class.
Function definitions
A function definition consists of the declaration and the function body, enclosed in curly
braces, which contains variable declarations, statements and expressions. The following
example shows a complete function definition:
C++
Variables declared inside the body are called local variables or locals. They go out of
scope when the function exits; therefore, a function should never return a reference to a
local!
C++
MyClass& boom(int i, std::string s)
{
int value {i};
MyClass mc;
mc.Initialize(i,s);
return mc;
}
Declare a function as constexpr when the value it produces can possibly be determined
at compile time. A constexpr function generally executes faster than a regular function.
For more information, see constexpr.
Function Templates
A function template is similar to a class template; it generates concrete functions based
on the template arguments. In many cases, the template is able to infer the type
arguments and therefore it isn't necessary to explicitly specify them.
C++
By default, arguments are passed to the function by value, which means the function
receives a copy of the object being passed. For large objects, making a copy can be
expensive and isn't always necessary. To cause arguments to be passed by reference
(specifically lvalue reference), add a reference quantifier to the parameter:
C++
C++
C++ 11: To explicitly handle arguments that are passed by rvalue-reference or lvalue-
reference, use a double-ampersand on the parameter to indicate a universal reference:
C++
A function declared with the single keyword void in the parameter declaration list takes
no arguments, as long as the keyword void is the first and only member of the
argument declaration list. Arguments of type void elsewhere in the list produce errors.
For example:
C++
// OK same as GetTickCount()
long GetTickCount( void );
While it's illegal to specify a void argument except as outlined here, types derived from
type void (such as pointers to void and arrays of void ) can appear anywhere the
argument declaration list.
Default Arguments
The last parameter or parameters in a function signature may be assigned a default
argument, which means that the caller may leave out the argument when calling the
function unless they want to specify some other value.
C++
C++
When auto is used in conjunction with a trailing return type, it just serves as a
placeholder for whatever the decltype expression produces, and doesn't itself perform
type deduction.
In C++ a local variable may be declared as static. The variable is only visible inside the
function body, but a single copy of the variable exists for all instances of the function.
Local static objects are destroyed during termination specified by atexit . If a static
object wasn't constructed because the program's flow of control bypassed its
declaration, no attempt is made to destroy that object.
In this example, auto will be deduced as a non-const value copy of the sum of lhs and
rhs.
C++
The following example (based on code from N3493 ), shows decltype(auto) being
used to enable perfect forwarding of function arguments in a return type that isn't
known until the template is instantiated.
C++
1. Encapsulate the values in a named class or struct object. Requires the class or
struct definition to be visible to the caller:
C++
#include <string>
#include <iostream>
struct S
{
string name;
int num;
};
S g()
{
string t{ "hello" };
int u{ 42 };
return { t, u };
}
int main()
{
S s = g();
cout << s.name << " " << s.num << endl;
return 0;
}
C++
#include <tuple>
#include <string>
#include <iostream>
int main()
{
auto t = f();
cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
// --or--
int myval;
string myname;
double mydecimal;
tie(myval, myname, mydecimal) = f();
cout << myval << " " << myname << " " << mydecimal << endl;
return 0;
}
3. Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later):
Use structured bindings. The advantage of structured bindings is that the variables
that store the return values are initialized at the same time they're declared, which
in some cases can be significantly more efficient. In the statement auto[x, y, z] =
f(); the brackets introduce and initialize names that are in scope for the entire
function block.
C++
#include <tuple>
#include <string>
#include <iostream>
S g()
{
string t{ "hello" };
int u{ 42 };
return { t, u };
}
int main()
{
auto[x, y, z] = f(); // init from tuple
cout << x << " " << y << " " << z << endl;
4. In addition to using the return value itself, you can "return" values by defining any
number of parameters to use pass-by-reference so that the function can modify or
initialize the values of objects that the caller provides. For more information, see
Reference-Type Function Arguments.
Function pointers
C++ supports function pointers in the same manner as the C language. However a more
type-safe alternative is usually to use a function object.
It's recommended that you use typedef to declare an alias for the function pointer type
if declaring a function that returns a function pointer type. For example
C++
If this isn't done, the proper syntax for the function declaration may be deduced from
the declarator syntax for the function pointer by replacing the identifier ( fp in the above
example) with the functions name and argument list, as follows:
C++
See also
Function Overloading
Functions with Variable Argument Lists
Explicitly Defaulted and Deleted Functions
Argument-Dependent Name (Koenig) Lookup on Functions
Default Arguments
Inline Functions
Functions with Variable Argument Lists
(C++)
Article • 08/03/2021 • 3 minutes to read
Function declarations in which the last member of is the ellipsis (...) can take a variable
number of arguments. In these cases, C++ provides type checking only for the explicitly
declared arguments. You can use variable argument lists when you need to make a
function so general that even the number and types of arguments can vary. The family
of functions is an example of functions that use variable argument
lists. printf argument-declaration-list
Microsoft Specific
Microsoft C++ allows the ellipsis to be specified as an argument if the ellipsis is the last
argument and the ellipsis is preceded by a comma. Therefore, the declaration int Func(
int i, ... ); is legal, but int Func( int i ... ); is not.
When arguments of type char are passed as variable arguments, they are converted to
type int . Similarly, when arguments of type float are passed as variable arguments,
they are converted to type double . Arguments of other types are subject to the usual
integral and floating-point promotions. See Standard Conversions for more information.
Functions that require variable lists are declared by using the ellipsis (...) in the argument
list. Use the types and macros that are described in the <stdarg.h> include file to access
arguments that are passed by a variable list. For more information about these macros,
see va_arg, va_copy, va_end, va_start. in the documentation for the C Run-Time Library.
The following example shows how the macros work together with the type (declared in
<stdarg.h>):
C++
// variable_argument_lists.cpp
#include <stdio.h>
#include <stdarg.h>
case 'f':
Printable.f = va_arg( vl, double );
printf_s( "%f\n", Printable.f );
break;
case 'c':
Printable.c = va_arg( vl, char );
printf_s( "%c\n", Printable.c );
break;
case 's':
Printable.s = va_arg( vl, char * );
printf_s( "%s\n", Printable.s );
break;
default:
break;
}
}
va_end( vl );
}
//Output:
// 32.400002
// a
// Test string
1. You must establish a list marker as a variable of type va_list before any variable
arguments are accessed. In the previous example, the marker is called vl .
2. The individual arguments are accessed by using the va_arg macro. You must tell
the va_arg macro the type of argument to retrieve so that it can transfer the
correct number of bytes from the stack. If you specify an incorrect type of a size
different from that supplied by the calling program to va_arg , the results are
unpredictable.
3. You should explicitly cast the result obtained by using the va_arg macro to the
type that you want.
C++ lets you specify more than one function of the same name in the same scope.
These functions are called overloaded functions, or overloads. Overloaded functions
enable you to supply different semantics for a function, depending on the types and
number of its arguments.
For example, consider a print function that takes a std::string argument. This
function might perform very different tasks than a function that takes an argument of
type double . Overloading keeps you from having to use names such as print_string or
print_double . At compile time, the compiler chooses which overload to use based on
the types and number of arguments passed in by the caller. If you call print(42.0) , then
the void print(double d) function is invoked. If you call print("hello world") , then the
void print(std::string) overload is invoked.
You can overload both member functions and free functions. The following table shows
which parts of a function declaration C++ uses to differentiate between groups of
functions with the same name in the same scope.
Overloading Considerations
Example
The following example illustrates how you can use function overloads:
C++
// function_overloading.cpp
// compile with: /EHsc
#include <iostream>
#include <math.h>
#include <string>
// Print a string.
int print(string s)
{
cout << s << endl;
return cout.good();
}
The preceding code shows overloads of the print function in file scope.
The default argument isn't considered part of the function type. Therefore, it's not used
in selecting overloaded functions. Two functions that differ only in their default
arguments are considered multiple definitions rather than overloaded functions.
Argument matching
The compiler selects which overloaded function to invoke based on the best match
among the function declarations in the current scope to the arguments supplied in the
function call. If a suitable function is found, that function is called. "Suitable" in this
context means either:
A set of "best matching functions" is built for each argument, and the selected function
is the intersection of all the sets. If the intersection contains more than one function, the
overloading is ambiguous and generates an error. The function that's eventually
selected is always a better match than every other function in the group for at least one
argument. If there's no clear winner, the function call generates a compiler error.
Consider the following declarations (the functions are marked Variant 1 , Variant 2 ,
and Variant 3 , for identification in the following discussion):
C++
C++
F1 = Add( F2, 23 );
Set 1: Candidate functions that have first Set 2: Candidate functions whose second
argument of type Fraction argument can be converted to type int
Variant 3
Functions in Set 2 are functions that have implicit conversions from the actual parameter
type to the formal parameter type. One of those functions has the smallest "cost" to
convert the actual parameter type to its corresponding formal parameter type.
The intersection of these two sets is Variant 1. An example of an ambiguous function call
is:
C++
F1 = Add( 3, 6 );
Set 1: Candidate Functions That Have First Set 2: Candidate Functions That Have Second
Argument of Type int Argument of Type int
Variant 2 ( int can be converted to long using Variant 1 ( int can be converted to long using a
a standard conversion) standard conversion)
Because the intersection of these two sets is empty, the compiler generates an error
message.
For argument matching, a function with n default arguments is treated as n+1 separate
functions, each with a different number of arguments.
The ellipsis ( ... ) acts as a wildcard; it matches any actual argument. It can lead to many
ambiguous sets, if you don't design your overloaded function sets with extreme care.
7 Note
For the same reason, function arguments of a type modified by const or volatile
aren't treated differently than the base type for the purposes of overloading.
However, the function overloading mechanism can distinguish between references that
are qualified by const and volatile and references to the base type. It makes code
such as the following possible:
C++
// argument_type_differences.cpp
// compile with: /EHsc /W3
// C4521 expected
#include <iostream>
int main() {
Over o1; // Calls default constructor.
Over o2( o1 ); // Calls Over( Over& ).
const Over o3; // Calls default constructor.
Over o4( o3 ); // Calls Over( const Over& ).
volatile Over o5; // Calls default constructor.
Over o6( o5 ); // Calls Over( volatile Over& ).
}
Output
Output
Pointers to const and volatile objects are also considered different from pointers to
the base type for the purposes of overloading.
The resultant sequence of conversions, if any, is called the best matching sequence. There
are several ways to convert an object of type int to type unsigned long using standard
conversions (described in Standard conversions):
Convert from int to long and then from long to unsigned long .
Although the first sequence achieves the desired goal, it isn't the best matching
sequence, because a shorter sequence exists.
The following table shows a group of conversions called trivial conversions. Trivial
conversions have a limited effect on which sequence the compiler chooses as the best
match. The effect of trivial conversions is described after the table.
Trivial conversions
type-name type-name&
type-name& type-name
type-name[] type-name*
type-name(argument-list) (*type-name)(argument-list)
1. Exact match. An exact match between the types with which the function is called
and the types declared in the function prototype is always the best match.
Sequences of trivial conversions are classified as exact matches. However,
sequences that don't make any of these conversions are considered better than
sequences that convert:
2. Match using promotions. Any sequence not classified as an exact match that
contains only integral promotions, conversions from float to double , and trivial
conversions is classified as a match using promotions. Although not as good a
match as any exact match, a match using promotions is better than a match using
standard conversions.
3. Match using standard conversions. Any sequence not classified as an exact match
or a match using promotions that contains only standard conversions and trivial
conversions is classified as a match using standard conversions. Within this
category, the following rules are applied:
This same rule applies to reference conversions. Conversion from type D& to type C& is
preferable to conversion from type D& to type B& , and so on.
This same rule applies to pointer-to-member conversions. Conversion from type T D::*
to type T C::* is preferable to conversion from type T D::* to type T B::* , and so on
(where T is the type of the member).
The preceding rule applies only along a given path of derivation. Consider the graph
shown in the following figure.
2. Match with an ellipsis. Any sequence that matches an ellipsis in the declaration is
classified as a match with an ellipsis. It's considered the weakest match.
C++
// argument_matching1.cpp
class UDC
{
public:
operator int()
{
return 0;
}
operator long();
};
void Print( int i )
{
};
UDC udc;
int main()
{
Print( udc );
}
The available user-defined conversions for class UDC are from type int and type long .
Therefore, the compiler considers conversions for the type of the object being matched:
UDC . A conversion to int exists, and it's selected.
C++
C++
// argument_matching2.cpp
// C2668 expected
class UDC1
{
public:
UDC1( int ); // User-defined conversion from int.
};
class UDC2
{
public:
UDC2( long ); // User-defined conversion from long.
};
int main()
{
Func( 1 );
}
Both versions of Func require a user-defined conversion to convert type int to the class
type argument. The possible conversions are:
Convert from type int to type long ; then convert to type UDC2 (a two-step
conversion).
Even though the second one requires both a standard conversion and the user-defined
conversion, the two conversions are still considered equal.
7 Note
Member functions that aren't static require the implied this pointer to match the
object type the function is being called through. Or, for overloaded operators, they
require the first argument to match the object the operator is applied to. For more
information about overloaded operators, see Overloaded operators.
Unlike other arguments in overloaded functions, the compiler introduces no temporary
objects and attempts no conversions when trying to match the this pointer argument.
When the -> member-selection operator is used to access a member function of class
class_name , the this pointer argument has a type of class_name * const . If the
members are declared as const or volatile , the types are const class_name * const
and volatile class_name * const , respectively.
The . member-selection operator works exactly the same way, except that an implicit &
(address-of) operator is prefixed to the object name. The following example shows how
this works:
C++
The left operand of the ->* and .* (pointer to member) operators are treated the same
way as the . and -> (member-selection) operators with respect to argument matching.
C++
#include <iostream>
#include <vector>
class C
{
public:
C() {/*expensive initialization*/}
vector<unsigned> get_data() &
{
cout << "lvalue\n";
return _data;
}
vector<unsigned> get_data() &&
{
cout << "rvalue\n";
return std::move(_data);
}
private:
vector<unsigned> _data;
};
int main()
{
C c;
auto v = c.get_data(); // get a copy. prints "lvalue".
auto v2 = C().get_data(); // get the original. prints "rvalue"
return 0;
}
Restrictions on overloading
Several restrictions govern an acceptable set of overloaded functions:
Any two functions in a set of overloaded functions must have different argument
lists.
Overloading functions that have argument lists of the same types, based on return
type alone, is an error.
Microsoft Specific
You can overload operator new based on the return type, specifically, based on the
memory-model modifier specified.
Member functions can't be overloaded solely because one is static and the other
isn't static .
typedef declarations don't define new types; they introduce synonyms for existing
types. They don't affect the overloading mechanism. Consider the following code:
C++
typedef char * PSTR;
The preceding two functions have identical argument lists. PSTR is a synonym for
type char * . In member scope, this code generates an error.
Enumerated types are distinct types and can be used to distinguish between
overloaded functions.
The types "array of" and "pointer to" are considered identical for the purposes of
distinguishing between overloaded functions, but only for one-dimensional arrays.
These overloaded functions conflict and generate an error message:
C++
For higher dimension arrays, the second and later dimensions are considered part
of the type. They're used in distinguishing between overloaded functions:
C++
Class scope is strictly observed. A function declared in a base class isn't in the same
scope as a function declared in a derived class. If a function in a derived class is declared
with the same name as a virtual function in the base class, the derived-class function
overrides the base-class function. For more information, see Virtual Functions.
If the base class function isn't declared as virtual , then the derived class function is
said to hide it. Both overriding and hiding are distinct from overloading.
Block scope is strictly observed. A function declared in file scope isn't in the same scope
as a function declared locally. If a locally declared function has the same name as a
function declared in file scope, the locally declared function hides the file-scoped
function instead of causing overloading. For example:
C++
// declaration_matching1.cpp
// compile with: /EHsc
#include <iostream>
int main()
{
// Declare func local to main.
extern void func( char *sz );
The preceding code shows two definitions from the function func . The definition that
takes an argument of type char * is local to main because of the extern statement.
Therefore, the definition that takes an argument of type int is hidden, and the first call
to func is in error.
For overloaded member functions, different versions of the function can be given
different access privileges. They're still considered to be in the scope of the enclosing
class and thus are overloaded functions. Consider the following code, in which the
member function Deposit is overloaded; one version is public, the other, private.
The intent of this sample is to provide an Account class in which a correct password is
required to perform deposits. It's done by using overloading.
The call to Deposit in Account::Deposit calls the private member function. This call is
correct because Account::Deposit is a member function, and has access to the private
members of the class.
C++
// declaration_matching2.cpp
class Account
{
public:
Account()
{
}
double Deposit( double dAmount, char *szPassword );
private:
double Deposit( double dAmount )
{
return 0.0;
}
int Validate( char *szPassword )
{
return 0;
}
};
int main()
{
// Allocate a new object of type Account.
Account *pAcct = new Account;
See also
Functions (C++)
Explicitly Defaulted and Deleted
Functions
Article • 08/03/2021 • 6 minutes to read
In C++11, defaulted and deleted functions give you explicit control over whether the
special member functions are automatically generated. Deleted functions also give you
simple language to prevent problematic type promotions from occurring in arguments
to functions of all types—special member functions, as well as normal member functions
and non-member functions—which would otherwise cause an unwanted function call.
This is convenient for simple types, but complex types often define one or more of the
special member functions themselves, and this can prevent other special member
functions from being automatically generated. In practice:
7 Note
The consequences of these rules can also leak into object hierarchies. For example, if for
any reason a base class fails to have a default constructor that's callable from a deriving
class—that is, a public or protected constructor that takes no parameters—then a class
that derives from it cannot automatically generate its own default constructor.
C++
struct noncopyable
{
noncopyable() {};
private:
noncopyable(const noncopyable&);
noncopyable& operator=(const noncopyable&);
};
Before C++11, this code snippet was the idiomatic form of non-copyable types.
However, it has several problems:
The copy constructor has to be declared privately to hide it, but because it's
declared at all, automatic generation of the default constructor is prevented. You
have to explicitly define the default constructor if you want one, even if it does
nothing.
Even if the explicitly-defined default constructor does nothing, it's considered non-
trivial by the compiler. It's less efficient than an automatically generated default
constructor and prevents noncopyable from being a true POD type.
Even though the copy constructor and copy-assignment operator are hidden from
outside code, the member functions and friends of noncopyable can still see and
call them. If they are declared but not defined, calling them causes a linker error.
Although this is a commonly accepted idiom, the intent is not clear unless you
understand all of the rules for automatic generation of the special member
functions.
C++
struct noncopyable
{
noncopyable() =default;
noncopyable(const noncopyable&) =delete;
noncopyable& operator=(const noncopyable&) =delete;
};
Notice how the problems with the pre-C++11 idiom are resolved:
Explicitly defaulted special member functions are still considered trivial, so there is
no performance penalty, and noncopyable is not prevented from being a true POD
type.
The copy constructor and copy-assignment operator are public but deleted. It is a
compile-time error to define or call a deleted function.
The intent is clear to anyone who understands =default and =delete . You don't
have to understand the rules for automatic generation of special member
functions.
Similar idioms exist for making user-defined types that are non-movable, that can only
be dynamically allocated, or that cannot be dynamically allocated. Each of these idioms
have pre-C++11 implementations that suffer similar problems, and that are similarly
resolved in C++11 by implementing them in terms of defaulted and deleted special
member functions.
Explicitly defaulted functions
You can default any of the special member functions—to explicitly state that the special
member function uses the default implementation, to define the special member
function with a non-public access qualifier, or to reinstate a special member function
whose automatic generation was prevented by other circumstances.
C++
struct widget
{
widget()=default;
Notice that you can default a special member function outside the body of a class as
long as it's inlinable.
Deleted functions
You can delete special member functions as well as normal member functions and non-
member functions to prevent them from being defined or called. Deleting of special
member functions provides a cleaner way of preventing the compiler from generating
special member functions that you don't want. The function must be deleted as it is
declared; it cannot be deleted afterwards in the way that a function can be declared and
then later defaulted.
C++
struct widget
{
// deleted operator new prevents widget from being dynamically allocated.
void* operator new(std::size_t) = delete;
};
C++
by using an int argument would not; in the int case, the argument will be promoted
from int to double and successfully call the double version of the function, even
though that might not be what's intended. To ensure that any call to this function by
using a non-double argument causes a compiler error, you can declare a template
version of the function that's deleted.
C++
The compiler can use argument-dependent name lookup to find the definition of an
unqualified function call. Argument-dependent name lookup is also called Koenig
lookup. The type of every argument in a function call is defined within a hierarchy of
namespaces, classes, structures, unions, or templates. When you specify an unqualified
postfix function call, the compiler searches for the function definition in the hierarchy
associated with each argument type.
Example
In the sample, the compiler notes that function f() takes an argument x . Argument x
is of type A::X , which is defined in namespace A . The compiler searches namespace A
and finds a definition for function f() that takes an argument of type A::X .
C++
// argument_dependent_name_koenig_lookup_on_functions.cpp
namespace A
{
struct X
{
};
void f(const X&)
{
}
}
int main()
{
// The compiler finds A::f() in namespace A, which is where
// the type of argument x is defined. The type of x is A::X.
A::X x;
f(x);
}
Default Arguments
Article • 08/03/2021 • 2 minutes to read
In many cases, functions have arguments that are used so infrequently that a default
value would suffice. To address this, the default-argument facility allows for specifying
only those arguments to a function that are meaningful in a given call. To illustrate this
concept, consider the example presented in Function Overloading.
C++
In many applications, a reasonable default can be supplied for prec , eliminating the
need for two functions:
C++
The implementation of the print function is changed slightly to reflect the fact that
only one such function exists for type double :
C++
// default_arguments.cpp
// compile with: /EHsc /c
#include <iostream>
#include <math.h>
using namespace std;
To invoke the new print function, use code such as the following:
C++
Default arguments are used only in function calls where trailing arguments are
omitted — they must be the last argument(s). Therefore, the following code is
illegal:
C++
C++
...
C++
The inline keyword tells the compiler to substitute the code within the function
definition for every instance of a function call.
Using inline functions can make your program faster because they eliminate the
overhead associated with function calls. The compiler can optimize functions expanded
inline in ways that aren't available to normal functions.
Inline code substitution occurs at the compiler's discretion. For example, the compiler
won't inline a function if its address is taken or if it's too large to inline.
Example
In the following class declaration, the Account constructor is an inline function. The
member functions GetBalance , Deposit , and Withdraw aren't specified as inline but
can be implemented as inline functions.
C++
// Inline_Member_Functions.cpp
class Account
{
public:
Account(double initial_balance) { balance = initial_balance; }
double GetBalance();
double Deposit( double Amount );
double Withdraw( double Amount );
private:
double balance;
};
7 Note
In the class declaration, the functions were declared without the inline keyword.
The inline keyword can be specified in the class declaration; the result is the same.
A given inline member function must be declared the same way in every compilation
unit. This constraint causes inline functions to behave as if they were instantiated
functions. Additionally, there must be exactly one definition of an inline function.
A class member function defaults to external linkage unless a definition for that function
contains the inline specifier. The preceding example shows that you don't have to
declare these functions explicitly with the inline specifier. Using inline in the function
definition causes it to be an inline function. However, you can't redeclare a function as
inline after a call to that function.
The insertion, called inline expansion or inlining, occurs only if the compiler's cost-
benefit analysis shows it's worthwhile. Inline expansion minimizes the function-call
overhead at the potential cost of larger code size.
The __forceinline keyword overrides the cost-benefit analysis and relies on the
judgment of the programmer instead. Exercise caution when using __forceinline .
Indiscriminate use of __forceinline can result in larger code with only marginal
performance gains or, in some cases, even performance losses (because of the increased
paging of a larger executable, for example).
The compiler treats the inline expansion options and keywords as suggestions. There's
no guarantee that functions will be inlined. You can't force the compiler to inline a
particular function, even with the __forceinline keyword. When you compile with /clr ,
the compiler won't inline a function if there are security attributes applied to the
function.
For compatibility with previous versions, _inline and _forceinline are synonyms for
__inline and __forceinline , respectively, unless compiler option /Za (Disable language
extensions) is specified.
The inline keyword tells the compiler that inline expansion is preferred. However, the
compiler can create a separate instance of the function (instantiate) and create standard
calling linkages instead of inserting the code inline. Two cases where this behavior can
happen are:
Recursive functions.
Functions that are referred to through a pointer elsewhere in the translation unit.
These reasons may interfere with inlining, as may others, at the discretion of the
compiler; you shouldn't depend on the inline specifier to cause a function to be
inlined.
Rather than expand an inline function defined in a header file, the compiler may create it
as a callable function in more than one translation unit. The compiler marks the
generated function for the linker to prevent one-definition-rule (ODR) violations.
As with normal functions, there's no defined order for argument evaluation in an inline
function. In fact, it could be different from the argument evaluation order when passed
using the normal function-call protocol.
The /Ob compiler optimization option helps to determine whether inline function
expansion actually occurs.
/LTCG does cross-module inlining whether it's requested in source code or not.
Example 1
C++
// inline_keyword1.cpp
// compile with: /c
inline int max( int a , int b ) {
if( a > b )
return a;
return b;
}
A class's member functions can be declared inline, either by using the inline keyword
or by placing the function definition within the class definition.
Example 2
C++
// inline_keyword2.cpp
// compile with: /EHsc /c
#include <iostream>
using namespace std;
class MyClass {
public:
void print() { cout << i << ' '; } // Implicitly inline
private:
int i;
};
Microsoft-specific
Even with __forceinline , the compiler can't inline code in all circumstances. The
compiler can't inline a function if:
The function or its caller is compiled with /Ob0 (the default option for debug
builds).
The function and the caller use different types of exception handling (C++
exception handling in one, structured exception handling in the other).
The function uses inline assembly, unless compiled with /Ox , /O1 , or /O2 .
The function is recursive and doesn't have #pragma inline_recursion(on) set. With
the pragma, recursive functions are inlined to a default depth of 16 calls. To reduce
the inlining depth, use inline_depth pragma.
The function is virtual and is called virtually. Direct calls to virtual functions can be
inlined.
The program takes the address of the function and the call is made via the pointer
to the function. Direct calls to functions that have had their address taken can be
inlined.
Recursive functions can be replaced with inline code to a depth specified by the
inline_depth pragma, up to a maximum of 16 calls. After that depth, recursive function
calls are treated as calls to an instance of the function. The depth to which recursive
functions are examined by the inline heuristic can't exceed 16. The inline_recursion
pragma controls the inline expansion of a function currently under expansion. See the
Inline-Function Expansion (/Ob) compiler option for related information.
C++
// when_to_use_inline_functions.cpp
class Point
{
public:
// Define "accessor" functions as
// reference types.
unsigned& x();
unsigned& y();
private:
unsigned _x;
unsigned _y;
};
Function calls (including parameter passing and placing the object's address on
the stack)
Return-value communication
Return
Inline functions follow all the protocols of type safety enforced on normal
functions.
Inline functions are specified using the same syntax as any other function except
that they include the inline keyword in the function declaration.
Expressions passed as arguments to inline functions are evaluated once. In some
cases, expressions passed as arguments to macros can be evaluated more than
once.
The following example shows a macro that converts lowercase letters to uppercase:
C++
// inline_functions_macro.c
#include <stdio.h>
#include <conio.h>
#define toupper(a) ((a) >= 'a' && ((a) <= 'z') ? ((a)-('a'-'A')):(a))
int main() {
char ch;
printf_s("Enter a character: ");
ch = toupper( getc(stdin) );
printf_s( "%c", ch );
}
// Sample Input: xyz
// Sample Output: Z
C++
// inline_functions_inline.cpp
#include <stdio.h>
#include <conio.h>
int main() {
printf_s("Enter a character: ");
char ch = toupper( getc(stdin) );
printf_s( "%c", ch );
}
Output
Sample Input: a
Sample Output: A
See also
noinline
auto_inline
Operator overloading
Article • 02/17/2022 • 2 minutes to read
The operator keyword declares a function specifying what operator-symbol means when
applied to instances of a class. This gives the operator more than one meaning, or
"overloads" it. The compiler distinguishes between the different meanings of an
operator by examining the types of its operands.
Syntax
type operator operator-symbol ( parameter-list )
Remarks
You can redefine the function of most built-in operators globally or on a class-by-class
basis. Overloaded operators are implemented as functions.
Redefinable Operators
, Comma Binary
!= Inequality Binary
% Modulus Binary
() Function call —
* Multiplication Binary
+ Addition Binary
++ Increment 1 Unary
- Subtraction Binary
-- Decrement 1 Unary
/ Division Binary
= Assignment Binary
== Equality Binary
[] Array subscript —
^ Exclusive OR Binary
|| Logical OR Binary
delete Delete —
new New —
1 Two versions of the unary increment and decrement operators exist: preincrement and
postincrement.
See General Rules for Operator Overloading for more information. The constraints on
the various categories of overloaded operators are described in the following topics:
Unary Operators
Binary Operators
Assignment
Function Call
Subscripting
Class-Member Access
The operators shown in the following table cannot be overloaded. The table includes the
preprocessor symbols # and ##.
Nonredefinable Operators
Operator Name
. Member selection
.* Pointer-to-member selection
:: Scope resolution
?: Conditional
## Preprocessor concatenate
Although overloaded operators are usually called implicitly by the compiler when they
are encountered in code, they can be invoked explicitly the same way as any member or
nonmember function is called:
C++
Point pt;
pt.operator+( 3 ); // Call addition operator to add 3 to pt.
Example
The following example overloads the + operator to add two complex numbers and
returns the result.
C++
// operator_overloading.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
struct Complex {
Complex( double r, double i ) : re(r), im(i) {}
Complex operator+( Complex &other );
void Display( ) { cout << re << ", " << im << endl; }
private:
double re, im;
};
int main() {
Complex a = Complex( 1.2, 3.4 );
Complex b = Complex( 5.6, 7.8 );
Complex c = Complex( 0.0, 0.0 );
c = a + b;
c.Display();
}
Output
6.8, 11.2
In this section
General Rules for Operator Overloading
Binary Operators
Assignment
Function Call
Subscripting
Member Access
See also
C++ Built-in Operators, Precedence and Associativity
Keywords
General Rules for Operator Overloading
Article • 08/03/2021 • 2 minutes to read
The following rules constrain how overloaded operators are implemented. However,
they do not apply to the new and delete operators, which are covered separately.
You cannot redefine the meaning of operators when applied to built-in data types.
C++
// rules_for_operator_overloading.cpp
class Point
{
public:
Point operator<( Point & ); // Declare a member operator
// overload.
// Declare addition operators.
friend Point operator+( Point&, int );
friend Point operator+( int, Point& );
};
int main()
{
}
The preceding code sample declares the less-than operator as a member function;
however, the addition operators are declared as global functions that have friend
access. Note that more than one implementation can be provided for a given
operator. In the case of the preceding addition operator, the two implementations
are provided to facilitate commutativity. It is just as likely that operators that add a
Point to a Point , int to a Point , and so on, might be implemented.
If an operator can be used as either a unary or a binary operator (&, *, +, and -),
you can overload each use separately.
Note that the meaning of any of the operators can be changed completely. That
includes the meaning of the address-of (&), assignment (=), and function-call operators.
Also, identities that can be relied upon for built-in types can be changed using operator
overloading. For example, the following four statements are usually equivalent when
completely evaluated:
C++
var = var + 1;
var += 1;
var++;
++var;
This identity cannot be relied upon for class types that overload operators. Moreover,
some of the requirements implicit in the use of these operators for basic types are
relaxed for overloaded operators. For example, the addition/assignment operator, +=,
requires the left operand to be an l-value when applied to basic types; there is no such
requirement when the operator is overloaded.
7 Note
For consistency, it is often best to follow the model of the built-in types when
defining overloaded operators. If the semantics of an overloaded operator differ
significantly from its meaning in other contexts, it can be more confusing than
useful.
See also
Operator Overloading
Overloading unary operators
Article • 07/11/2022 • 2 minutes to read
Unary operators produce a result from a single operand. You can define overloads of a
standard set of unary operators to work on user-defined types.
! (logical NOT)
& (address-of)
~ (complement)
* (pointer dereference)
+ (unary plus)
- (unary negation)
Conversion operators
The following rules apply to all prefix unary operators. To declare a unary operator
function as a non-static member function, use this declaration form:
In this form, return-type is the return type, op is one of the operators listed in the
preceding table, and class-type is the class type of the argument on which to operate.
The postfix forms of ++ and -- take an extra int argument to distinguish them from
the prefix forms. For more information about the prefix and postfix forms of ++ and -- ,
see Increment and decrement operator overloading.
7 Note
There's no restriction on the return types of the unary operators. For example, it
makes sense for logical NOT ( ! ) to return a bool value, but this behavior isn't
enforced.
See also
Operator overloading
Increment and Decrement Operator
Overloading (C++)
Article • 08/10/2021 • 2 minutes to read
The increment and decrement operators fall into a special category because there are
two variants of each:
When you write overloaded operator functions, it can be useful to implement separate
versions for the prefix and postfix versions of these operators. To distinguish between
the two, the following rule is observed: The prefix form of the operator is declared
exactly the same way as any other unary operator; the postfix form accepts an extra
argument of type int .
7 Note
When specifying an overloaded operator for the postfix form of the increment or
decrement operator, the additional argument must be of type int ; specifying any
other type generates an error.
The following example shows how to define prefix and postfix increment and decrement
operators for the Point class:
C++
// increment_and_decrement1.cpp
class Point
{
public:
// Declare prefix and postfix increment operators.
Point& operator++(); // Prefix increment operator.
Point operator++(int); // Postfix increment operator.
int main()
{
}
The same operators can be defined in file scope (globally) using the following function
prototypes:
C++
C++
// increment_and_decrement2.cpp
class Int
{
public:
Int operator++( int n ); // Postfix increment operator
private:
int _i;
};
int main()
{
Int i;
i.operator++( 25 ); // Increment by 25.
}
There's no syntax for using the increment or decrement operators to pass these values
other than explicit invocation, as shown in the preceding code. A more straightforward
way to implement this functionality is to overload the addition/assignment operator
(+=).
See also
Operator Overloading
Binary Operators
Article • 02/17/2022 • 2 minutes to read
, Comma
!= Inequality
% Modulus
%= Modulus/assignment
* Multiplication
*= Multiplication/assignment
+ Addition
+= Addition/assignment
- Subtraction
-= Subtraction/assignment
/ Division
/= Division/assignment
= Assignment
== Equality
^ Exclusive OR
^= Exclusive OR/assignment
| Bitwise inclusive OR
|| Logical OR
To declare a binary operator function as a nonstatic member, you must declare it in the
form:
where ret-type is the return type, op is one of the operators listed in the preceding table,
and arg is an argument of any type.
To declare a binary operator function as a global function, you must declare it in the
form:
where ret-type and op are as described for member operator functions and arg1 and
arg2 are arguments. At least one of the arguments must be of class type.
7 Note
There is no restriction on the return types of the binary operators; however, most
user-defined binary operators return either a class type or a reference to a class
type.
See also
Operator Overloading
Assignment
Article • 08/03/2021 • 2 minutes to read
The assignment operator (=) is, strictly speaking, a binary operator. Its declaration is
identical to any other binary operator, with the following exceptions:
C++
class Point
{
public:
int _x, _y;
int main()
{
Point pt1, pt2;
pt1 = pt2;
}
The supplied argument is the right side of the expression. The operator returns the
object to preserve the behavior of the assignment operator, which returns the value of
the left side after the assignment is complete. This allows chaining of assignments, such
as:
C++
pt1 = pt2 = pt3;
The copy assignment operator is not to be confused with the copy constructor. The
latter is called during the construction of a new object from an existing one:
C++
7 Note
It is advisable to follow the rule of three that a class which defines a copy
assignment operator should also explicitly define copy constructor, destructor, and,
starting with C++11, move constructor and move assignment operator.
See also
Operator Overloading
Copy Constructors and Copy Assignment Operators (C++)
Function Call (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
primary-expression ( expression-list )
Remarks
In this context, primary-expression is the first operand, and expression-list , a possibly
empty list of arguments, is the second operand. The function-call operator is used for
operations that require a number of parameters. This works because expression-list is
a list instead of a single operand. The function-call operator must be a nonstatic
member function.
The function-call operator, when overloaded, does not modify how functions are called;
rather, it modifies how the operator is to be interpreted when applied to objects of a
given class type. For example, the following code would usually be meaningless:
C++
Point pt;
pt( 3, 2 );
C++
// function_call.cpp
class Point
{
public:
Point() { _x = _y = 0; }
Point &operator()( int dx, int dy )
{ _x += dx; _y += dy; return *this; }
private:
int _x, _y;
};
int main()
{
Point pt;
pt( 3, 2 );
}
Note that the function-call operator is applied to the name of an object, not the name
of a function.
You can also overload the function call operator using a pointer to a function (rather
than the function itself).
C++
typedef void(*ptf)();
void func()
{
}
struct S
{
operator ptf()
{
return func;
}
};
int main()
{
S s;
s();//operates as s.operator ptf()()
}
See also
Operator Overloading
Subscripting
Article • 08/03/2021 • 2 minutes to read
The subscript operator ([ ]), like the function-call operator, is considered a binary
operator. The subscript operator must be a nonstatic member function that takes a
single argument. This argument can be of any type and designates the desired array
subscript.
Example
The following example demonstrates how to create a vector of type int that
implements bounds checking:
C++
// subscripting.cpp
// compile with: /EHsc
#include <iostream>
// Construct an IntVector.
IntVector::IntVector( int cElements ) {
_iElements = new int[cElements];
_iUpperBound = cElements;
}
v[3] = v[9];
Output
Comments
When i reaches 10 in the preceding program, operator[] detects that an out-of-bounds
subscript is being used and issues an error message.
Note that the function operator[] returns a reference type. This causes it to be an l-
value, allowing you to use subscripted expressions on either side of assignment
operators.
See also
Operator Overloading
Member Access
Article • 08/03/2021 • 2 minutes to read
Class member access can be controlled by overloading the member access operator (-
>). This operator is considered a unary operator in this usage, and the overloaded
operator function must be a class member function. Therefore, the declaration for such
a function is:
Syntax
class-type *operator->()
Remarks
where class-type is the name of the class to which this operator belongs. The member
access operator function must be a nonstatic member function.
See also
Operator Overloading
Classes and Structs (C++)
Article • 08/03/2021 • 2 minutes to read
This section introduces C++ classes and structs. The two constructs are identical in C++
except that in structs the default accessibility is public, whereas in classes the default is
private.
Classes and structs are the constructs whereby you define your own types. Classes and
structs can both contain data members and member functions, which enable you to
describe the type's state and behavior.
class
struct
Inheritance
Static Members
Pointers to Members
this Pointer
The three class types are structure, class, and union. They are declared using the struct,
class, and union keywords. The following table shows the differences among the three
class types.
For more information on unions, see Unions. For information on classes and structs in
C++/CLI and C++/CX, see Classes and Structs.
Access Control and Constraints of Structures, Classes and
Unions
See also
C++ Language Reference
class (C++)
Article • 08/03/2021 • 2 minutes to read
The class keyword declares a class type or defines an object of a class type.
Syntax
[template-spec]
class [ms-decl-spec] [tag [: base-list ]]
{
member-list
} [declarators];
[ class ] tag declarators;
Parameters
template-spec
Optional template specifications. For more information, refer to Templates.
class
The class keyword.
ms-decl-spec
Optional storage-class specification. For more information, refer to the __declspec
keyword.
tag
The type name given to the class. The tag becomes a reserved word within the scope of
the class. The tag is optional. If omitted, an anonymous class is defined. For more
information, see Anonymous Class Types.
base-list
Optional list of classes or structures this class will derive its members from. See Base
Classes for more information. Each base class or structure name can be preceded by an
access specifier (public, private, protected) and the virtual keyword. See the member-
access table in Controlling Access to Class Members for more information.
member-list
List of class members. Refer to Class Member Overview for more information.
declarators
Declarator list specifying the names of one or more instances of the class type.
Declarators may include initializer lists if all data members of the class are public . This is
more common in structures, whose data members are public by default, than in classes.
See Overview of Declarators for more information.
Remarks
For more information on classes in general, refer to one of the following topics:
struct
union
__multiple_inheritance
__single_inheritance
__virtual_inheritance
For information on managed classes and structs in C++/CLI and C++/CX, see Classes
and Structs
Example
C++
// class.cpp
// compile with: /EHsc
// Example of the class keyword
// Exhibits polymorphism/virtual functions.
#include <iostream>
#include <string>
using namespace std;
class dog
{
public:
dog()
{
_legs = 4;
_bark = true;
}
private:
string _dogSize, _earType;
int _legs;
bool _bark;
};
string getColor()
{
return _color;
}
protected:
string _color, _earLength, _earType;
};
int main()
{
dog mongrel;
breed labrador("yellow", "large");
mongrel.setEars("pointy");
labrador.setEars("long", "floppy");
cout << "Cody is a " << labrador.getColor() << " labrador" << endl;
}
See also
Keywords
Classes and Structs
struct (C++)
Article • 08/03/2021 • 2 minutes to read
The struct keyword defines a structure type and/or a variable of a structure type.
Syntax
Parameters
template-spec
Optional template specifications. For more information, refer to Template Specifications.
struct
The struct keyword.
ms-decl-spec
Optional storage-class specification. For more information, refer to the __declspec
keyword.
tag
The type name given to the structure. The tag becomes a reserved word within the
scope of the structure. The tag is optional. If omitted, an anonymous structure is
defined. For more information, see Anonymous Class Types.
base-list
Optional list of classes or structures this structure will derive its members from. See Base
Classes for more information. Each base class or structure name can be preceded by an
access specifier (public, private, protected) and the virtual keyword. See the member-
access table in Controlling Access to Class Members for more information.
member-list
List of structure members. Refer to Class Member Overview for more information. The
only difference here is that struct is used in place of class .
declarators
Declarator list specifying the names of the structure. Declarator lists declare one or more
instances of the structure type. Declarators may include initializer lists if all data
members of the structure are public . Initializer lists are common in structures because
data members are public by default. See Overview of Declarators for more information.
Remarks
A structure type is a user-defined composite type. It is composed of fields or members
that can have different types.
In C++, a structure is the same as a class except that its members are public by default.
For information on managed classes and structs in C++/CLI, see Classes and Structs.
Using a Structure
In C, you must explicitly use the struct keyword to declare a structure. In C++, you do
not need to use the struct keyword after the type has been defined.
You have the option of declaring variables when the structure type is defined by placing
one or more comma-separated variable names between the closing brace and the
semicolon.
Structure variables can be initialized. The initialization for each variable must be
enclosed in braces.
Example
C++
#include <iostream>
using namespace std;
int main() {
struct PERSON sister; // C style structure declaration
PERSON brother; // C++ style structure declaration
sister.age = 13; // assign values to members
brother.age = 7;
cout << "sister.age = " << sister.age << '\n';
cout << "brother.age = " << brother.age << '\n';
CELL my_cell;
my_cell.character = 1;
cout << "my_cell.character = " << my_cell.character;
}
// Output:
// sister.age = 13
// brother.age = 7
// my_cell.character = 1
Class member overview
Article • 07/04/2022 • 3 minutes to read
A class or struct consists of its members. The work that a class does is performed by
its member functions. The state that it maintains is stored in its data members.
Initialization of members is done by constructors, and cleanup work such as freeing of
memory and releasing of resources is done by destructors. In C++11 and later, data
members can (and usually should) be initialized at the point of declaration.
Mutable and static data members, including built-in types and other user defined
types.
Operators
Unions
Enumerations.
Bit fields.
Friends.
7 Note
Friends are included in the preceding list because they are contained in the
class declaration. However, they are not true class members, because they are
not in the scope of the class.
C++
// TestRun.h
class TestRun
{
// Start member list.
Member accessibility
The members of a class are declared in the member list. The member list of a class may
be divided into any number of private , protected and public sections using keywords
known as access specifiers. A colon : must follow the access specifier. These sections
don't have to be contiguous; that is, any of these keywords may appear several times in
the member list. The keyword designates the access of all members up until the next
access specifier or the closing brace. For more information, see Member access control
(C++).
Static members
A data member may be declared as static, which means all objects of the class have
access to the same copy of it. A member function may be declared as static, in which
case it can only access static data members of the class (and has no this pointer). For
more information, see Static Data Members.
Default constructor
Copy constructor
Destructor
Member-wise initialization
In C++11 and later, non-static member declarators can contain initializers.
C++
class CanInit
{
public:
long num {7}; // OK in C++11
int k = 9; // OK in C++11
static int i = 9; // Error: must be defined and initialized
// outside of class declaration.
There's only one shared copy of static data members for all objects of a given class type.
Static data members must be defined and can be initialized at file scope. For more
information about static data members, see Static data members. The following example
shows how to initialize static data members:
C++
// class_members2.cpp
class CanInit2
{
public:
CanInit2() {} // Initializes num to 7 when new objects of type
// CanInit are created.
long num {7};
static int i;
static int j;
};
// At file scope:
7 Note
The class name, CanInit2 , must precede i to specify that the i being defined is a
member of class CanInit2 .
See also
Classes and Structs
Member Access Control (C++)
Article • 04/04/2023 • 6 minutes to read
Access controls enable you to separate the public interface of a class from the private
implementation details and the protected members that are only for use by derived
classes. The access specifier applies to all members declared after it until the next access
specifier is encountered.
C++
class Point
{
public:
Point( int, int ) // Declare public constructor.;
Point();// Declare public default constructor.
int &x( int ); // Declare public accessor.
int &y( int ); // Declare public accessor.
The default access is private in a class, and public in a struct or union. Access
specifiers in a class can be used any number of times in any order. The allocation of
storage for objects of class types is implementation-dependent. However, compilers
must guarantee assignment of members to successively higher memory addresses
between access specifiers.
Member-Access Control
Type of Meaning
Access
private Class members declared as private can be used only by member functions and
friends (classes or functions) of the class.
protected Class members declared as protected can be used by member functions and friends
(classes or functions) of the class. Additionally, they can be used by classes derived
from the class.
7 Note
Access control is equally applicable to all names: member functions, member data,
nested classes, and enumerators.
Whether the derived class declares the base class using the public access
specifier.
The following table shows the interaction between these factors and how to determine
base-class member access.
Always inaccessible with private in derived class if you private in derived class if you
any derivation access use private derivation use private derivation
C++
// access_specifiers_for_base_classes.cpp
class BaseClass
{
public:
int PublicFunc(); // Declare a public member.
protected:
int ProtectedFunc(); // Declare a protected member.
private:
int PrivateFunc(); // Declare a private member.
};
int main()
{
DerivedClass1 derived_class1;
DerivedClass2 derived_class2;
derived_class1.PublicFunc();
derived_class2.PublicFunc(); // function is inaccessible
}
You can declare a derived class without a base-class access specifier. In such a case, the
derivation is considered private if the derived class declaration uses the class
keyword. The derivation is considered public if the derived class declaration uses the
struct keyword. For example, the following code:
C++
class Derived : Base
...
is equivalent to:
C++
C++
is equivalent to:
C++
7 Note
When specifying a private base class, it is advisable to explicitly use the private
keyword so users of the derived class understand the member access.
// access_control.cpp
class Base
{
public:
int Print(); // Nonstatic member.
static int CountOf(); // Static member.
};
In the preceding code, access control prohibits conversion from a pointer to Derived2 to
a pointer to Base . The this pointer is implicitly of type Derived2 * . To select the
CountOf function, this must be converted to type Base * . Such a conversion isn't
permitted because Base is a private indirect base class to Derived2 . Conversion to a
private base class type is acceptable only for pointers to immediate derived classes.
That's why pointers of type Derived1 * can be converted to type Base * .
An explicit call to the CountOf function, without using a pointer, reference, or object to
select it, implies no conversion. That's why the call is allowed.
C++
// access_to_virtual_functions.cpp
class VFuncBase
{
public:
virtual int GetState() { return _state; }
protected:
int _state;
};
int main()
{
VFuncDerived vfd; // Object of derived type.
VFuncBase *pvfb = &vfd; // Pointer to base type.
VFuncDerived *pvfd = &vfd; // Pointer to derived type.
int State;
In the preceding example, calling the virtual function GetState using a pointer to type
VFuncBase calls VFuncDerived::GetState , and GetState is treated as public . However,
U Caution
The virtual function GetState can be called using a pointer to the base class
VFuncBase . This doesn't mean that the function called is the base-class version of
that function.
Access control with multiple inheritance
In multiple-inheritance lattices involving virtual base classes, a given name can be
reached through more than one path. Because different access control can be applied
along these different paths, the compiler chooses the path that gives the most access.
See the following figure:
In the figure, a name declared in class VBase is always reached through class RightPath .
The right path is more accessible because RightPath declares VBase as a public base
class, while LeftPath declares VBase as private .
See also
C++ Language Reference
friend (C++)
Article • 07/01/2022 • 5 minutes to read
In some circumstances, it's useful for a class to grant member-level access to functions
that aren't members of the class, or to all members in a separate class. These free
functions and classes are known as friends, marked by the friend keyword. Only the
class implementer can declare who its friends are. A function or class can't declare itself
as a friend of any class. In a class definition, use the friend keyword and the name of a
non-member function or other class to grant it access to the private and protected
members of your class. In a template definition, a type parameter can be declared as a
friend .
Syntax
friend-declaration :
friend function-declaration
friend function-definition
friend elaborated-type-specifier ; ;
friend simple-type-specifier ;
friend typename-specifier ;
friend declarations
If you declare a friend function that wasn't previously declared, that function is
exported to the enclosing nonclass scope.
Functions declared in a friend declaration are treated as if they had been declared
using the extern keyword. For more information, see extern.
Although functions with global scope can be declared as friend functions prior to their
prototypes, member functions can't be declared as friend functions before the
appearance of their complete class declaration. The following code shows how such a
declaration fails:
C++
The preceding example enters the class name ForwardDeclared into scope, but the
complete declaration (specifically, the portion that declares the function IsAFriend ) isn't
known. the friend declaration in class HasFriends generates an error.
C++
friend class F;
friend F;
The first form introduces a new class F if no existing class by that name was found in the
innermost namespace. C++11: The second form doesn't introduce a new class; it can be
used when the class has already been declared, and it must be used when declaring a
template type parameter or a typedef as a friend .
Use friend class F when the referenced type hasn't been declared yet:
C++
namespace NS
{
class M
{
friend class F; // Introduces F but doesn't define it
};
}
An error occurs if you use friend with a class type that hasn't been declared:
C++
namespace NS
{
class M
{
friend F; // error C2433: 'NS::F': 'friend' not permitted on data
declarations
};
}
In the following example, friend F refers to the F class that is declared outside the
scope of NS.
C++
class F {};
namespace NS
{
class M
{
friend F; // OK
};
}
C++
C++
class G
{
friend F; // OK
friend class F // Error C2371 -- redefinition
};
To declare two classes that are friends of one another, the entire second class must be
specified as a friend of the first class. The reason for this restriction is that the compiler
has enough information to declare individual friend functions only at the point where
the second class is declared.
7 Note
Although the entire second class must be a friend to the first class, you can select
which functions in the first class will be friends of the second class.
friend functions
A friend function is a function that isn't a member of a class but has access to the
class's private and protected members. Friend functions aren't considered class
members; they're normal external functions that are given special access privileges.
Friends aren't in the class's scope, and they aren't called using the member-selection
operators (. and ->) unless they're members of another class. A friend function is
declared by the class that is granting access. The friend declaration can be placed
anywhere in the class declaration. It isn't affected by the access control keywords.
The following example shows a Point class and a friend function, ChangePrivate . The
friend function has access to the private data member of the Point object it receives
as a parameter.
C++
// friend_functions.cpp
// compile with: /EHsc
#include <iostream>
private:
int m_i;
};
int main()
{
Point sPoint;
sPoint.PrintPrivate();
ChangePrivate(sPoint);
sPoint.PrintPrivate();
// Output: 0
1
}
C++
// classes_as_friends1.cpp
// compile with: /c
class B;
class A {
public:
int Func1( B& b );
private:
int Func2( B& b );
};
class B {
private:
int _b;
In the preceding example, only the function A::Func1( B& ) is granted friend access to
class B . Therefore, access to the private member _b is correct in Func1 of class A but
not in Func2 .
A friend class is a class all of whose member functions are friend functions of a class,
that is, whose member functions have access to the other class's private and protected
members. Suppose the friend declaration in class B had been:
C++
friend class A;
In that case, all member functions in class A would have been granted friend access to
class B . The following code is an example of a friend class:
C++
// classes_as_friends2.cpp
// compile with: /EHsc
#include <iostream>
class YourOtherClass {
public:
void change( YourClass& yc, int x ){yc.topSecret = x;}
};
int main() {
YourClass yc1;
YourOtherClass yoc1;
yc1.printMember();
yoc1.change( yc1, 5 );
yc1.printMember();
}
Friendship isn't mutual unless explicitly specified as such. In the above example, member
functions of YourClass can't access the private members of YourOtherClass .
A managed type (in C++/CLI) can't have any friend functions, friend classes, or
friend interfaces.
Friendship isn't inherited, meaning that classes derived from YourOtherClass can't
access YourClass 's private members. Friendship isn't transitive, so classes that are
friends of YourOtherClass can't access YourClass 's private members.
The following figure shows four class declarations: Base , Derived , aFriend , and
anotherFriend . Only class aFriend has direct access to the private members of Base
See also
Keywords
private (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
private:
[member-list]
private base-class
Remarks
When preceding a list of class members, the private keyword specifies that those
members are accessible only from member functions and friends of the class. This
applies to all members declared up to the next access specifier or the end of the class.
When preceding the name of a base class, the private keyword specifies that the public
and protected members of the base class are private members of the derived class.
Default access of a base class is private for classes and public for structures. Unions
cannot have base classes.
For related information, see friend, public, protected, and the member-access table in
Controlling Access to Class Members.
/clr Specific
In CLR types, the C++ access specifier keywords ( public , private , and protected ) can
affect the visibility of types and methods with regard to assemblies. For more
information, see Member Access Control.
7 Note
Files compiled with /LN are not affected by this behavior. In this case, all managed
classes (either public or private) will be visible.
END /clr Specific
Example
C++
// keyword_private.cpp
class BaseClass {
public:
// privMem accessible from member function
int pubFunc() { return privMem; }
private:
void privMem;
};
int main() {
BaseClass aBase;
DerivedClass aDerived;
DerivedClass2 aDerived2;
aBase.privMem = 1; // C2248: privMem not accessible
aDerived.privMem = 1; // C2248: privMem not accessible
// in derived class
aDerived2.pubFunc(); // C2247: pubFunc() is private in
// derived class
}
See also
Controlling Access to Class Members
Keywords
protected (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
protected:
[member-list]
protected base-class
Remarks
The protected keyword specifies access to class members in the member-list up to the
next access specifier ( public or private ) or the end of the class definition. Class
members declared as protected can be used only by the following:
Classes derived with public or protected access from the class that originally
declared these members.
Direct privately derived classes that also have private access to protected
members.
When preceding the name of a base class, the protected keyword specifies that the
public and protected members of the base class are protected members of its derived
classes.
Protected members are not as private as private members, which are accessible only to
members of the class in which they are declared, but they are not as public as public
members, which are accessible in any function.
Protected members that are also declared as static are accessible to any friend or
member function of a derived class. Protected members that are not declared as static
are accessible to friends and member functions in a derived class only through a pointer
to, reference to, or object of the derived class.
For related information, see friend, public, private, and the member-access table in
Controlling Access to Class Members.
/clr Specific
In CLR types, the C++ access specifier keywords ( public , private , and protected ) can
affect the visibility of types and methods with regard to assemblies. For more
information, see Member Access Control.
7 Note
Files compiled with /LN are not affected by this behavior. In this case, all managed
classes (either public or private) will be visible.
Example
C++
// keyword_protected.cpp
// compile with: /EHsc
#include <iostream>
class Y : public X {
public:
void useProtfunc() { Protfunc(); }
} y;
int main() {
// x.m_protMemb; error, m_protMemb is protected
x.setProtMemb( 0 ); // OK, uses public access function
x.Display();
y.setProtMemb( 5 ); // OK, uses public access function
y.Display();
// x.Protfunc(); error, Protfunc() is protected
y.useProtfunc(); // OK, uses public access function
// in derived class
}
See also
Controlling Access to Class Members
Keywords
public (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
public:
[member-list]
public base-class
Remarks
When preceding a list of class members, the public keyword specifies that those
members are accessible from any function. This applies to all members declared up to
the next access specifier or the end of the class.
When preceding the name of a base class, the public keyword specifies that the public
and protected members of the base class are public and protected members,
respectively, of the derived class.
Default access of a base class is private for classes and public for structures. Unions
cannot have base classes.
For more information, see private, protected, friend, and the member-access table in
Controlling Access to Class Members.
/clr Specific
In CLR types, the C++ access specifier keywords ( public , private , and protected ) can
affect the visibility of types and methods with regard to assemblies. For more
information, see Member Access Control.
7 Note
Files compiled with /LN are not affected by this behavior. In this case, all managed
classes (either public or private) will be visible.
END /clr Specific
Example
C++
// keyword_public.cpp
class BaseClass {
public:
int pubFunc() { return 0; }
};
int main() {
BaseClass aBase;
DerivedClass aDerived;
aBase.pubFunc(); // pubFunc() is accessible
// from any function
aDerived.pubFunc(); // pubFunc() is still public in
// derived class
}
See also
Controlling Access to Class Members
Keywords
Brace initialization
Article • 09/08/2022 • 3 minutes to read
It isn't always necessary to define a constructor for a class , especially ones that are
relatively simple. Users can initialize objects of a class or struct by using uniform
initialization, as shown in the following example:
C++
// no_constructor.cpp
// Compile with: cl /EHsc no_constructor.cpp
#include <time.h>
// No constructor
struct TempData
{
int StationId;
time_t timeSet;
double current;
double maxTemp;
double minTemp;
};
// Has a constructor
struct TempData2
{
TempData2(double minimum, double maximum, double cur, int id, time_t t)
:
stationId{id}, timeSet{t}, current{cur}, maxTemp{maximum},
minTemp{minimum} {}
int stationId;
time_t timeSet;
double current;
double maxTemp;
double minTemp;
};
int main()
{
time_t time_to_set;
return 0;
}
When a class or struct has no constructor, you provide the list elements in the order
that the members are declared in the class . If the class has a constructor, provide the
elements in the order of the parameters. If a type has a default constructor, either
implicitly or explicitly declared, you can use brace initialization with empty braces to
invoke it. For example, the following class may be initialized by using both empty and
non-empty brace initialization:
C++
#include <string>
using namespace std;
class class_a {
public:
class_a() {}
class_a(string str) : m_string{ str } {}
class_a(string str, double dbl) : m_string{ str }, m_double{ dbl } {}
double m_double;
string m_string;
};
int main()
{
class_a c1{};
class_a c1_1;
If a class has non-default constructors, the order in which class members appear in the
brace initializer is the order in which the corresponding parameters appear in the
constructor, not the order in which the members are declared (as with class_a in the
previous example). Otherwise, if the type has no declared constructor, member
initializers must appear in the brace initializer in the same order as they're declared. In
this case, you can initialize as many of the public members as you wish, but you can't
skip any member. The following example shows the order that's used in brace
initialization when there's no declared constructor:
C++
class class_d {
public:
float m_float;
string m_string;
wchar_t m_char;
};
int main()
{
class_d d1{};
class_d d1{ 4.5 };
class_d d2{ 4.5, "string" };
class_d d3{ 4.5, "string", 'c' };
If the default constructor is explicitly declared but marked as deleted, empty brace
initialization can't be used:
C++
class class_f {
public:
class_f() = delete;
class_f(string x): m_string { x } {}
string m_string;
};
int main()
{
class_f cf{ "hello" };
class_f cf1{}; // compiler error C2280: attempting to reference a
deleted function
}
You can use brace initialization anywhere you would typically do initialization—for
example, as a function parameter or a return value, or with the new keyword:
C++
initializer_list constructors
The initializer_list Class represents a list of objects of a specified type that can be used in
a constructor, and in other contexts. You can construct an initializer_list by using brace
initialization:
C++
) Important
An initializer_list can be copied. In this case, the members of the new list are
references to the members of the original list:
C++
initializer_list<int> ilist1{ 5, 6, 7 };
initializer_list<int> ilist2( ilist1 );
if (ilist1.begin() == ilist2.begin())
cout << "yes" << endl; // expect "yes"
The standard library container classes, and also string , wstring , and regex , have
initializer_list constructors. The following examples show how to do brace
C++
See also
Classes and Structs
Constructors
Object lifetime and resource
management (RAII)
Article • 11/07/2022 • 3 minutes to read
Unlike managed languages, C++ doesn't have automatic garbage collection, an internal
process that releases heap memory and other resources as a program runs. A C++
program is responsible for returning all acquired resources to the operating system.
Failure to release an unused resource is called a leak. Leaked resources are unavailable
to other programs until the process exits. Memory leaks in particular are a common
cause of bugs in C-style programming.
Modern C++ avoids using heap memory as much as possible by declaring objects on
the stack. When a resource is too large for the stack, then it should be owned by an
object. As the object gets initialized, it acquires the resource it owns. The object is then
responsible for releasing the resource in its destructor. The owning object itself is
declared on the stack. The principle that objects own resources is also known as
"resource acquisition is initialization," or RAII.
When a resource-owning stack object goes out of scope, its destructor is automatically
invoked. In this way, garbage collection in C++ is closely related to object lifetime, and
is deterministic. A resource is always released at a known point in the program, which
you can control. Only deterministic destructors like those in C++ can handle memory
and non-memory resources equally.
The following example shows a simple object w . It's declared on the stack at function
scope, and is destroyed at the end of the function block. The object w owns no
resources (such as heap-allocated memory). Its only member g is itself declared on the
stack, and simply goes out of scope along with w . No special code is needed in the
widget destructor.
C++
class widget {
private:
gadget g; // lifetime automatically tied to enclosing object
public:
void draw();
};
void functionUsingWidget () {
widget w; // lifetime automatically tied to enclosing scope
// constructs w, including the w.g gadget member
// ...
w.draw();
// ...
} // automatic destruction and deallocation for w and w.g
// automatic exception safety,
// as if "finally { w.dispose(); w.g.dispose(); }"
In the following example, w owns a memory resource and so must have code in its
destructor to delete the memory.
C++
class widget
{
private:
int* data;
public:
widget(const int size) { data = new int[size]; } // acquire
~widget() { delete[] data; } // release
void do_something() {}
};
void functionUsingWidget() {
widget w(1000000); // lifetime automatically tied to enclosing scope
// constructs w, including the w.data member
w.do_something();
Since C++11, there's a better way to write the previous example: by using a smart
pointer from the standard library. The smart pointer handles the allocation and deletion
of the memory it owns. Using a smart pointer eliminates the need for an explicit
destructor in the widget class.
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
By using smart pointers for memory allocation, you may eliminate the potential for
memory leaks. This model works for other resources, such as file handles or sockets. You
can manage your own resources in a similar way in your classes. For more information,
see Smart pointers.
The design of C++ ensures objects are destroyed when they go out of scope. That is,
they get destroyed as blocks are exited, in reverse order of construction. When an object
is destroyed, its bases and members are destroyed in a particular order. Objects
declared outside of any block, at global scope, can lead to problems. It may be difficult
to debug, if the constructor of a global object throws an exception.
See also
Welcome back to C++
C++ language reference
C++ Standard Library
Pimpl For Compile-Time Encapsulation
(Modern C++)
Article • 08/03/2021 • 2 minutes to read
Portability.
Pimpl header
C++
// my_class.h
class my_class {
// ... all public and protected stuff goes here ...
private:
class impl; unique_ptr<impl> pimpl; // opaque type here
};
The pimpl idiom avoids rebuild cascades and brittle object layouts. It's well suited for
(transitively) popular types.
Pimpl implementation
Define the impl class in the .cpp file.
C++
// my_class.cpp
class my_class::impl { // defined privately here
// ... all private data and functions: all of these
// can now change without recompiling callers ...
};
my_class::my_class(): pimpl( new impl )
{
// ... set impl values ...
}
Best practices
Consider whether to add support for non-throwing swap specialization.
See also
Welcome back to C++
C++ Language Reference
C++ Standard Library
Portability at ABI boundaries
Article • 08/03/2021 • 2 minutes to read
C++
// class widget {
// widget();
// ~widget();
// double method( int, gadget& );
// };
extern "C" { // functions using explicit "this"
struct widget; // opaque type (forward declaration only)
widget* STDCALL widget_create(); // constructor creates new "this"
void STDCALL widget_destroy(widget*); // destructor consumes "this"
double STDCALL widget_method(widget*, int, gadget*); // method uses
"this"
}
See also
Welcome back to C++
C++ Language Reference
C++ Standard Library
Constructors (C++)
Article • 02/08/2022 • 17 minutes to read
To customize how a class initializes its members, or to invoke functions when an object
of your class is created, define a constructor. A constructor has the same name as the
class and no return value. You can define as many overloaded constructors as needed to
customize initialization in various ways. Typically, constructors have public accessibility
so that code outside the class definition or inheritance hierarchy can create objects of
the class. But you can also declare a constructor as protected or private .
Constructors can optionally take a member initializer list. It's a more efficient way to
initialize class members than assigning values in the constructor body. The following
example shows a class Box with three overloaded constructors. The last two use
member init lists:
C++
class Box {
public:
// Default constructor
Box() {}
private:
// Will have value of 0 when default constructor is called.
// If we didn't zero-init here, default constructor would
// leave them uninitialized with garbage values.
int m_width{ 0 };
int m_length{ 0 };
int m_height{ 0 };
};
When you declare an instance of a class, the compiler chooses which constructor to
invoke based on the rules of overload resolution:
C++
int main()
{
Box b; // Calls Box()
Prefer member initializer lists over assigning values in the body of the constructor. A
member initializer list directly initializes the members. The following example shows the
member initializer list, which consists of all the identifier(argument) expressions after
the colon:
C++
The identifier must refer to a class member; it's initialized with the value of the
argument. The argument can be one of the constructor parameters, a function call or a
std::initializer_list<T>.
const members and members of reference type must be initialized in the member
initializer list.
To ensure base classes are fully initialized before the derived constructor runs, call any
parameterized base class constructors in the initializer list.
Default constructors
Default constructors typically have no parameters, but they can have parameters with
default values.
C++
class Box {
public:
Box() { /*perform any required default initialization steps*/}
Default constructors are one of the special member functions. If no constructors are
declared in a class, the compiler provides an implicit inline default constructor.
C++
#include <iostream>
using namespace std;
class Box {
public:
int Volume() {return m_width * m_height * m_length;}
private:
int m_width { 0 };
int m_height { 0 };
int m_length { 0 };
};
int main() {
Box box1; // Invoke compiler-generated constructor
cout << "box1.Volume: " << box1.Volume() << endl; // Outputs 0
}
If you rely on an implicit default constructor, be sure to initialize members in the class
definition, as shown in the previous example. Without those initializers, the members
would be uninitialized and the Volume() call would produce a garbage value. In general,
it's good practice to initialize members in this way even when not relying on an implicit
default constructor.
You can prevent the compiler from generating an implicit default constructor by
defining it as deleted:
C++
// Default constructor
Box() = delete;
When you call a compiler-generated default constructor and try to use parentheses, a
warning is issued:
C++
class myclass{};
int main(){
myclass mc(); // warning C4930: prototyped function not called (was a
variable definition intended?)
}
This statement is an example of the "Most Vexing Parse" problem. You could interpret
myclass md(); either as a function declaration or as the invocation of a default
constructor. Because C++ parsers favor declarations over other things, the expression is
treated as a function declaration. For more information, see Most Vexing Parse .
If any non-default constructors are declared, the compiler doesn't provide a default
constructor:
C++
class Box {
public:
Box(int width, int length, int height)
: m_width(width), m_length(length), m_height(height){}
private:
int m_width;
int m_length;
int m_height;
};
int main(){
If a class has no default constructor, an array of objects of that class can't be constructed
by using square-bracket syntax alone. For example, given the previous code block, an
array of Boxes can't be declared like this:
C++
However, you can use a set of initializer lists to initialize an array of Box objects:
C++
Box boxes[3]{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
Copy constructors
A copy constructor initializes an object by copying the member values from an object of
the same type. If your class members are all simple types such as scalar values, the
compiler-generated copy constructor is sufficient and you don't need to define your
own. If your class requires more complex initialization, then you need to implement a
custom copy constructor. For example, if a class member is a pointer then you need to
define a copy constructor to allocate new memory and copy the values from the other's
pointed-to object. The compiler-generated copy constructor simply copies the pointer,
so that the new pointer still points to the other's memory location.
C++
You can prevent your object from being copied by defining the copy constructor as
deleted:
C++
Attempting to copy the object produces error C2280: attempting to reference a deleted
function.
Move constructors
A move constructor is a special member function that moves ownership of an existing
object's data to a new variable without copying the original data. It takes an rvalue
reference as its first parameter, and any later parameters must have default values.
Move constructors can significantly increase your program's efficiency when passing
around large objects.
C++
Box(Box&& other);
The compiler chooses a move constructor when the object is initialized by another
object of the same type, if the other object is about to be destroyed and no longer
needs its resources. The following example shows one case when a move constructor is
selected by overload resolution. In the constructor that calls get_Box() , the returned
value is an xvalue (eXpiring value). It's not assigned to any variable and is therefore
about to go out of scope. To provide motivation for this example, let's give Box a large
vector of strings that represent its contents. Rather than copying the vector and its
strings, the move constructor "steals" it from the expiring value "box" so that the vector
now belongs to the new object. The call to std::move is all that's needed because both
vector and string classes implement their own move constructors.
C++
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Box {
public:
Box() { std::cout << "default" << std::endl; }
Box(int width, int height, int length)
: m_width(width), m_height(height), m_length(length)
{
std::cout << "int,int,int" << std::endl;
}
Box(Box& other)
: m_width(other.m_width), m_height(other.m_height),
m_length(other.m_length)
{
std::cout << "copy" << std::endl;
}
Box(Box&& other) : m_width(other.m_width), m_height(other.m_height),
m_length(other.m_length)
{
m_contents = std::move(other.m_contents);
std::cout << "move" << std::endl;
}
int Volume() { return m_width * m_height * m_length; }
void Add_Item(string item) { m_contents.push_back(item); }
void Print_Contents()
{
for (const auto& item : m_contents)
{
cout << item << " ";
}
}
private:
int m_width{ 0 };
int m_height{ 0 };
int m_length{ 0 };
vector<string> m_contents;
};
Box get_Box()
{
Box b(5, 10, 18); // "int,int,int"
b.Add_Item("Toupee");
b.Add_Item("Megaphone");
b.Add_Item("Suit");
return b;
}
int main()
{
Box b; // "default"
Box b1(b); // "copy"
Box b2(get_Box()); // "move"
cout << "b2 contents: ";
b2.Print_Contents(); // Prove that we have all the values
char ch;
cin >> ch; // keep window open
return 0;
}
If a class doesn't define a move constructor, the compiler generates an implicit one if
there's no user-declared copy constructor, copy assignment operator, move assignment
operator, or destructor. If no explicit or implicit move constructor is defined, operations
that would otherwise use a move constructor use the copy constructor instead. If a class
declares a move constructor or move assignment operator, the implicitly declared copy
constructor is defined as deleted.
An implicitly declared move constructor is defined as deleted if any members that are
class types lack a destructor or if the compiler can't determine which constructor to use
for the move operation.
For more information about how to write a non-trivial move constructor, see Move
Constructors and Move Assignment Operators (C++).
C++
class Box2
{
public:
Box2() = delete;
Box2(const Box2& other) = default;
Box2& operator=(const Box2& other) = default;
Box2(Box2&& other) = default;
Box2& operator=(Box2&& other) = default;
//...
};
constexpr constructors
A constructor may be declared as constexpr if
it's either declared as defaulted or else it satisfies all the conditions for constexpr
functions in general;
the class has no virtual base classes;
each of the parameters is a literal type;
the body isn't a function try-block;
all non-static data members and base class subobjects are initialized;
if the class is (a) a union having variant members, or (b) has anonymous unions,
only one of the union members is initialized;
every non-static data member of class type, and all base-class subobjects have a
constexpr constructor
C++
C++
Explicit constructors
If a class has a constructor with a single parameter, or if all parameters except one have
a default value, the parameter type can be implicitly converted to the class type. For
example, if the Box class has a constructor like this:
C++
C++
Box b = 42;
C++
class ShippingOrder
{
public:
ShippingOrder(Box b, double postage) : m_box(b), m_postage(postage){}
private:
Box m_box;
double m_postage;
}
//elsewhere...
ShippingOrder so(42, 10.8);
Such conversions can be useful in some cases, but more often they can lead to subtle
but serious errors in your code. As a general rule, you should use the explicit keyword
on a constructor (and user-defined operators) to prevent this kind of implicit type
conversion:
C++
When the constructor is explicit, this line causes a compiler error: ShippingOrder so(42,
10.8); . For more information, see User-Defined Type Conversions.
Order of construction
A constructor performs its work in this order:
2. If the class is derived from virtual base classes, it initializes the object's virtual base
pointers.
3. If the class has or inherits virtual functions, it initializes the object's virtual function
pointers. Virtual function pointers point to the class's virtual function table to
enable correct binding of virtual function calls to code.
The following example shows the order in which base class and member constructors
are called in the constructor for a derived class. First, the base constructor is called.
Then, the base-class members are initialized in the order in which they appear in the
class declaration. Finally, the derived constructor is called.
C++
#include <iostream>
class Contained1 {
public:
Contained1() { cout << "Contained1 ctor\n"; }
};
class Contained2 {
public:
Contained2() { cout << "Contained2 ctor\n"; }
};
class Contained3 {
public:
Contained3() { cout << "Contained3 ctor\n"; }
};
class BaseContainer {
public:
BaseContainer() { cout << "BaseContainer ctor\n"; }
private:
Contained1 c1;
Contained2 c2;
};
int main() {
DerivedContainer dc;
}
Here's the output:
Output
Contained1 ctor
Contained2 ctor
BaseContainer ctor
Contained3 ctor
DerivedContainer ctor
A derived class constructor always calls a base class constructor, so that it can rely on
completely constructed base classes before any extra work is done. The base class
constructors are called in order of derivation—for example, if ClassA is derived from
ClassB , which is derived from ClassC , the ClassC constructor is called first, then the
If a base class doesn't have a default constructor, you must supply the base class
constructor parameters in the derived class constructor:
C++
class Box {
public:
Box(int width, int length, int height){
m_width = width;
m_length = length;
m_height = height;
}
private:
int m_width;
int m_length;
int m_height;
};
int main(){
2. Base class and member objects are destroyed, in the reverse order of declaration.
3. If the constructor is non-delegating, all fully constructed base class objects and
members are destroyed. However, because the object itself isn't fully constructed,
the destructor isn't run.
C++
struct Derived;
struct Base {
friend struct Derived;
private:
Base() {}
};
In C++17, Derived is now considered an aggregate type. It means that the initialization
of Base via the private default constructor happens directly, as part of the extended
aggregate initialization rule. Previously, the Base private constructor was called via the
Derived constructor, and it succeeded because of the friend declaration.
The following example shows C++17 behavior in Visual Studio 2017 and later in
/std:c++17 mode:
C++
struct Derived;
struct Base {
friend struct Derived;
private:
Base() {}
};
C++
#include <iostream>
using namespace std;
class BaseClass1 {
public:
BaseClass1() { cout << "BaseClass1 ctor\n"; }
};
class BaseClass2 {
public:
BaseClass2() { cout << "BaseClass2 ctor\n"; }
};
class BaseClass3 {
public:
BaseClass3() { cout << "BaseClass3 ctor\n"; }
};
class DerivedClass : public BaseClass1,
public BaseClass2,
public BaseClass3
{
public:
DerivedClass() { cout << "DerivedClass ctor\n"; }
};
int main() {
DerivedClass dc;
}
Output
BaseClass1 ctor
BaseClass2 ctor
BaseClass3 ctor
DerivedClass ctor
Delegating constructors
A delegating constructor calls a different constructor in the same class to do some of the
work of initialization. This feature is useful when you have multiple constructors that all
have to perform similar work. You can write the main logic in one constructor and
invoke it from others. In the following trivial example, Box(int) delegates its work to
Box(int,int,int):
C++
class Box {
public:
// Default constructor
Box() {}
The object created by the constructors is fully initialized as soon as any constructor is
finished. For more information, see Delegating Constructors.
#include <iostream>
using namespace std;
class Base
{
public:
Base() { cout << "Base()" << endl; }
Base(const Base& other) { cout << "Base(Base&)" << endl; }
explicit Base(int i) : num(i) { cout << "Base(int)" << endl; }
explicit Base(char c) : letter(c) { cout << "Base(char)" << endl; }
private:
int num;
char letter;
};
private:
// Can't initialize newMember from Base constructors.
int newMember{ 0 };
};
int main()
{
cout << "Derived d1(5) calls: ";
Derived d1(5);
cout << "Derived d1('c') calls: ";
Derived d2('c');
cout << "Derived d3 = d2 calls: " ;
Derived d3 = d2;
cout << "Derived d4 calls: ";
Derived d4;
}
/* Output:
Derived d1(5) calls: Base(int)
Derived d1('c') calls: Base(char)
Derived d3 = d2 calls: Base(Base&)
Derived d4 calls: Base()*/
Visual Studio 2017 and later: The using statement in /std:c++17 mode and later brings
into scope all constructors from the base class except ones that have an identical
signature to constructors in the derived class. In general, it's best to use inheriting
constructors when the derived class declares no new data members or constructors.
A class template can inherit all the constructors from a type argument if that type
specifies a base class:
C++
A deriving class can't inherit from multiple base classes if those base classes have
constructors that have an identical signature.
C++
class Label {
public:
Label(const string& name, const string& address) { m_name = name;
m_address = address; }
string m_name;
string m_address;
};
int main(){
// passing a named Label
Label label1{ "some_name", "some_address" };
StorageBox sb1(1, 2, 3, label1);
// passing a temporary label
StorageBox sb2(3, 4, 5, Label{ "another name", "another address" });
In this section
Copy constructors and copy assignment operators
Move constructors and move assignment operators
Delegating constructors
See also
Classes and structs
Copy constructors and copy assignment
operators (C++)
Article • 02/15/2022 • 2 minutes to read
7 Note
Starting in C++11, two kinds of assignment are supported in the language: copy
assignment and move assignment. In this article "assignment" means copy
assignment unless explicitly stated otherwise. For information about move
assignment, see Move Constructors and Move Assignment Operators (C++).
Both the assignment operation and the initialization operation cause objects to be
copied.
Assignment: When one object's value is assigned to another object, the first object
is copied to the second object. So, this code copies the value of b into a :
C++
Point a, b;
...
a = b;
Initialization: Initialization occurs when you declare a new object, when you pass
function arguments by value, or when you return by value from a function.
You can define the semantics of "copy" for objects of class type. For example, consider
this code:
C++
TextFile a, b;
a.Open( "FILE1.DAT" );
b.Open( "FILE2.DAT" );
b = a;
The preceding code could mean "copy the contents of FILE1.DAT to FILE2.DAT" or it
could mean "ignore FILE2.DAT and make b a second handle to FILE1.DAT." You must
attach appropriate copying semantics to each class, as follows:
Use an assignment operator operator= that returns a reference to the class type
and takes one parameter that's passed by const reference—for example
ClassName& operator=(const ClassName& x); .
If you don't declare a copy constructor, the compiler generates a member-wise copy
constructor for you. Similarly, if you don't declare a copy assignment operator, the
compiler generates a member-wise copy assignment operator for you. Declaring a copy
constructor doesn't suppress the compiler-generated copy assignment operator, and
vice-versa. If you implement either one, we recommend that you implement the other
one, too. When you implement both, the meaning of the code is clear.
The copy constructor takes an argument of type ClassName& , where ClassName is the
name of the class. For example:
C++
// spec1_copying_class_objects.cpp
class Window
{
public:
Window( const Window& ); // Declare copy constructor.
Window& operator=(const Window& x); // Declare copy assignment.
// ...
};
int main()
{
}
7 Note
Make the type of the copy constructor's argument const ClassName& whenever
possible. This prevents the copy constructor from accidentally changing the copied
object. It also lets you copy from const objects.
When the argument type to the copy constructor isn't const , initialization by copying a
const object generates an error. The reverse isn't true: If the argument is const , you can
initialize by copying an object that's not const .
Compiler-generated assignment operators follow the same pattern for const . They take
a single argument of type ClassName& unless the assignment operators in all base and
member classes take arguments of type const ClassName& . In this case, the generated
assignment operator for the class takes a const argument.
7 Note
When virtual base classes are initialized by copy constructors, whether compiler-
generated or user-defined, they're initialized only once: at the point when they are
constructed.
The implications are similar to the copy constructor. When the argument type isn't
const , assignment from a const object generates an error. The reverse isn't true: If a
const value is assigned to a value that's not const , the assignment succeeds.
This topic describes how to write a move constructor and a move assignment operator
for a C++ class. A move constructor enables the resources owned by an rvalue object to
be moved into an lvalue without copying. For more information about move semantics,
see Rvalue Reference Declarator: &&.
This topic builds upon the following C++ class, MemoryBlock , which manages a memory
buffer.
C++
// MemoryBlock.h
#pragma once
#include <iostream>
#include <algorithm>
class MemoryBlock
{
public:
// Destructor.
~MemoryBlock()
{
std::cout << "In ~MemoryBlock(). length = "
<< _length << ".";
if (_data != nullptr)
{
std::cout << " Deleting resource.";
// Delete the resource.
delete[] _data;
}
// Copy constructor.
MemoryBlock(const MemoryBlock& other)
: _length(other._length)
, _data(new int[other._length])
{
std::cout << "In MemoryBlock(const MemoryBlock&). length = "
<< other._length << ". Copying resource." << std::endl;
if (this != &other)
{
// Free the existing resource.
delete[] _data;
_length = other._length;
_data = new int[_length];
std::copy(other._data, other._data + _length, _data);
}
return *this;
}
private:
size_t _length; // The length of the resource.
int* _data; // The resource.
};
The following procedures describe how to write a move constructor and a move
assignment operator for the example C++ class.
C++
MemoryBlock(MemoryBlock&& other)
: _data(nullptr)
, _length(0)
{
}
2. In the move constructor, assign the class data members from the source object to
the object that is being constructed:
C++
_data = other._data;
_length = other._length;
3. Assign the data members of the source object to default values. This prevents the
destructor from freeing resources (such as memory) multiple times:
C++
other._data = nullptr;
other._length = 0;
C++
C++
if (this != &other)
{
}
3. In the conditional statement, free any resources (such as memory) from the object
that is being assigned to.
The following example frees the _data member from the object that is being
assigned to:
C++
Follow steps 2 and 3 in the first procedure to transfer the data members from the
source object to the object that is being constructed:
C++
C++
return *this;
C++
// Move constructor.
MemoryBlock(MemoryBlock&& other) noexcept
: _data(nullptr)
, _length(0)
{
std::cout << "In MemoryBlock(MemoryBlock&&). length = "
<< other._length << ". Moving resource." << std::endl;
// Copy the data pointer and its length from the
// source object.
_data = other._data;
_length = other._length;
if (this != &other)
{
// Free the existing resource.
delete[] _data;
C++
// rvalue-references-move-semantics.cpp
// compile with: /EHsc
#include "MemoryBlock.h"
#include <vector>
int main()
{
// Create a vector object and add a few elements to it.
vector<MemoryBlock> v;
v.push_back(MemoryBlock(25));
v.push_back(MemoryBlock(75));
Output
Before Visual Studio 2010, this example produced the following output:
Output
The version of this example that uses move semantics is more efficient than the version
that does not use move semantics because it performs fewer copy, memory allocation,
and memory deallocation operations.
Robust Programming
To prevent resource leaks, always free resources (such as memory, file handles, and
sockets) in the move assignment operator.
If you provide both a move constructor and a move assignment operator for your class,
you can eliminate redundant code by writing the move constructor to call the move
assignment operator. The following example shows a revised version of the move
constructor that calls the move assignment operator:
C++
// Move constructor.
MemoryBlock(MemoryBlock&& other) noexcept
: _data(nullptr)
, _length(0)
{
*this = std::move(other);
}
See also
Rvalue Reference Declarator: &&
std::move
Delegating constructors
Article • 10/17/2022 • 2 minutes to read
Many classes have multiple constructors that do similar things—for example, validate
parameters:
C++
class class_c {
public:
int max;
int min;
int middle;
class_c() {}
class_c(int my_max) {
max = my_max > 0 ? my_max : 10;
}
class_c(int my_max, int my_min) {
max = my_max > 0 ? my_max : 10;
min = my_min > 0 && my_min < max ? my_min : 1;
}
class_c(int my_max, int my_min, int my_middle) {
max = my_max > 0 ? my_max : 10;
min = my_min > 0 && my_min < max ? my_min : 1;
middle = my_middle < max && my_middle > min ? my_middle : 5;
}
};
You could reduce the repetitive code by adding a function that does all of the validation,
but the code for class_c would be easier to understand and maintain if one constructor
could delegate some of the work to another one. To add delegating constructors, use
the constructor (. . .) : constructor (. . .) syntax:
C++
class class_c {
public:
int max;
int min;
int middle;
class_c(int my_max) {
max = my_max > 0 ? my_max : 10;
}
class_c(int my_max, int my_min) : class_c(my_max) {
min = my_min > 0 && my_min < max ? my_min : 1;
}
class_c(int my_max, int my_min, int my_middle) : class_c (my_max,
my_min){
middle = my_middle < max && my_middle > min ? my_middle : 5;
}
};
int main() {
class_c c1{ 1, 3, 2 };
}
As you step through the previous example, notice that the constructor class_c(int,
int, int) first calls the constructor class_c(int, int) , which in turn calls class_c(int) .
Each of the constructors performs only the work that is not performed by the other
constructors.
The first constructor that's called initializes the object so that all of its members are
initialized at that point. You can't do member initialization in a constructor that
delegates to another constructor, as shown here:
C++
class class_a {
public:
class_a() {}
// member initialization here, no delegate
class_a(string str) : m_string{ str } {}
The next example shows the use of non-static data-member initializers. Notice that if a
constructor also initializes a given data member, the member initializer is overridden:
C++
class class_a {
public:
class_a() {}
class_a(string str) : m_string{ str } {}
class_a(string str, double dbl) : class_a(str) { m_double = dbl; }
double m_double{ 1.0 };
string m_string{ m_double < 10.0 ? "alpha" : "beta" };
};
int main() {
class_a a{ "hello", 2.0 }; //expect a.m_double == 2.0, a.m_string ==
"hello"
int y = 4;
}
The constructor delegation syntax doesn't prevent the accidental creation of constructor
recursion—Constructor1 calls Constructor2 which calls Constructor1—and no errors are
thrown until there is a stack overflow. It's your responsibility to avoid cycles.
C++
class class_f{
public:
int max;
int min;
// don't do this
class_f() : class_f(6, 3){ }
class_f(int my_max, int my_min) : class_f() { }
};
Destructors (C++)
Article • 02/14/2023 • 7 minutes to read
A destructor is a member function that is invoked automatically when the object goes
out of scope or is explicitly destroyed by a call to delete . A destructor has the same
name as the class, preceded by a tilde ( ~ ). For example, the destructor for class String
is declared: ~String() .
If you don't define a destructor, the compiler provides a default one; for many classes
this is sufficient. You only need to define a custom destructor when the class stores
handles to system resources that need to be released, or pointers that own the memory
they point to.
C++
// spec1_destructors.cpp
#include <string>
class String {
public:
String( char *ch ); // Declare constructor
~String(); // and destructor.
private:
char *_text;
size_t sizeOfText;
};
int main() {
String str("The piper in the glen...");
}
In the preceding example, the destructor String::~String uses the delete operator to
deallocate the space dynamically allocated for text storage.
Declaring destructors
Destructors are functions with the same name as the class but preceded by a tilde ( ~ )
Can't be declared as const , volatile , or static . However, they can be invoked for
the destruction of objects declared as const , volatile , or static .
Can be declared as virtual . Using virtual destructors, you can destroy objects
without knowing their type—the correct destructor for the object is invoked using
the virtual function mechanism. Destructors can also be declared as pure virtual
functions for abstract classes.
Using destructors
Destructors are called when one of the following events occurs:
An object allocated using the new operator is explicitly deallocated using delete .
The destructor is explicitly called using the destructor function's fully qualified
name.
Destructors can freely call class member functions and access class member data.
Order of destruction
When an object goes out of scope or is deleted, the sequence of events in its complete
destruction is as follows:
1. The class's destructor is called, and the body of the destructor function is executed.
2. Destructors for nonstatic member objects are called in the reverse order in which
they appear in the class declaration. The optional member initialization list used in
construction of these members doesn't affect the order of construction or
destruction.
3. Destructors for non-virtual base classes are called in the reverse order of
declaration.
4. Destructors for virtual base classes are called in the reverse order of declaration.
C++
// order_of_destruction.cpp
#include <cstdio>
int main() {
A1 * a = new A3;
delete a;
printf("\n");
B1 * b = new B3;
delete b;
printf("\n");
B3 * b2 = new B3;
delete b2;
}
Output: A3 dtor
A2 dtor
A1 dtor
B1 dtor
B3 dtor
B2 dtor
B1 dtor
The following lists the class heads for the classes shown in the figure.
C++
class A
class B
class C : virtual public A, virtual public B
class D : virtual public A, virtual public B
class E : public C, public D, virtual public B
To determine the order of destruction of the virtual base classes of an object of type E ,
the compiler builds a list by applying the following algorithm:
1. Traverse the graph left, starting at the deepest point in the graph (in this case, E ).
2. Perform leftward traversals until all nodes have been visited. Note the name of the
current node.
3. Revisit the previous node (down and to the right) to find out whether the node
being remembered is a virtual base class.
4. If the remembered node is a virtual base class, scan the list to see whether it has
already been entered. If it isn't a virtual base class, ignore it.
5. If the remembered node isn't yet in the list, add it to the bottom of the list.
6. Traverse the graph up and along the next path to the right.
7. Go to step 2.
8. When the last upward path is exhausted, note the name of the current node.
9. Go to step 3.
10. Continue this process until the bottom node is again the current node.
This process produces an ordered list of unique entries. No class name appears twice.
Once the list is constructed, it's walked in reverse order, and the destructor for each of
the classes in the list from the last to the first is called.
C++
In the preceding example, the destructor for Base2 is called before the destructor for
Base1 .
Explicit destructor calls
Calling a destructor explicitly is seldom necessary. However, it can be useful to perform
cleanup of objects placed at absolute addresses. These objects are commonly allocated
using a user-defined new operator that takes a placement argument. The delete
operator can't deallocate this memory because it isn't allocated from the free store (for
more information, see The new and delete Operators). A call to the destructor, however,
can perform appropriate cleanup. To explicitly call the destructor for an object, s , of
class String , use one of the following statements:
C++
The notation for explicit calls to destructors, shown in the preceding, can be used
regardless of whether the type defines a destructor. This allows you to make such
explicit calls without knowing if a destructor is defined for the type. An explicit call to a
destructor where none is defined has no effect.
Robust programming
A class needs a destructor if it acquires a resource, and to manage the resource safely it
probably has to implement a copy constructor and a copy assignment.
If these special functions aren't defined by the user, they're implicitly defined by the
compiler. The implicitly generated constructors and assignment operators perform
shallow, memberwise copy, which is almost certainly wrong if an object is managing a
resource.
In the next example, the implicitly generated copy constructor will make the pointers
str1.text and str2.text refer to the same memory, and when we return from
copy_strings() , that memory will be deleted twice, which is undefined behavior:
C++
void copy_strings()
{
String str1("I have a sense of impending disaster...");
String str2 = str1; // str1.text and str2.text now refer to the same
object
} // delete[] _text; deallocates the same memory twice
// undefined behavior
See also
Copy Constructors and Copy Assignment Operators
Move Constructors and Move Assignment Operators
Overview of Member Functions
Article • 08/03/2021 • 2 minutes to read
Member functions are either static or nonstatic. The behavior of static member functions
differs from other member functions because static member functions have no implicit
this argument. Nonstatic member functions have a this pointer. Member functions,
whether static or nonstatic, can be defined either in or outside the class declaration.
C++
// overview_of_member_functions1.cpp
class Account
{
public:
// Declare the member function Deposit within the declaration
// of class Account.
double Deposit( double HowMuch )
{
balance += HowMuch;
return balance;
}
private:
double balance;
};
int main()
{
}
The following example is identical to the previous declaration of class Account , except
that the Deposit function is defined outside the class declaration:
C++
// overview_of_member_functions2.cpp
class Account
{
public:
// Declare the member function Deposit but do not define it.
double Deposit( double HowMuch );
private:
double balance;
};
int main()
{
}
7 Note
Classes containing member functions can have many declarations, but the member
functions themselves must have only one definition in a program. Multiple definitions
cause an error message at link time. If a class contains inline function definitions, the
function definitions must be identical to observe this "one definition" rule.
virtual Specifier
Article • 08/03/2021 • 2 minutes to read
The virtual keyword can be applied only to nonstatic class member functions. It signifies
that binding of calls to the function is deferred until run time. For more information, see
Virtual Functions.
override Specifier
Article • 08/03/2021 • 2 minutes to read
You can use the override keyword to designate member functions that override a virtual
function in a base class.
Syntax
function-declaration override;
Remarks
override is context-sensitive and has special meaning only when it's used after a
member function declaration; otherwise, it's not a reserved keyword.
Example
Use override to help prevent inadvertent inheritance behavior in your code. The
following example shows where, without using override, the member function behavior
of the derived class may not have been intended. The compiler doesn't emit any errors
for this code.
C++
class BaseClass
{
virtual void funcA();
virtual void funcB() const;
virtual void funcC(int = 0);
void funcD();
};
When you use override, the compiler generates errors instead of silently creating new
member functions.
C++
class BaseClass
{
virtual void funcA();
virtual void funcB() const;
virtual void funcC(int = 0);
void funcD();
};
To specify that functions cannot be overridden and that classes cannot be inherited, use
the final keyword.
See also
final Specifier
Keywords
final Specifier
Article • 08/03/2021 • 2 minutes to read
You can use the final keyword to designate virtual functions that cannot be overridden
in a derived class. You can also use it to designate classes that cannot be inherited.
Syntax
function-declaration final;
class class-name final base-classes
Remarks
final is context-sensitive and has special meaning only when it's used after a function
declaration or class name; otherwise, it's not a reserved keyword.
Example
The following example uses the final keyword to specify that a virtual function cannot
be overridden.
C++
class BaseClass
{
virtual void func() final;
};
For information about how to specify that member functions can be overridden, see
override Specifier.
The next example uses the final keyword to specify that a class cannot be inherited.
C++
See also
Keywords
override Specifier
Inheritance (C++)
Article • 08/03/2021 • 2 minutes to read
This section explains how to use derived classes to produce extensible programs.
Overview
New classes can be derived from existing classes using a mechanism called "inheritance"
(see the information beginning in Single Inheritance). Classes that are used for
derivation are called "base classes" of a particular derived class. A derived class is
declared using the following syntax:
C++
After the tag (name) for the class, a colon appears followed by a list of base
specifications. The base classes so named must have been declared previously. The base
specifications may contain an access specifier, which is one of the keywords public ,
protected or private . These access specifiers appear before the base class name and
apply only to that base class. These specifiers control the derived class's permission to
use to members of the base class. See Member-Access Control for information on
access to base class members. If the access specifier is omitted, the access to that base
is considered private . The base specifications may contain the keyword virtual to
indicate virtual inheritance. This keyword may appear before or after the access specifier,
if any. If virtual inheritance is used, the base class is referred to as a virtual base class.
Multiple base classes can be specified, separated by commas. If a single base class is
specified, the inheritance model is Single inheritance. If more than one base class is
specified, the inheritance model is called Multiple inheritance.
Single inheritance
Multiple base classes
Virtual functions
Explicit overrides
Abstract classes
See also
C++ Language Reference
Virtual Functions
Article • 04/07/2022 • 4 minutes to read
Virtual functions ensure that the correct function is called for an object, regardless of the
expression used to make the function call.
Suppose a base class contains a function declared as virtual and a derived class defines
the same function. The function from the derived class is invoked for objects of the
derived class, even if it is called using a pointer or reference to the base class. The
following example shows a base class that provides an implementation of the
PrintBalance function and two derived classes
C++
// deriv_VirtualFunctions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Account {
public:
Account( double d ) { _balance = d; }
virtual ~Account() {}
virtual double GetBalance() { return _balance; }
virtual void PrintBalance() { cerr << "Error. Balance not available for
base type." << endl; }
private:
double _balance;
};
In the preceding code, the calls to PrintBalance are identical, except for the object
pAccount points to. Because PrintBalance is virtual, the version of the function defined
for each object is called. The PrintBalance function in the derived classes
CheckingAccount and SavingsAccount "override" the function in the base class Account .
Functions in derived classes override virtual functions in base classes only if their type is
the same. A function in a derived class cannot differ from a virtual function in a base
class in its return type only; the argument list must differ as well.
When calling a function using pointers or references, the following rules apply:
A call to a virtual function is resolved according to the underlying type of object for
which it is called.
The following example shows how virtual and nonvirtual functions behave when called
through pointers:
C++
// deriv_VirtualFunctions2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Base {
public:
virtual void NameOf(); // Virtual function.
void InvokingClass(); // Nonvirtual function.
};
void Base::InvokingClass() {
cout << "Invoked by Base\n";
}
void Derived::InvokingClass() {
cout << "Invoked by Derived\n";
}
int main() {
// Declare an object of type Derived.
Derived aDerived;
Output
Derived::NameOf
Invoked by Base
Derived::NameOf
Invoked by Derived
Note that regardless of whether the NameOf function is invoked through a pointer to
Base or a pointer to Derived , it calls the function for Derived . It calls the function for
Derived because NameOf is a virtual function, and both pBase and pDerived point to an
Because virtual functions are called only for objects of class types, you cannot declare
global or static functions as virtual .
The virtual keyword can be used when declaring overriding functions in a derived
class, but it is unnecessary; overrides of virtual functions are always virtual.
Virtual functions in a base class must be defined unless they are declared using the
pure-specifier. (For more information about pure virtual functions, see Abstract Classes.)
C++
Both calls to PrintBalance in the preceding example suppress the virtual function-call
mechanism.
Single Inheritance
Article • 11/11/2021 • 4 minutes to read
In "single inheritance," a common form of inheritance, classes have only one base class.
Consider the relationship illustrated in the following figure.
Note the progression from general to specific in the figure. Another common attribute
found in the design of most class hierarchies is that the derived class has a "kind of"
relationship with the base class. In the figure, a Book is a kind of a PrintedDocument , and
a PaperbackBook is a kind of a book .
One other item of note in the figure: Book is both a derived class (from
PrintedDocument ) and a base class ( PaperbackBook is derived from Book ). A skeletal
C++
// deriv_SingleInheritance.cpp
// compile with: /LD
class PrintedDocument {};
to PaperbackBook . The difference is that a direct base class appears in the base list of a
class declaration and an indirect base does not.
The base class from which each class is derived is declared before the declaration of the
derived class. It is not sufficient to provide a forward-referencing declaration for a base
class; it must be a complete declaration.
In the preceding example, the access specifier public is used. The meaning of public,
protected, and private inheritance is described in Member-Access Control.
A class can serve as the base class for many specific classes, as illustrated in the
following figure.
In the diagram shown above, called a "directed acyclic graph" (or "DAG"), some of the
classes are base classes for more than one derived class. However, the reverse is not
true: there is only one direct base class for any given derived class. The graph in the
figure depicts a "single inheritance" structure.
7 Note
Directed acyclic graphs are not unique to single inheritance. They are also used to
depict multiple-inheritance graphs.
In inheritance, the derived class contains the members of the base class plus any new
members you add. As a result, a derived class can refer to members of the base class
(unless those members are redefined in the derived class). The scope-resolution
operator ( :: ) can be used to refer to members of direct or indirect base classes when
those members have been redefined in the derived class. Consider this example:
C++
// deriv_SingleInheritance2.cpp
// compile with: /EHsc /c
#include <iostream>
using namespace std;
class Document {
public:
char *Name; // Document name.
void PrintNameOf(); // Print name.
};
Note that the constructor for Book , ( Book::Book ), has access to the data member, Name .
In a program, an object of type Book can be created and used as follows:
C++
...
C++
// deriv_SingleInheritance3.cpp
// compile with: /EHsc /LD
#include <iostream>
using namespace std;
class Document {
public:
char *Name; // Document name.
void PrintNameOf() {} // Print name.
};
Pointers and references to derived classes can be implicitly converted to pointers and
references to their base classes if there is an accessible, unambiguous base class. The
following code demonstrates this concept using pointers (the same principle applies to
references):
C++
// deriv_SingleInheritance4.cpp
// compile with: /W3
struct Document {
char *Name;
void PrintNameOf() {}
};
int main() {
Document * DocLib[10]; // Library of ten documents.
for (int i = 0 ; i < 5 ; i++)
DocLib[i] = new Document;
for (int i = 5 ; i < 10 ; i++)
DocLib[i] = new PaperbackBook;
}
In the preceding example, different types are created. However, because these types are
all derived from the Document class, there is an implicit conversion to Document * . As a
result, DocLib is a "heterogeneous list" (a list in which not all objects are of the same
type) containing different kinds of objects.
Because the Document class has a PrintNameOf function, it can print the name of each
book in the library, although it may omit some of the information specific to the type of
document (page count for Book , number of bytes for HelpFile , and so on).
7 Note
Forcing the base class to implement a function such as PrintNameOf is often not the
best design. Virtual Functions offers other design alternatives.
Base Classes
Article • 08/03/2021 • 2 minutes to read
The inheritance process creates a new derived class that is made up of the members of
the base class(es) plus any new members added by the derived class. In a multiple-
inheritance, it is possible to construct an inheritance graph where the same base class is
part of more than one of the derived classes. The following figure shows such a graph.
A class can be derived from more than one base class. In a multiple-inheritance model
(where classes are derived from more than one base class), the base classes are specified
using the base-list grammar element. For example, the class declaration for
CollectionOfBook , derived from Collection and Book , can be specified:
C++
// deriv_MultipleBaseClasses.cpp
// compile with: /LD
class Collection {
};
class Book {};
class CollectionOfBook : public Book, public Collection {
// New members
};
The order in which base classes are specified isn't significant except in certain cases
where constructors and destructors are invoked. In these cases, the order in which base
classes are specified affects the following:
The order in which constructors are called. If your code relies on the Book portion
of CollectionOfBook to be initialized before the Collection part, the order of
specification is significant. Initialization takes place in the order the classes are
specified in the base-list.
The order in which destructors are invoked to clean up. Again, if a particular "part"
of the class must be present when the other part is being destroyed, the order is
significant. Destructors are called in the reverse order of the classes specified in the
base-list.
7 Note
The order of specification of base classes can affect the memory layout of the
class. Do not make any programming decisions based on the order of base
members in memory.
When specifying the base-list, you can't specify the same class name more than once.
However, it's possible for a class to be an indirect base to a derived class more than
once.
Virtual base classes
Because a class can be an indirect base class to a derived class more than once, C++
provides a way to optimize the way such base classes work. Virtual base classes offer a
way to save space and avoid ambiguities in class hierarchies that use multiple
inheritance.
Each nonvirtual object contains a copy of the data members defined in the base class.
This duplication wastes space and requires you to specify which copy of the base class
members you want whenever you access them.
When a base class is specified as a virtual base, it can act as an indirect base more than
once without duplication of its data members. A single copy of its data members is
shared by all the base classes that use it as a virtual base.
When declaring a virtual base class, the virtual keyword appears in the base lists of the
derived classes.
Consider the class hierarchy in the following figure, which illustrates a simulated lunch
line:
In the figure, Queue is the base class for both CashierQueue and LunchQueue . However,
when both classes are combined to form LunchCashierQueue , the following problem
arises: the new class contains two subobjects of type Queue , one from CashierQueue and
the other from LunchQueue . The following figure shows the conceptual memory layout
(the actual memory layout might be optimized):
C++
// deriv_VirtualBaseClasses.cpp
// compile with: /LD
class Queue {};
class CashierQueue : virtual public Queue {};
class LunchQueue : virtual public Queue {};
class LunchCashierQueue : public LunchQueue, public CashierQueue {};
The virtual keyword ensures that only one copy of the subobject Queue is included
(see the following figure).
A class can have both a virtual component and a nonvirtual component of a given type.
This happens in the conditions illustrated in the following figure:
In the figure, CashierQueue and LunchQueue use Queue as a virtual base class. However,
TakeoutQueue specifies Queue as a base class, not a virtual base class. Therefore,
LunchTakeoutCashierQueue has two subobjects of type Queue : one from the inheritance
path that includes LunchCashierQueue and one from the path that includes
TakeoutQueue . This is illustrated in the following figure.
Object layout with virtual and nonvirtual inheritance
7 Note
Virtual inheritance provides significant size benefits when compared with nonvirtual
inheritance. However, it can introduce extra processing overhead.
If a derived class overrides a virtual function that it inherits from a virtual base class, and
if a constructor or a destructor for the derived base class calls that function using a
pointer to the virtual base class, the compiler may introduce other hidden "vtordisp"
fields into the classes with virtual bases. The /vd0 compiler option suppresses the
addition of the hidden vtordisp constructor/destructor displacement member. The /vd1
compiler option, the default, enables them where they're necessary. Turn off vtordisps
only if you're sure that all class constructors and destructors call virtual functions
virtually.
The /vd compiler option affects an entire compilation module. Use the vtordisp
pragma to suppress and then reenable vtordisp fields on a class-by-class basis:
C++
Name ambiguities
Multiple inheritance introduces the possibility for names to be inherited along more
than one path. The class-member names along these paths aren't necessarily unique.
These name conflicts are called "ambiguities."
Any expression that refers to a class member must make an unambiguous reference.
The following example shows how ambiguities develop:
C++
// deriv_NameAmbiguities.cpp
// compile with: /LD
// Declare two base classes, A and B.
class A {
public:
unsigned a;
unsigned b();
};
class B {
public:
unsigned a(); // class A also has a member "a"
int b(); // and a member "b".
char c;
};
Given the preceding class declarations, code such as the following is ambiguous
because it's unclear whether b refers to the b in A or in B :
C++
C *pc = new C;
pc->b();
Consider the preceding example. Because the name a is a member of both class A and
class B , the compiler can't discern which a designates the function to be called. Access
to a member is ambiguous if it can refer to more than one function, object, type, or
enumerator.
C *pc = new C;
pc->B::a();
7 Note
When C is declared, it has the potential to cause errors when B is referenced in the
scope of C . No error is issued, however, until an unqualified reference to B is
actually made in C 's scope.
Dominance
it's possible for more than one name (function, object, or enumerator) to be reached
through an inheritance graph. Such cases are considered ambiguous with nonvirtual
base classes. They're also ambiguous with virtual base classes, unless one of the names
"dominates" the others.
A name dominates another name if it's defined in both classes and one class is derived
from the other. The dominant name is the name in the derived class; this name is used
when an ambiguity would otherwise have arisen, as shown in the following example:
C++
// deriv_Dominance.cpp
// compile with: /LD
class A {
public:
int a;
};
The effect of applying the address-of operator (&) to that object. The address-of
operator always supplies the base address of the object.
The effect of explicitly converting the pointer obtained using the address-of
operator to the base-class type A . Coercing the address of the object to type A*
doesn't always provide the compiler with enough information as to which
subobject of type A to select; in this case, two subobjects exist.
C++
The following figure shows how objects are composed using virtual and nonvirtual
inheritance.
Virtual and nonvirtual derivation
In the figure, accessing any member of class A through nonvirtual base classes causes
an ambiguity; the compiler has no information that explains whether to use the
subobject associated with B or the subobject associated with C . However, when A is
specified as a virtual base class, there's no question which subobject is being accessed.
See also
Inheritance
Explicit Overrides (C++)
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
If the same virtual function is declared in two or more interfaces and if a class is derived
from these interfaces, you can explicitly override each virtual function.
For information on explicit overrides in managed code using C++/CLI, see Explicit
Overrides.
Example
The following code example illustrates how to use explicit overrides:
C++
// deriv_ExplicitOverrides.cpp
// compile with: /GR
extern "C" int printf_s(const char *, ...);
__interface IMyInt1 {
void mf1();
void mf1(int);
void mf2();
void mf2(int);
};
__interface IMyInt2 {
void mf1();
void mf1(int);
void mf2();
void mf2(int);
};
void IMyInt1::mf1(int) {
printf_s("In CMyClass::IMyInt1::mf1(int)\n");
}
void IMyInt1::mf2();
void IMyInt1::mf2(int);
void IMyInt2::mf1() {
printf_s("In CMyClass::IMyInt2::mf1()\n");
}
void IMyInt2::mf1(int) {
printf_s("In CMyClass::IMyInt2::mf1(int)\n");
}
void IMyInt2::mf2();
void IMyInt2::mf2(int);
};
void CMyClass::IMyInt1::mf2() {
printf_s("In CMyClass::IMyInt1::mf2()\n");
}
void CMyClass::IMyInt1::mf2(int) {
printf_s("In CMyClass::IMyInt1::mf2(int)\n");
}
void CMyClass::IMyInt2::mf2() {
printf_s("In CMyClass::IMyInt2::mf2()\n");
}
void CMyClass::IMyInt2::mf2(int) {
printf_s("In CMyClass::IMyInt2::mf2(int)\n");
}
int main() {
IMyInt1 *pIMyInt1 = new CMyClass();
IMyInt2 *pIMyInt2 = dynamic_cast<IMyInt2 *>(pIMyInt1);
pIMyInt1->mf1();
pIMyInt1->mf1(1);
pIMyInt1->mf2();
pIMyInt1->mf2(2);
pIMyInt2->mf1();
pIMyInt2->mf1(3);
pIMyInt2->mf2();
pIMyInt2->mf2(4);
Output
In CMyClass::IMyInt1::mf1()
In CMyClass::IMyInt1::mf1(int)
In CMyClass::IMyInt1::mf2()
In CMyClass::IMyInt1::mf2(int)
In CMyClass::IMyInt2::mf1()
In CMyClass::IMyInt2::mf1(int)
In CMyClass::IMyInt2::mf2()
In CMyClass::IMyInt2::mf2(int)
See also
Inheritance
Abstract classes (C++)
Article • 08/03/2021 • 2 minutes to read
Abstract classes act as expressions of general concepts from which more specific classes
can be derived. You can't create an object of an abstract class type. However, you can
use pointers and references to abstract class types.
You create an abstract class by declaring at least one pure virtual member function.
That's a virtual function declared by using the pure specifier ( = 0 ) syntax. Classes
derived from the abstract class must implement the pure virtual function or they, too,
are abstract classes.
Consider the example presented in Virtual functions. The intent of class Account is to
provide general functionality, but objects of type Account are too general to be useful.
That means Account is a good candidate for an abstract class:
C++
// deriv_AbstractClasses.cpp
// compile with: /LD
class Account {
public:
Account( double d ); // Constructor.
virtual double GetBalance(); // Obtain balance.
virtual void PrintBalance() = 0; // Pure virtual function.
private:
double _balance;
};
The only difference between this declaration and the previous one is that PrintBalance
is declared with the pure specifier ( = 0 ).
Argument types
abstract-class-name::function-name()
Defined pure virtual functions are helpful when you design class hierarchies whose base
classes include pure virtual destructors. That's because base class destructors are always
called during object destruction. Consider the following example:
C++
// deriv_RestrictionsOnUsingAbstractClasses.cpp
// Declare an abstract base class with a pure virtual destructor.
// It's the simplest possible abstract class.
class base
{
public:
base() {}
// To define the virtual destructor outside the class:
virtual ~base() = 0;
// Microsoft-specific extension to define it inline:
// virtual ~base() = 0 {};
};
int main()
{
derived aDerived; // destructor called when it goes out of scope
}
The example shows how a Microsoft compiler extension lets you add an inline definition
to pure virtual ~base() . You can also define it outside the class by using base::~base()
{} .
When the object aDerived goes out of scope, the destructor for class derived is called.
The compiler generates code to implicitly call the destructor for class base after the
derived destructor. The empty implementation for the pure virtual function ~base
ensures that at least some implementation exists for the function. Without it, the linker
generates an unresolved external symbol error for the implicit call.
7 Note
In the preceding example, the pure virtual function base::~base is called implicitly
from derived::~derived . It's also possible to call pure virtual functions explicitly by
using a fully qualified member-function name. Such functions must have an
implementation, or the call results in an error at link time.
See also
Inheritance
Summary of Scope Rules
Article • 08/03/2021 • 2 minutes to read
The use of a name must be unambiguous within its scope (up to the point where
overloading is determined). If the name denotes a function, the function must be
unambiguous with respect to number and type of parameters. If the name remains
unambiguous, member-access rules are applied.
Constructor initializers
Constructor initializers are evaluated in the scope of the outermost block of the
constructor for which they are specified. Therefore, they can use the constructor's
parameter names.
Global names
A name of an object, function, or enumerator is global if it is introduced outside any
function or class or prefixed by the global unary scope operator ( :: ), and if it is not
used in conjunction with any of these binary operators:
Scope-resolution ( :: )
Qualified names
Names used with the binary scope-resolution operator ( :: ) are called "qualified names."
The name specified after the binary scope-resolution operator must be a member of the
class specified on the left of the operator or a member of its base class(es).
Names specified after the member-selection operator (. or ->) must be members of the
class type of the object specified on the left of the operator or members of its base
class(es). Names specified on the right of the member-selection operator (->) can also
be objects of another class type, provided that the left-hand side of -> is a class object
and that the class defines an overloaded member-selection operator (->) that evaluates
to a pointer to some other class type. (This provision is discussed in more detail in Class
Member Access.)
The compiler searches for names in the following order, stopping when the name is
found:
1. Current block scope if name is used inside a function; otherwise, global scope.
2. Outward through each enclosing block scope, including the outermost function
scope (which includes function parameters).
3. If the name is used inside a member function, the class's scope is searched for the
name.
5. The enclosing nested class scope (if any) and its bases are searched. The search
continues until the outermost enclosing class scope is searched.
2. Names preceded by the class , struct , and union keywords force the compiler to
search only for class , struct , or union names.
3. Names on the left side of the scope-resolution operator ( :: ) can be only class ,
struct , namespace , or union names.
If the name refers to a nonstatic member but is used in a static member function, an
error message is generated. Similarly, if the name refers to any nonstatic member in an
enclosing class, an error message is generated because enclosed classes do not have
enclosing-class this pointers.
Function parameter names in function declarations (prototypes) are in local scope of the
declaration and go out of scope at the end of the declaration.
Default parameters are in the scope of the parameter for which they are the default, as
described in the preceding two paragraphs. However, they cannot access local variables
or nonstatic class members. Default parameters are evaluated at the point of the
function call, but they are evaluated in the function declaration's original scope.
Therefore, the default parameters for member functions are always evaluated in class
scope.
See also
Inheritance
Inheritance keywords
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
class class-name
where:
class-name
C++ allows you to declare a pointer to a class member before the definition of the class.
For example:
C++
class S;
int S::*p;
encounters such a pointer, it must make a generalized representation of the pointer. The
size of the representation is dependent on the inheritance model specified. There are
three ways to specify an inheritance model to the compiler:
7 Note
If you always declare a pointer to a member of a class after defining the class,
you don't need to use any of these options.
If you declare a pointer to a class member before the class is defined, it can negatively
affect the size and speed of the resulting executable file. The more complex the
inheritance used by a class, the greater the number of bytes required to represent a
pointer to a member of the class. And, the larger the code required to interpret the
pointer. Single (or no) inheritance is least complex, and virtual inheritance is most
complex. Pointers to members you declare before the class is defined always use the
largest, most complex representation.
C++
class __single_inheritance S;
int S::*p;
then no matter the command-line options or pragmas you specify, pointers to members
of class S will use the smallest possible representation.
7 Note
See also
Keywords
virtual (C++)
Article • 08/03/2021 • 2 minutes to read
Syntax
Parameters
type-specifiers
Specifies the return type of the virtual member function.
member-function-declarator
Declares a member function.
access-specifier
Defines the level of access to the base class, public , protected or private . Can appear
before or after the virtual keyword.
base-class-name
Identifies a previously declared class type.
Remarks
See Virtual Functions for more information.
Also see the following keywords: class, private, public, and protected.
See also
Keywords
__super
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Allows you to explicitly state that you are calling a base-class implementation for a
function that you are overriding.
Syntax
__super::member_function();
Remarks
All accessible base-class methods are considered during the overload resolution phase,
and the function that provides the best match is the one that is called.
__super cannot be used with a using declaration. See using Declaration for more
information.
With the introduction of attributes that inject code, your code might contain one or
more base classes whose names you may not know but that contain methods that you
wish to call.
Example
C++
// deriv_super.cpp
// compile with: /c
struct B1 {
void mf(int) {}
};
struct B2 {
void mf(short) {}
void mf(char) {}
};
struct D : B1, B2 {
void mf(short) {
__super::mf(1); // Calls B1::mf(int)
__super::mf('s'); // Calls B2::mf(char)
}
};
See also
Keywords
__interface
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
Remarks
A C++ class or struct could be implemented with these rules, but __interface enforces
them.
C++
__interface IMyInterface {
HRESULT CommitX();
HRESULT get_X(BSTR* pbstrName);
};
Notice that you do not have to explicitly indicate that the CommitX and get_X functions
are pure virtual. An equivalent declaration for the first function would be:
C++
Example
The following sample shows how to use properties declared in an interface.
C++
// deriv_interface.cpp
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
#include <string.h>
#include <comdef.h>
#include <stdio.h>
[module(name="test")];
[ coclass, uuid("00000000-0000-0000-0000-000000000002") ]
class MyClass : public IFace {
private:
int m_i;
BSTR m_bstr;
public:
MyClass()
{
m_i = 0;
m_bstr = 0;
}
~MyClass()
{
if (m_bstr)
::SysFreeString(m_bstr);
}
int get_int_data()
{
return m_i;
}
void put_int_data(int _i)
{
m_i = _i;
}
BSTR get_bstr_data()
{
BSTR bstr = ::SysAllocString(m_bstr);
return bstr;
}
int main()
{
_bstr_t bstr("Testing");
CoInitialize(NULL);
CComObject<MyClass>* p;
CComObject<MyClass>::CreateInstance(&p);
p->int_data = 100;
printf_s("p->int_data = %d\n", p->int_data);
p->bstr_data = bstr;
printf_s("bstr_data = %S\n", p->bstr_data);
}
Output
p->int_data = 100
bstr_data = Testing
See also
Keywords
Interface Attributes
Special member functions
Article • 08/03/2021 • 2 minutes to read
The special member functions are class (or struct) member functions that, in certain
cases, the compiler automatically generates for you. These functions are the default
constructor, the destructor, the copy constructor and copy assignment operator, and the
move constructor and move assignment operator. If your class does not define one or
more of the special member functions, then the compiler may implicitly declare and
define the functions that are used. The compiler-generated implementations are called
the default special member functions. The compiler does not generate functions if they
are not needed.
You can explicitly declare a default special member function by using the = default
keyword. This causes the compiler to define the function only if needed, in the same way
as if the function was not declared at all.
In some cases, the compiler may generate deleted special member functions, which are
not defined and therefore not callable. This can happen in cases where a call to a
particular special member function on a class doesn't make sense, given other
properties of the class. To explicitly prevent automatic generation of a special member
function, you can declare it as deleted by using the = delete keyword.
The default destructor performs member-wise destruction of the object. It is virtual only
if a base class destructor is virtual.
The default copy and move construction and assignment operations perform member-
wise bit-pattern copies or moves of non-static data members. Move operations are only
generated when no destructor or move or copy operations are declared. A default copy
constructor is only generated when no copy constructor is declared. It is implicitly
deleted if a move operation is declared. A default copy assignment operator is
generated only when no copy assignment operator is explicitly declared. It is implicitly
deleted if a move operation is declared.
See also
C++ Language Reference
Static Members (C++)
Article • 08/03/2021 • 2 minutes to read
Classes can contain static member data and member functions. When a data member is
declared as static , only one copy of the data is maintained for all objects of the class.
Static data members are not part of objects of a given class type. As a result, the
declaration of a static data member is not considered a definition. The data member is
declared in class scope, but definition is performed at file scope. These static members
have external linkage. The following example illustrates this:
C++
// static_data_members.cpp
class BufferedOutput
{
public:
// Return number of bytes written by any object of this class.
short BytesWritten()
{
return bytecount;
}
int main()
{
}
In the preceding code, the member bytecount is declared in class BufferedOutput , but it
must be defined outside the class declaration.
Static data members can be referred to without referring to an object of class type. The
number of bytes written using BufferedOutput objects can be obtained as follows:
C++
long nBytes = BufferedOutput::bytecount;
For the static member to exist, it is not necessary that any objects of the class type exist.
Static members can also be accessed using the member-selection (. and ->) operators.
For example:
C++
BufferedOutput Console;
In the preceding case, the reference to the object ( Console ) is not evaluated; the value
returned is that of the static object bytecount .
Static data members are subject to class-member access rules, so private access to static
data members is allowed only for class-member functions and friends. These rules are
described in Member-Access Control. The exception is that static data members must be
defined in file scope regardless of their access restrictions. If the data member is to be
explicitly initialized, an initializer must be provided with the definition.
The type of a static member is not qualified by its class name. Therefore, the type of
BufferedOutput::bytecount is long .
See also
Classes and Structs
User-Defined Type Conversions (C++)
Article • 08/03/2021 • 10 minutes to read
A conversion produces a new value of some type from a value of a different type.
Standard conversions are built into the C++ language and support its built-in types, and
you can create user-defined conversions to perform conversions to, from, or between
user-defined types.
The standard conversions perform conversions between built-in types, between pointers
or references to types related by inheritance, to and from void pointers, and to the null
pointer. For more information, see Standard Conversions. User-defined conversions
perform conversions between user-defined types, or between user-defined types and
built-in types. You can implement them as Conversion constructors or as Conversion
functions.
Conversions can either be explicit—when the programmer calls for one type to be
converted to another, as in a cast or direct initialization—or implicit—when the
language or program calls for a different type than the one given by the programmer.
An argument supplied to a function does not have the same type as the matching
parameter.
The value returned from a function does not have the same type as the function
return type.
An initializer expression does not have the same type as the object it is initializing.
An operand supplied to an operator does not have the same type as the matching
operand-parameter. For built-in operators, both operands must have the same
type, and are converted to a common type that can represent both. For more
information, see Standard Conversions. For user-defined operators, each operand
must have the same type as the matching operand-parameter.
When one standard conversion can't complete an implicit conversion, the compiler can
use a user-defined conversion, followed optionally by an additional standard conversion,
to complete it.
When two or more user-defined conversions that perform the same conversion are
available at a conversion site, the conversion is said to be ambiguous. Such ambiguities
are an error because the compiler can't determine which one of the available
conversions it should choose. However, it's not an error just to define multiple ways of
performing the same conversion because the set of available conversions can be
different at different locations in the source code—for example, depending on which
header files are included in a source file. As long as only one conversion is available at
the conversion site, there is no ambiguity. There are several ways that ambiguous
conversions can arise, but the most common ones are:
Multiple inheritance. The conversion is defined in more than one base class.
You can usually resolve an ambiguity just by qualifying the name of the involved type
more fully or by performing an explicit cast to clarify your intent.
One well-known example of an implicit conversion that can cause problems is the
conversion to bool . There are many reasons that you might want to create a class type
that can be used in a Boolean context—for example, so that it can be used to control an
if statement or loop—but when the compiler performs a user-defined conversion to a
built-in type, the compiler is allowed to apply an additional standard conversion
afterwards. The intent of this additional standard conversion is to allow for things like
promotion from short to int , but it also opens the door for less-obvious conversions—
for example, from bool to int , which allows your class type to be used in integer
contexts you never intended. This particular problem is known as the Safe Bool Problem.
This kind of problem is where the explicit keyword can help.
The explicit keyword tells the compiler that the specified conversion can't be used to
perform implicit conversions. If you wanted the syntactic convenience of implicit
conversions before the explicit keyword was introduced, you had to either accept the
unintended consequences that implicit conversion sometimes created or use less-
convenient, named conversion functions as a workaround. Now, by using the explicit
keyword, you can create convenient conversions that can only be used to perform
explicit casts or direct initialization, and that won't lead to the kind of problems
exemplified by the Safe Bool Problem.
The explicit keyword can be applied to conversion constructors since C++98, and to
conversion functions since C++11. The following sections contain more information
about how to use the explicit keyword.
Conversion constructors
Conversion constructors define conversions from user-defined or built-in types to a
user-defined type. The following example demonstrates a conversion constructor that
converts from the built-in type double to a user-defined type Money .
C++
#include <iostream>
class Money
{
public:
Money() : amount{ 0.0 } {};
Money(double _amount) : amount{ _amount } {};
double amount;
};
display_balance(payable);
display_balance(49.95);
display_balance(9.99f);
return 0;
}
Notice that the first call to the function display_balance , which takes an argument of
type Money , doesn't require a conversion because its argument is the correct type.
However, on the second call to display_balance , a conversion is needed because the
type of the argument, a double with a value of 49.95 , is not what the function expects.
The function can't use this value directly, but because there's a conversion from the type
of the argument— double —to the type of the matching parameter— Money —a
temporary value of type Money is constructed from the argument and used to complete
the function call. In the third call to display_balance , notice that the argument is not a
double , but is instead a float with a value of 9.99 —and yet the function call can still
be completed because the compiler can perform a standard conversion—in this case,
from float to double —and then perform the user-defined conversion from double to
Money to complete the necessary conversion.
The target type of the conversion is the user-defined type that's being constructed.
Conversion constructors typically take exactly one argument, which is of the source
type. However, a conversion constructor can specify additional parameters if each
additional parameter has a default value. The source type remains the type of the
first parameter.
C++
#include <iostream>
class Money
{
public:
Money() : amount{ 0.0 } {};
explicit Money(double _amount) : amount{ _amount } {};
double amount;
};
return 0;
}
In this example, notice that you can still use the explicit conversion constructor to
perform direct initialization of payable . If instead you were to copy-initialize Money
payable = 79.99; , it would be an error. The first call to display_balance is unaffected
because the argument is the correct type. The second call to display_balance is an
error, because the conversion constructor can't be used to perform implicit conversions.
The third call to display_balance is legal because of the explicit cast to Money , but
notice that the compiler still helped complete the cast by inserting an implicit cast from
float to double .
C++
#include <iostream>
class Money
{
public:
Money() : amount{ 0.0 } {};
Money(double _amount) : amount{ _amount } {};
Notice that the member variable amount is made private and that a public conversion
function to type double is introduced just to return the value of amount . In the function
display_balance , an implicit conversion occurs when the value of balance is streamed
to standard output by using the stream insertion operator << . Because no stream-
insertion operator is defined for the user-defined type Money , but there is one for built-
in type double , the compiler can use the conversion function from Money to double to
satisfy the stream-insertion operator.
The target type of the conversion must be declared prior to the declaration of the
conversion function. Classes, structures, enumerations, and typedefs cannot be
declared within the declaration of the conversion function.
C++
Conversion functions have a return type that is specified by the name of the
conversion function, which is also the name of the conversion's target type.
Specifying a return type in the declaration is an error.
C++
#include <iostream>
class Money
{
public:
Money() : amount{ 0.0 } {};
Money(double _amount) : amount{ _amount } {};
Here the conversion function operator double has been made explicit, and an explicit
cast to type double has been introduced in the function display_balance to perform the
conversion. If this cast were omitted, the compiler would be unable to locate a suitable
stream-insertion operator << for type Money and an error would occur.
Mutable Data Members (C++)
Article • 08/03/2021 • 2 minutes to read
This keyword can only be applied to non-static and non-const data members of a class.
If a data member is declared mutable , then it is legal to assign a value to this data
member from a const member function.
Syntax
mutable member-variable-declaration;
Remarks
For example, the following code will compile without error because m_accessCount has
been declared to be mutable , and therefore can be modified by GetFlag even though
GetFlag is a const member function.
C++
// mutable.cpp
class X
{
public:
bool GetFlag() const
{
m_accessCount++;
return m_flag;
}
private:
bool m_flag;
mutable int m_accessCount;
};
int main()
{
}
See also
Keywords
Nested Class Declarations
Article • 08/03/2021 • 4 minutes to read
A class can be declared within the scope of another class. Such a class is called a "nested
class." Nested classes are considered to be within the scope of the enclosing class and
are available for use within that scope. To refer to a nested class from a scope other than
its immediate enclosing scope, you must use a fully qualified name.
C++
// nested_class_declarations.cpp
class BufferedIO
{
public:
enum IOError { None, Access, General };
int main()
{
}
BufferedIO . These class names are not visible outside the scope of class BufferedIO .
However, an object of type BufferedIO does not contain any objects of types
BufferedInput or BufferedOutput .
Nested classes can directly use names, type names, names of static members, and
enumerators only from the enclosing class. To use names of other class members, you
must use pointers, references, or object names.
7 Note
Nested classes declare only types within class scope. They do not cause contained
objects of the nested class to be created. The preceding example declares two
nested classes but does not declare any objects of these class types.
An exception to the scope visibility of a nested class declaration is when a type name is
declared together with a forward declaration. In this case, the class name declared by
the forward declaration is visible outside the enclosing class, with its scope defined to
be the smallest enclosing non-class scope. For example:
C++
// nested_class_declarations_2.cpp
class C
{
public:
typedef class U u_t; // class U visible outside class C scope
typedef class V {} v_t; // class V not visible outside class C
};
int main()
{
// okay, forward declaration used above so file scope is used
U* pu;
C++
// member_functions_in_nested_classes.cpp
class BufferedIO
{
public:
enum IOError { None, Access, General };
class BufferedInput
{
public:
int read(); // Declare but do not define member
int good(); // functions read and good.
private:
IOError _inputerror;
};
class BufferedOutput
{
// Member list.
};
};
// Define member functions read and good in
// file scope.
int BufferedIO::BufferedInput::read()
{
return(1);
}
int BufferedIO::BufferedInput::good()
{
return _inputerror == None;
}
int main()
{
}
In the preceding example, the qualified-type-name syntax is used to declare the function
name. The declaration:
C++
BufferedIO::BufferedInput::read()
means "the read function that is a member of the BufferedInput class that is in the
scope of the BufferedIO class." Because this declaration uses the qualified-type-name
syntax, constructs of the following form are possible:
C++
int BIO_INPUT::read()
The preceding declaration is equivalent to the previous one, but it uses a typedef name
in place of the class names.
C++
// friend_functions_and_nested_classes.cpp
#include <string.h>
enum
{
sizeOfMessage = 255
};
char *rgszMessage[sizeOfMessage];
class BufferedIO
{
public:
class BufferedInput
{
public:
friend int GetExtendedErrorStatus();
static char *message;
static int messageSize;
int iMsgNo;
};
};
char *BufferedIO::BufferedInput::message;
int BufferedIO::BufferedInput::messageSize;
int GetExtendedErrorStatus()
{
int iMsgNo = 1; // assign arbitrary value as message number
strcpy_s( BufferedIO::BufferedInput::message,
BufferedIO::BufferedInput::messageSize,
rgszMessage[iMsgNo] );
return iMsgNo;
}
int main()
{
}
C++
With the preceding interface, several classes can use the services of this function by
passing a memory location where they want the error message copied.
See also
Classes and Structs
Anonymous Class Types
Article • 08/03/2021 • 2 minutes to read
Classes can be anonymous — that is, they can be declared without an identifier. This is
useful when you replace a class name with a typedef name, as in the following:
C++
typedef struct
{
unsigned x;
unsigned y;
} POINT;
7 Note
The use of anonymous classes shown in the previous example is useful for
preserving compatibility with existing C code. In some C code, the use of typedef
in conjunction with anonymous structures is prevalent.
Anonymous classes are also useful when you want a reference to a class member to
appear as though it were not contained in a separate class, as in the following:
C++
struct PTValue
{
POINT ptLoc;
union
{
int iValue;
long lValue;
};
};
PTValue ptv;
In the preceding code, iValue can be accessed using the object member-selection
operator (.) as follows:
C++
int i = ptv.iValue;
Anonymous classes are subject to certain restrictions. (For more information about
anonymous unions, see Unions.) Anonymous classes:
Anonymous structs
Microsoft Specific
You can access the members of an anonymous structure as if they were members in the
containing structure.
C++
// anonymous_structures.c
#include <stdio.h>
struct phone
{
int areacode;
long number;
};
struct person
{
char name[30];
char gender;
int age;
int weight;
struct phone; // Anonymous structure; no name needed
} Jim;
int main()
{
Jim.number = 1234567;
printf_s("%d\n", Jim.number);
}
//Output: 1234567
END Microsoft Specific
Pointers to Members
Article • 08/03/2021 • 4 minutes to read
The type specifier: the name of a type. It's the type of the member to be
pointed to, not the class.
2. The declarator:
The qualified name of the class containing the members to be pointed to.
The :: operator.
The * operator.
The = operator.
The :: operator.
A pointer to a member of a class differs from a normal pointer: it has both type
information for the type of the member and for the class to which the member belongs.
A normal pointer identifies (has the address of) only a single object in memory. A
pointer to a member of a class identifies that member in any instance of the class. The
following example declares a class, Window , and some pointers to member data.
C++
// pointers_to_members1.cpp
class Window
{
public:
Window(); // Default constructor.
Window( int x1, int y1, // Constructor specifying
int x2, int y2 ); // Window size.
bool SetCaption( const char *szTitle ); // Set window caption.
const char *GetCaption(); // Get window caption.
char *szWinCaption; // Window caption.
};
In the preceding example, pwCaption is a pointer to any member of class Window that's
of type char* . The type of pwCaption is char * Window::* . The next code fragment
declares pointers to the SetCaption and GetCaption member functions.
C++
The pointers pfnwGC and pfnwSC point to GetCaption and SetCaption of the Window
class, respectively. The code copies information to the window caption directly using the
pointer to member pwCaption :
C++
Window wMainWindow;
Window *pwChildWindow = new Window;
char *szUntitled = "Untitled - ";
int cUntitledLen = strlen( szUntitled );
The difference between the .* and ->* operators (the pointer-to-member operators) is
that the .* operator selects members given an object or object reference, while the ->*
operator selects members through a pointer. For more information about these
operators, see Expressions with Pointer-to-Member Operators.
The result of the pointer-to-member operators is the type of the member. In this case,
it's char * .
The following code fragment invokes the member functions GetCaption and SetCaption
using pointers to members:
C++
// Allocate a buffer.
enum {
sizeOfBuffer = 100
};
char szCaptionBase[sizeOfBuffer];
The key to virtual functions working, as always, is invoking them through a pointer to a
base class. (For more information about virtual functions, see Virtual Functions.)
The following code shows how to invoke a virtual function through a pointer-to-
member function:
C++
// virtual_functions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Base
{
public:
virtual void Print();
};
void (Base::* bfnPrint)() = &Base::Print;
void Base::Print()
{
cout << "Print function for class Base" << endl;
}
void Derived::Print()
{
cout << "Print function for class Derived" << endl;
}
int main()
{
Base *bPtr;
Base bObject;
Derived dObject;
bPtr = &bObject; // Set pointer to address of bObject.
(bPtr->*bfnPrint)();
bPtr = &dObject; // Set pointer to address of dObject.
(bPtr->*bfnPrint)();
}
// Output:
// Print function for class Base
// Print function for class Derived
The this pointer
Article • 06/03/2022 • 3 minutes to read
The this pointer is a pointer accessible only within the nonstatic member functions of a
class , struct , or union type. It points to the object for which the member function is
called. Static member functions don't have a this pointer.
Syntax
C++
this
this->member-identifier
Remarks
An object's this pointer isn't part of the object itself. It's not reflected in the result of a
sizeof statement on the object. When a nonstatic member function is called for an
object, the compiler passes the object's address to the function as a hidden argument.
For example, the following function call:
C++
myDate.setMonth( 3 );
C++
setMonth( &myDate, 3 );
The object's address is available from within the member function as the this pointer.
Most this pointer uses are implicit. It's legal, though unnecessary, to use an explicit
this when referring to members of the class. For example:
C++
The expression *this is commonly used to return the current object from a member
function:
C++
return *this;
C++
if (&Object != this) {
// do not execute in cases of self-reference
7 Note
Because the this pointer is nonmodifiable, assignments to the this pointer are
not allowed. Earlier implementations of C++ allowed assignment to this .
Occasionally, the this pointer is used directly — for example, to manipulate self-
referential data structures, where the address of the current object is required.
Example
C++
// this_pointer.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>
class Buf
{
public:
Buf( char* szBuffer, size_t sizeOfBuffer );
Buf& operator=( const Buf & );
void Display() { cout << buffer << endl; }
private:
char* buffer;
size_t sizeOfBuffer;
};
int main()
{
Buf myBuf( "my buffer", 10 );
Buf yourBuf( "your buffer", 12 );
// assignment operator
myBuf = yourBuf;
Output
my buffer
your buffer
Type of the this pointer
The this pointer's type can be modified in the function declaration by the const and
volatile keywords. To declare a function that has either of these attributes, add the
Consider an example:
C++
// type_of_this_pointer1.cpp
class Point
{
unsigned X() const;
};
int main()
{
}
The preceding code declares a member function, X , in which the this pointer is treated
as a const pointer to a const object. Combinations of cv-mod-list options can be used,
but they always modify the object pointed to by the this pointer, not the pointer itself.
The following declaration declares function X , where the this pointer is a const
pointer to a const object:
C++
// type_of_this_pointer2.cpp
class Point
{
unsigned X() const;
};
int main()
{
}
The type of this in a member function is described by the following syntax. The cv-
qualifier-list is determined from the member function's declarator. It can be const or
volatile (or both). class-type is the name of the class:
In other words, the this pointer is always a const pointer. It can't be reassigned. The
const or volatile qualifiers used in the member function declaration apply to the class
instance the this pointer points at, in the scope of that function.
The following table explains more about how these modifiers work.
Modifier Meaning
const Can't change member data; can't invoke member functions that aren't const .
volatile Member data is loaded from memory each time it's accessed; disables certain
optimizations.
It's an error to pass a const object to a member function that isn't const .
Similarly, it's also an error to pass a volatile object to a member function that isn't
volatile .
Member functions declared as const can't change member data — in such functions,
the this pointer is a pointer to a const object.
7 Note
See also
Keywords
C++ Bit Fields
Article • 04/04/2023 • 2 minutes to read
Classes and structures can contain members that occupy less storage than an integral
type. These members are specified as bit fields. The syntax for bit-field member-
declarator specification follows:
Syntax
declarator : constant-expression
Remarks
The (optional) declarator is the name by which the member is accessed in the program.
It must be an integral type (including enumerated types). The constant-expression
specifies the number of bits the member occupies in the structure. Anonymous bit fields
—that is, bit-field members with no identifier—can be used for padding.
7 Note
An unnamed bit field of width 0 forces alignment of the next bit field to the next
type boundary, where type is the type of the member.
C++
// bit_fields1.cpp
// compile with: /LD
struct Date {
unsigned short nWeekDay : 3; // 0..7 (3 bits)
unsigned short nMonthDay : 6; // 0..31 (6 bits)
unsigned short nMonth : 5; // 0..12 (5 bits)
unsigned short nYear : 8; // 0..100 (8 bits)
};
The conceptual memory layout of an object of type Date is shown in the following
figure:
nYear is 8 bits long, which would overflow the word boundary of the declared type,
unsigned short . Therefore, it starts at the beginning of a new unsigned short . It isn't
necessary that all bit fields fit in one object of the underlying type; new units of storage
are allocated, according to the number of bits requested in the declaration.
Microsoft Specific
The ordering of data declared as bit fields is from low to high bit, as shown in the
previous figure.
C++
// bit_fields2.cpp
// compile with: /LD
struct Date {
unsigned nWeekDay : 3; // 0..7 (3 bits)
unsigned nMonthDay : 6; // 0..31 (6 bits)
unsigned : 0; // Force alignment to next boundary.
unsigned nMonth : 5; // 0..12 (5 bits)
unsigned nYear : 8; // 0..100 (8 bits)
};
The underlying type of a bit field must be an integral type, as described in Built-in types.
If the initializer for a reference of type const T& is an lvalue that refers to a bit field of
type T , the reference isn't bound to the bit field directly. Instead, the reference is bound
to a temporary initialized to hold the value of the bit field.
Restrictions on bit fields
The following list details erroneous operations on bit fields:
See also
Classes and Structs
Lambda expressions in C++
Article • 02/20/2023 • 12 minutes to read
Related articles
Lambda expressions vs. function objects
Working with lambda expressions
constexpr lambda expressions
C++
#include <algorithm>
#include <cmath>
4. exception-specification Optional.
5. trailing-return-type Optional.
6. lambda body.
Capture clause
A lambda can introduce new variables in its body (in C++14), and it can also access, or
capture, variables from the surrounding scope. A lambda begins with the capture clause.
It specifies which variables are captured, and whether the capture is by value or by
reference. Variables that have the ampersand ( & ) prefix are accessed by reference and
variables that don't have it are accessed by value.
An empty capture clause, [ ] , indicates that the body of the lambda expression
accesses no variables in the enclosing scope.
You can use a capture-default mode to indicate how to capture any outside variables
referenced in the lambda body: [&] means all variables that you refer to are captured
by reference, and [=] means they're captured by value. You can use a default capture
mode, and then specify the opposite mode explicitly for specific variables. For example,
if a lambda body accesses the external variable total by reference and the external
variable factor by value, then the following capture clauses are equivalent:
C++
[&total, factor]
[factor, &total]
[&, factor]
[=, &total]
Only variables that are mentioned in the lambda body are captured when a capture-
default is used.
C++
void S::f(int i) {
[&, i]{}; // OK
[&, &i]{}; // ERROR: i preceded by & when & is the default
[=, this]{}; // ERROR: this when = is the default
[=, *this]{ }; // OK: captures this by value. See below.
[i, i]{}; // ERROR: i repeated
}
C++
template<class... Args>
void f(Args... args) {
auto x = [args...] { return g(args...); };
x();
}
To use lambda expressions in the body of a class member function, pass the this
pointer to the capture clause to provide access to the member functions and data
members of the enclosing class.
Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): The
this pointer may be captured by value by specifying *this in the capture clause.
Capture by value copies the entire closure to every call site where the lambda is invoked.
(A closure is the anonymous function object that encapsulates the lambda expression.)
Capture by value is useful when the lambda executes in parallel or asynchronous
operations. It's especially useful on certain hardware architectures, such as NUMA.
For an example that shows how to use lambda expressions with class member functions,
see "Example: Using a lambda expression in a method" in Examples of lambda
expressions.
When you use the capture clause, we recommend that you keep these points in mind,
particularly when you use lambdas with multi-threading:
Reference captures can be used to modify variables outside, but value captures
can't. ( mutable allows copies to be modified, but not originals.)
Reference captures reflect updates to variables outside, but value captures don't.
C++
pNums = make_unique<vector<int>>(nums);
//...
auto a = [ptr = move(pNums)]()
{
// use ptr
};
Parameter list
Lambdas can both capture variables and accept input parameters. A parameter list
(lambda declarator in the Standard syntax) is optional and in most aspects resembles the
parameter list for a function.
C++
auto y = [] (int first, int second)
{
return first + second;
};
In C++14, if the parameter type is generic, you can use the auto keyword as the type
specifier. This keyword tells the compiler to create the function call operator as a
template. Each instance of auto in a parameter list is equivalent to a distinct type
parameter.
C++
A lambda expression can take another lambda expression as its argument. For more
information, see "Higher-Order Lambda Expressions" in the article Examples of lambda
expressions.
Because a parameter list is optional, you can omit the empty parentheses if you don't
pass arguments to the lambda expression and its lambda-declarator doesn't contain
exception-specification, trailing-return-type, or mutable .
Mutable specification
Typically, a lambda's function call operator is const-by-value, but use of the mutable
keyword cancels this out. It doesn't produce mutable data members. The mutable
specification enables the body of a lambda expression to modify variables that are
captured by value. Some of the examples later in this article show how to use mutable .
Exception specification
You can use the noexcept exception specification to indicate that the lambda expression
doesn't throw any exceptions. As with ordinary functions, the Microsoft C++ compiler
generates warning C4297 if a lambda expression declares the noexcept exception
specification and the lambda body throws an exception, as shown here:
C++
// throw_lambda_expression.cpp
// compile with: /W4 /EHsc
int main() // C4297 expected
{
[]() noexcept { throw 5; }();
}
Return type
The return type of a lambda expression is automatically deduced. You don't have to use
the auto keyword unless you specify a trailing-return-type. The trailing-return-type
resembles the return-type part of an ordinary function or member function. However,
the return type must follow the parameter list, and you must include the trailing-return-
type keyword -> before the return type.
You can omit the return-type part of a lambda expression if the lambda body contains
just one return statement. Or, if the expression doesn't return a value. If the lambda
body contains one return statement, the compiler deduces the return type from the type
of the return expression. Otherwise, the compiler deduces the return type as void .
Consider the following example code snippets that illustrate this principle:
C++
A lambda expression can produce another lambda expression as its return value. For
more information, see "Higher-order lambda expressions" in Examples of lambda
expressions.
Lambda body
The lambda body of a lambda expression is a compound statement. It can contain
anything that's allowed in the body of an ordinary function or member function. The
body of both an ordinary function and a lambda expression can access these kinds of
variables:
Parameters.
Any variable that has static storage duration—for example, global variables.
The following example contains a lambda expression that explicitly captures the variable
n by value and implicitly captures the variable m by reference:
C++
// captures_lambda_expression.cpp
// compile with: /W4 /EHsc
#include <iostream>
using namespace std;
int main()
{
int m = 0;
int n = 0;
[&, n] (int a) mutable { m = ++n + a; }(4);
cout << m << endl << n << endl;
}
Output
5
0
Because the variable n is captured by value, its value remains 0 after the call to the
lambda expression. The mutable specification allows n to be modified within the
lambda.
A lambda expression can only capture variables that have automatic storage duration.
However, you can use variables that have static storage duration in the body of a
lambda expression. The following example uses the generate function and a lambda
expression to assign a value to each element in a vector object. The lambda expression
modifies the static variable to generate the value of the next element.
C++
void fillVector(vector<int>& v)
{
// A local static variable.
static int nextValue = 1;
The following code example uses the function from the previous example, and adds an
example of a lambda expression that uses the C++ Standard Library algorithm
generate_n . This lambda expression assigns an element of a vector object to the sum
of the previous two elements. The mutable keyword is used so that the body of the
lambda expression can modify its copies of the external variables x and y , which the
lambda expression captures by value. Because the lambda expression captures the
original variables x and y by value, their values remain 1 after the lambda executes.
C++
void fillVector(vector<int>& v)
{
// A local static variable.
static int nextValue = 1;
int main()
{
// The number of elements in the vector.
const int elementCount = 9;
// Create a vector object with each element set to 1.
vector<int> v(elementCount, 1);
Output
C++
int y = 32;
auto answer = [y]() constexpr
{
int x = 10;
return y + x;
};
C++
C++
Microsoft-specific
Lambdas aren't supported in the following common language runtime (CLR) managed
entities: ref class , ref struct , value class , or value struct .
If you're using a Microsoft-specific modifier such as __declspec, you can insert it into a
lambda expression immediately after the parameter-declaration-clause . For example:
C++
Visual Studio supports C++11 Standard lambda functionality, and stateless lambdas. A
stateless lambda is convertible to a function pointer that uses an arbitrary calling
convention.
See also
C++ Language Reference
Function Objects in the C++ Standard Library
Function Call
for_each
Lambda Expression Syntax
Article • 08/03/2021 • 4 minutes to read
This article demonstrates the syntax and structural elements of lambda expressions. For
a description of lambda expressions, see Lambda Expressions.
A lambda combines the benefits of function pointers and function objects and avoids
their disadvantages. Like a function object, a lambda is flexible and can maintain state,
but unlike a function object, its compact syntax doesn't require an explicit class
definition. By using lambdas, you can write code that's less cumbersome and less prone
to errors than the code for an equivalent function object.
The following examples compare the use of a lambda to the use of a function object.
The first example uses a lambda to print to the console whether each element in a
vector object is even or odd. The second example uses a function object to accomplish
Code
C++
// even_lambda.cpp
// compile with: cl /EHsc /nologo /W4 /MTd
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// Create a vector object that contains 9 elements.
vector<int> v;
for (int i = 1; i < 10; ++i) {
v.push_back(i);
}
Output
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd
There are 4 even numbers in the vector.
Comments
In the example, the third argument to the for_each function is a lambda. The
[&evenCount] part specifies the capture clause of the expression, (int n) specifies the
parameter list, and remaining part specifies the body of the expression.
For more information about the operator(), see Function Call. For more information
about the for_each function, see for_each.
Code
C++
// even_functor.cpp
// compile with: /EHsc
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class FunctorClass
{
public:
// The required constructor for this example.
explicit FunctorClass(int& evenCount)
: m_evenCount(evenCount) { }
if (n % 2 == 0) {
cout << " is even " << endl;
++m_evenCount;
} else {
cout << " is odd " << endl;
}
}
private:
// Default assignment operator to silence warning C4512.
FunctorClass& operator=(const FunctorClass&);
int main()
{
// Create a vector object that contains 9 elements.
vector<int> v;
for (int i = 1; i < 10; ++i) {
v.push_back(i);
}
Output
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd
There are 4 even numbers in the vector.
See also
Lambda Expressions
Examples of Lambda Expressions
generate
generate_n
for_each
Exception Specifications (throw)
Compiler Warning (level 1) C4297
Microsoft-Specific Modifiers
Examples of Lambda Expressions
Article • 08/17/2021 • 9 minutes to read
This article shows how to use lambda expressions in your programs. For an overview of
lambda expressions, see Lambda Expressions. For more information about the structure
of a lambda expression, see Lambda Expression Syntax.
Example 1
Because a lambda expression is typed, you can assign it to an auto variable or to a
function object, as shown here:
C++
// declaring_lambda_expressions1.cpp
// compile with: /EHsc /W4
#include <functional>
#include <iostream>
int main()
{
Output
5
7
Remarks
For more information, see auto, function Class, and Function Call.
Although lambda expressions are most often declared in the body of a function, you can
declare them anywhere that you can initialize a variable.
Example 2
The Microsoft C++ compiler binds a lambda expression to its captured variables when
the expression is declared instead of when the expression is called. The following
example shows a lambda expression that captures the local variable i by value and the
local variable j by reference. Because the lambda expression captures i by value, the
reassignment of i later in the program does not affect the result of the expression.
However, because the lambda expression captures j by reference, the reassignment of
j does affect the result of the expression.
C++
// declaring_lambda_expressions2.cpp
// compile with: /EHsc /W4
#include <functional>
#include <iostream>
int main()
{
using namespace std;
int i = 3;
int j = 5;
Output
47
Example 1
This example declares a lambda expression that returns the sum of two integers and
calls the expression immediately with the arguments 5 and 4 :
C++
// calling_lambda_expressions1.cpp
// compile with: /EHsc
#include <iostream>
int main()
{
using namespace std;
int n = [] (int x, int y) { return x + y; }(5, 4);
cout << n << endl;
}
Output
Example 2
This example passes a lambda expression as an argument to the find_if function. The
lambda expression returns true if its parameter is an even number.
C++
// calling_lambda_expressions2.cpp
// compile with: /EHsc /W4
#include <list>
#include <algorithm>
#include <iostream>
int main()
{
using namespace std;
Output
Remarks
For more information about the find_if function, see find_if. For more information
about the C++ Standard Library functions that perform common algorithms, see
<algorithm>.
C++
// nesting_lambda_expressions.cpp
// compile with: /EHsc /W4
#include <iostream>
int main()
{
using namespace std;
Output
13
Remarks
In this example, [](int y) { return y * 2; } is the nested lambda expression.
Example
Many programming languages support the concept of a higher-order function. A higher-
order function is a lambda expression that takes another lambda expression as its
argument or returns a lambda expression. You can use the function class to enable a
C++ lambda expression to behave like a higher-order function. The following example
shows a lambda expression that returns a function object and a lambda expression that
takes a function object as its argument.
C++
// higher_order_lambda_expression.cpp
// compile with: /EHsc /W4
#include <iostream>
#include <functional>
int main()
{
using namespace std;
Output
30
You can use the this pointer explicitly in a function, as shown here:
C++
// capture "this" by value (Visual Studio 2017 version 15.3 and later)
void ApplyScale2(const vector<int>& v) const
{
for_each(v.begin(), v.end(),
[*this](int n) { cout << n * _scale << endl; });
}
C++
The following example shows the Scale class, which encapsulates a scale value.
C++
// function_lambda_expression.cpp
// compile with: /EHsc /W4
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class Scale
{
public:
// The constructor.
explicit Scale(int scale) : _scale(scale) {}
private:
int _scale;
};
int main()
{
vector<int> values;
values.push_back(1);
values.push_back(2);
values.push_back(3);
values.push_back(4);
Output
3
6
9
12
Remarks
The ApplyScale function uses a lambda expression to print the product of the scale
value and each element in a vector object. The lambda expression implicitly captures
this so that it can access the _scale member.
[In This Article]
Example
Because lambda expressions are typed, you can use them with C++ templates. The
following example shows the negate_all and print_all functions. The negate_all
function applies the unary operator- to each element in the vector object. The
print_all function prints each element in the vector object to the console.
C++
// template_lambda_expression.cpp
// compile with: /EHsc
#include <vector>
#include <algorithm>
#include <iostream>
// Negates each element in the vector object. Assumes signed data type.
template <typename T>
void negate_all(vector<T>& v)
{
for_each(v.begin(), v.end(), [](T& n) { n = -n; });
}
int main()
{
// Create a vector of signed integers with a few elements.
vector<int> v;
v.push_back(34);
v.push_back(-43);
v.push_back(56);
print_all(v);
negate_all(v);
cout << "After negate_all():" << endl;
print_all(v);
}
The example produces this output:
Output
34
-43
56
After negate_all():
-34
43
-56
Remarks
For more information about C++ templates, see Templates.
Handling Exceptions
Example
The body of a lambda expression follows the rules for both structured exception
handling (SEH) and C++ exception handling. You can handle a raised exception in the
body of a lambda expression or defer exception handling to the enclosing scope. The
following example uses the for_each function and a lambda expression to fill a vector
object with the values of another one. It uses a try / catch block to handle invalid access
to the first vector.
C++
// eh_lambda_expression.cpp
// compile with: /EHsc /W4
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
// Create a vector that contains 3 elements.
vector<int> elements(3);
Output
Remarks
For more information about exception handling, see Exception Handling.
Example
The capture clause of a lambda expression cannot contain a variable that has a
managed type. However, you can pass an argument that has a managed type to the
parameter list of a lambda expression. The following example contains a lambda
expression that captures the local unmanaged variable ch by value and takes a
System.String object as its parameter.
C++
// managed_lambda_expression.cpp
// compile with: /clr
using namespace System;
int main()
{
char ch = '!'; // a local unmanaged variable
Output
Hello!
Remarks
You can also use lambda expressions with the STL/CLR library. For more information, see
STL/CLR Library Reference.
) Important
Lambdas are not supported in these common language runtime (CLR) managed
entities: ref class , ref struct , value class , and value struct .
See also
Lambda Expressions
Lambda Expression Syntax
auto
function Class
find_if
<algorithm>
Function Call
Templates
Exception Handling
STL/CLR Library Reference
constexpr lambda expressions in C++
Article • 08/17/2021 • 2 minutes to read
Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): A
lambda expression may be declared as constexpr or used in a constant expression when
the initialization of each data member that it captures or introduces is allowed within a
constant expression.
C++
int y = 32;
auto answer = [y]() constexpr
{
int x = 10;
return y + x;
};
C++
C++
An array is a sequence of objects of the same type that occupy a contiguous area of
memory. Traditional C-style arrays are the source of many bugs, but are still common,
especially in older code bases. In modern C++, we strongly recommend using
std::vector or std::array instead of C-style arrays described in this section. Both of these
standard library types store their elements as a contiguous block of memory. However,
they provide greater type safety, and support iterators that are guaranteed to point to a
valid location within the sequence. For more information, see Containers.
Stack declarations
In a C++ array declaration, the array size is specified after the variable name, not after
the type name as in some other languages. The following example declares an array of
1000 doubles to be allocated on the stack. The number of elements must be supplied as
an integer literal or else as a constant expression. That's because the compiler has to
know how much stack space to allocate; it can't use a value computed at run-time. Each
element in the array is assigned a default value of 0. If you don't assign a default value,
each element initially contains whatever random values happen to be at that memory
location.
C++
A zero-sized array is legal only when the array is the last field in a struct or union and
when the Microsoft extensions are enabled ( /Za or /permissive- isn't set).
Stack-based arrays are faster to allocate and access than heap-based arrays. However,
stack space is limited. The number of array elements can't be so large that it uses up too
much stack memory. How much is too much depends on your program. You can use
profiling tools to determine whether an array is too large.
Heap declarations
You may require an array that's too large to allocate on the stack, or whose size isn't
known at compile time. It's possible to allocate this array on the heap by using a new[]
expression. The operator returns a pointer to the first element. The subscript operator
works on the pointer variable the same way it does on a stack-based array. You can also
use pointer arithmetic to move the pointer to any arbitrary elements in the array. It's
your responsibility to ensure that:
you always keep a copy of the original pointer address so that you can delete the
memory when you no longer need the array.
you don't increment or decrement the pointer address past the array bounds.
The following example shows how to define an array on the heap at run time. It shows
how to access the array elements using the subscript operator and by using pointer
arithmetic:
C++
// Alternate method:
// Reset p to numbers[0]:
p = numbers;
}
int main()
{
do_something(108);
}
Initializing arrays
You can initialize an array in a loop, one element at a time, or in a single statement. The
contents of the following two arrays are identical:
C++
int a[10];
for (int i = 0; i < 10; ++i)
{
a[i] = i + 1;
}
int b[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
The following example shows a function that accepts an array and a length. The pointer
points to the original array, not a copy. Because the parameter isn't const , the function
can modify the array elements.
C++
Declare and define the array parameter p as const to make it read-only within the
function block:
C++
The same function can also be declared in these ways, with no change in behavior. The
array is still passed as a pointer to the first element:
C++
// Unsized array
void process(const double p[], const size_t len);
// Fixed-size array. Length must still be specified explicitly.
void process(const double p[1000], const size_t len);
Multidimensional arrays
Arrays constructed from other arrays are multidimensional arrays. These
multidimensional arrays are specified by placing multiple bracketed constant
expressions in sequence. For example, consider this declaration:
C++
int i2[5][7];
The image is a grid 7 cells wide and 5 cells high. Each cell contains the index of the cell.
The first cell index is labeled 0,0. The next cell in that row is 0,1 and so on to the last cell
in that row which is 0,6. The next row starts with the index 1,0. The cell after that has an
index of 1,1. The last cell in that row is 1,6. This pattern repeats until the last row, which
starts with the index 4,0. The the last cell in the last row has an index of 4,6. :::image-end
You can declare multidimensioned arrays that have an initializer list (as described in
Initializers). In these declarations, the constant expression that specifies the bounds for
the first dimension can be omitted. For example:
C++
// arrays2.cpp
// compile with: /c
const int cMarkets = 4;
// Declare a float that represents the transportation costs.
double TransportCosts[][cMarkets] = {
{ 32.19, 47.29, 31.99, 19.11 },
{ 11.29, 22.49, 33.47, 17.29 },
{ 41.97, 22.09, 9.76, 22.55 }
};
The preceding declaration defines an array that is three rows by four columns. The rows
represent factories and the columns represent markets to which the factories ship. The
values are the transportation costs from the factories to the markets. The first dimension
of the array is left out, but the compiler fills it in by examining the initializer.
Use of the indirection operator (*) on an n-dimensional array type yields an n-1
dimensional array. If n is 1, a scalar (or array element) is yielded.
C++ arrays are stored in row-major order. Row-major order means the last subscript
varies the fastest.
Example
You can also omit the bounds specification for the first dimension of a multidimensional
array in function declarations, as shown here:
C++
// multidimensional_arrays.cpp
// compile with: /EHsc
// arguments: 3
#include <limits> // Includes DBL_MAX
#include <iostream>
if (argv[1] == 0) {
cout << "You must specify the number of markets." << endl;
exit(0);
}
MinCost = FindMinToMkt( *argv[1] - '0', TransportCosts, cFacts);
cout << "The minimum cost to Market " << argv[1] << " is: "
<< MinCost << "\n";
}
return MinCost;
}
Output
The function FindMinToMkt is written such that adding new factories doesn't require any
code changes, just a recompilation.
Initializing Arrays
Arrays of objects that have a class constructor are initialized by the constructor. When
there are fewer items in the initializer list than elements in the array, the default
constructor is used for the remaining elements. If no default constructor is defined for
the class, the initializer list must be complete, that is, there must be one initializer for
each element in the array.
C++
// initializing_arrays1.cpp
class Point
{
public:
Point() // Default constructor.
{
}
Point( int, int ) // Construct from two ints
{
}
};
int main()
{
}
The first element of aPoint is constructed using the constructor Point( int, int ) ; the
remaining two elements are constructed using the default constructor.
Static member arrays (whether const or not) can be initialized in their definitions
(outside the class declaration). For example:
C++
// initializing_arrays2.cpp
class WindowColors
{
public:
static const char *rgszWindowPartList[7];
};
C++
// using_arrays.cpp
int main() {
char chArray[10];
char *pch = chArray; // Evaluates to a pointer to the first element.
char ch = chArray[0]; // Evaluates to the value of the first element.
ch = chArray[3]; // Evaluates to the value of the fourth element.
}
When you use multidimensional arrays, you can use various combinations in
expressions.
C++
// using_arrays_2.cpp
// compile with: /EHsc /W1
#include <iostream>
using namespace std;
int main() {
double multi[4][4][3]; // Declare the array.
double (*p2multi)[3];
double (*p1multi);
In the preceding code, multi is a three-dimensional array of type double . The p2multi
pointer points to an array of type double of size three. In this example, the array is used
with one, two, and three subscripts. Although it's more common to specify all subscripts,
as in the cout statement, sometimes it's useful to select a specific subset of array
elements, as shown in the statements that follow cout .
*((array_name) + (subscript))
As in all addition that involves pointer types, scaling is done automatically to adjust for
the size of the type. The resultant value isn't n bytes from the origin of array_name ;
instead, it's the nth element of the array. For more information about this conversion,
see Additive operators.
Similarly, for multidimensional arrays, the address is derived using the following method:
C++
The pointer psz points to the first element of the array szError1 . Arrays, unlike pointers,
aren't modifiable l-values. That's why the following assignment is illegal:
C++
szError1 = psz;
See also
std::array
References (C++)
Article • 08/03/2021 • 2 minutes to read
A reference, like a pointer, stores the address of an object that is located elsewhere in
memory. Unlike a pointer, a reference after it is initialized cannot be made to refer to a
different object or set to null. There are two kinds of references: lvalue references which
refer to a named variable and rvalue references which refer to a temporary object. The &
operator signifies an lvalue reference and the && operator signifies either an rvalue
reference, or a universal reference (either rvalue or lvalue) depending on the context.
Any valid declarator specifying a reference may be used. Unless the reference is a
reference to function or array type, the following simplified syntax applies:
2. The declarator:
The identifier.
3. An optional initializer.
The more complex declarator forms for pointers to arrays and functions also apply to
references to arrays and functions. For more information, see pointers.
C++
int &i;
int &i, &j;
C++
A reference holds the address of an object, but behaves syntactically like an object.
In the following program, notice that the name of the object, s , and the reference to
the object, SRef , can be used identically in programs:
Example
C++
// references.cpp
#include <stdio.h>
struct S {
short i;
};
int main() {
S s; // Declare the object.
S& SRef = s; // Declare the reference.
s.i = 3;
printf_s("%d\n", s.i);
printf_s("%d\n", SRef.i);
SRef.i = 4;
printf_s("%d\n", s.i);
printf_s("%d\n", SRef.i);
}
Output
3
3
4
4
See also
Reference-Type Function Arguments
Reference-Type Function Returns
References to Pointers
Lvalue reference declarator: &
Article • 11/23/2021 • 2 minutes to read
Syntax
lvalue-reference-type-id :
Remarks
You can think of an lvalue reference as another name for an object. An lvalue reference
declaration consists of an optional list of specifiers followed by a reference declarator. A
reference must be initialized and cannot be changed.
Any object whose address can be converted to a given pointer type can also be
converted to the similar reference type. For example, any object whose address can be
converted to type char * can also be converted to type char & .
Don't confuse reference declarations with use of the address-of operator. When the
& identifier is preceded by a type, such as int or char , identifier is declared as a
reference to the type. When & identifier is not preceded by a type, the usage is that of
the address-of operator.
Example
The following example demonstrates the reference declarator by declaring a Person
object and a reference to that object. Because rFriend is a reference to myFriend ,
updating either variable changes the same object.
C++
// reference_declarator.cpp
// compile with: /EHsc
// Demonstrates the reference declarator.
#include <iostream>
using namespace std;
struct Person
{
char* Name;
short Age;
};
int main()
{
// Declare a Person object.
Person myFriend;
Output
Bill is 40
See also
References
Reference-type function arguments
Reference-type function returns
References to pointers
Rvalue reference declarator: &&
Article • 09/28/2022 • 12 minutes to read
Syntax
rvalue-reference-type-id :
Remarks
Rvalue references enable you to distinguish an lvalue from an rvalue. Lvalue references
and rvalue references are syntactically and semantically similar, but they follow slightly
different rules. For more information about lvalues and rvalues, see Lvalues and Rvalues.
For more information about lvalue references, see Lvalue Reference Declarator: &.
The following sections describe how rvalue references support the implementation of
move semantics and perfect forwarding.
Move semantics
Rvalue references support the implementation of move semantics, which can
significantly increase the performance of your applications. Move semantics enables you
to write code that transfers resources (such as dynamically allocated memory) from one
object to another. Move semantics works because it enables transfer of resources from
temporary objects: ones that can't be referenced elsewhere in the program.
To implement move semantics, you typically provide a move constructor, and optionally a
move assignment operator ( operator= ), to your class. Copy and assignment operations
whose sources are rvalues then automatically take advantage of move semantics. Unlike
the default copy constructor, the compiler doesn't provide a default move constructor.
For more information about how to write and use a move constructor, see Move
constructors and move assignment operators.
You can also overload ordinary functions and operators to take advantage of move
semantics. Visual Studio 2010 introduces move semantics into the C++ Standard Library.
For example, the string class implements operations that use move semantics.
Consider the following example that concatenates several strings and prints the result:
C++
// string_concatenation.cpp
// compile with: /EHsc
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = string("h") + "e" + "ll" + "o";
cout << s << endl;
}
Before Visual Studio 2010, each call to operator+ allocates and returns a new temporary
string object (an rvalue). operator+ can't append one string to the other because it
doesn't know whether the source strings are lvalues or rvalues. If the source strings are
both lvalues, they might be referenced elsewhere in the program, and so must not be
modified. You can modify operator+ to take rvalues by using rvalue references, which
can't be referenced elsewhere in the program. With this change, operator+ can now
append one string to another. The change significantly reduces the number of dynamic
memory allocations that the string class must make. For more information about the
string class, see basic_string Class.
Move semantics also helps when the compiler can't use Return Value Optimization
(RVO) or Named Return Value Optimization (NRVO). In these cases, the compiler calls
the move constructor if the type defines it.
To better understand move semantics, consider the example of inserting an element into
a vector object. If the capacity of the vector object is exceeded, the vector object
must reallocate enough memory for its elements, and then copy each element to
another memory location to make room for the inserted element. When an insertion
operation copies an element, it first creates a new element. Then it calls the copy
constructor to copy the data from the previous element to the new element. Finally, it
destroys the previous element. Move semantics enables you to move objects directly
without having to make expensive memory allocation and copy operations.
To take advantage of move semantics in the vector example, you can write a move
constructor to move data from one object to another.
For more information about the introduction of move semantics into the C++ Standard
Library in Visual Studio 2010, see C++ Standard Library.
Perfect forwarding
Perfect forwarding reduces the need for overloaded functions and helps avoid the
forwarding problem. The forwarding problem can occur when you write a generic
function that takes references as its parameters. If it passes (or forwards) these
parameters to another function, for example, if it takes a parameter of type const T& ,
then the called function can't modify the value of that parameter. If the generic function
takes a parameter of type T& , then the function can't be called by using an rvalue (such
as a temporary object or integer literal).
Ordinarily, to solve this problem, you must provide overloaded versions of the generic
function that take both T& and const T& for each of its parameters. As a result, the
number of overloaded functions increases exponentially with the number of parameters.
Rvalue references enable you to write one version of a function that accepts arbitrary
arguments. Then that function can forward them to another function as if the other
function had been called directly.
Consider the following example that declares four types, W , X , Y , and Z . The
constructor for each type takes a different combination of const and non- const lvalue
references as its parameters.
C++
struct W
{
W(int&, int&) {}
};
struct X
{
X(const int&, int&) {}
};
struct Y
{
Y(int&, const int&) {}
};
struct Z
{
Z(const int&, const int&) {}
};
Suppose you want to write a generic function that generates objects. The following
example shows one way to write this function:
C++
C++
int a = 4, b = 5;
W* pw = factory<W>(a, b);
However, the following example doesn't contain a valid call to the factory function. It's
because factory takes lvalue references that are modifiable as its parameters, but it's
called by using rvalues:
C++
Z* pz = factory<Z>(2, 2);
Ordinarily, to solve this problem, you must create an overloaded version of the factory
function for every combination of A& and const A& parameters. Rvalue references
enable you to write one version of the factory function, as shown in the following
example:
C++
This example uses rvalue references as the parameters to the factory function. The
purpose of the std::forward function is to forward the parameters of the factory function
to the constructor of the template class.
The following example shows the main function that uses the revised factory function
to create instances of the W , X , Y , and Z classes. The revised factory function forwards
its parameters (either lvalues or rvalues) to the appropriate class constructor.
C++
int main()
{
int a = 4, b = 5;
W* pw = factory<W>(a, b);
X* px = factory<X>(2, b);
Y* py = factory<Y>(a, 2);
Z* pz = factory<Z>(2, 2);
delete pw;
delete px;
delete py;
delete pz;
}
C++
// reference-overload.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;
void f(MemoryBlock&&)
{
cout << "In f(MemoryBlock&&). This version can modify the parameter." <<
endl;
}
int main()
{
MemoryBlock block;
f(block);
f(MemoryBlock());
}
Output
In this example, the first call to f passes a local variable (an lvalue) as its argument. The
second call to f passes a temporary object as its argument. Because the temporary
object can't be referenced elsewhere in the program, the call binds to the overloaded
version of f that takes an rvalue reference, which is free to modify the object.
The compiler treats a named rvalue reference as an lvalue and an unnamed rvalue
reference as an rvalue.
Functions that take an rvalue reference as a parameter treat the parameter as an lvalue
in the body of the function. The compiler treats a named rvalue reference as an lvalue.
It's because a named object can be referenced by several parts of a program. It's
dangerous to allow multiple parts of a program to modify or remove resources from
that object. For example, if multiple parts of a program try to transfer resources from the
same object, only the first transfer succeeds.
The following example shows the function g , which is overloaded to take an lvalue
reference and an rvalue reference. The function f takes an rvalue reference as its
parameter (a named rvalue reference) and returns an rvalue reference (an unnamed
rvalue reference). In the call to g from f , overload resolution selects the version of g
that takes an lvalue reference because the body of f treats its parameter as an lvalue. In
the call to g from main , overload resolution selects the version of g that takes an rvalue
reference because f returns an rvalue reference.
C++
// named-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;
void g(MemoryBlock&&)
{
cout << "In g(MemoryBlock&&)." << endl;
}
int main()
{
g(f(MemoryBlock()));
}
C++
In g(const MemoryBlock&).
In g(MemoryBlock&&).
In the example, the main function passes an rvalue to f . The body of f treats its named
parameter as an lvalue. The call from f to g binds the parameter to an lvalue reference
(the first overloaded version of g ).
The C++ Standard Library std::move function enables you to convert an object to an
rvalue reference to that object. You can also use the static_cast keyword to cast an
lvalue to an rvalue reference, as shown in the following example:
C++
// cast-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;
void g(MemoryBlock&&)
{
cout << "In g(MemoryBlock&&)." << endl;
}
int main()
{
MemoryBlock block;
g(block);
g(static_cast<MemoryBlock&&>(block));
}
C++
In g(const MemoryBlock&).
In g(MemoryBlock&&).
Function templates deduce their template argument types and then use reference
collapsing rules.
A function template that passes (or forwards) its parameters to another function is a
common pattern. It's important to understand how template type deduction works for
function templates that take rvalue references.
deduction deduces T to be X , so the parameter has type X&& . If the function argument
is an lvalue or const lvalue, the compiler deduces its type to be an lvalue reference or
const lvalue reference of that type.
The following example declares one structure template and then specializes it for
various reference types. The print_type_and_value function takes an rvalue reference as
its parameter and forwards it to the appropriate specialized version of the S::print
method. The main function demonstrates the various ways to call the S::print method.
C++
// template-type-deduction.cpp
// Compile with: /EHsc
#include <iostream>
#include <string>
using namespace std;
int main()
{
// The following call resolves to:
// print_type_and_value<string&>(string& && t)
// Which collapses to:
// print_type_and_value<string&>(string& t)
string s1("first");
print_type_and_value(s1);
C++
print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth
To resolve each call to the print_type_and_value function, the compiler first does
template argument deduction. The compiler then applies reference collapsing rules
when it replaces the parameter types with the deduced template arguments. For
example, passing the local variable s1 to the print_type_and_value function causes the
compiler to produce the following function signature:
C++
print_type_and_value<string&>(string& && t)
The compiler uses reference collapsing rules to reduce the signature:
C++
print_type_and_value<string&>(string& t)
This version of the print_type_and_value function then forwards its parameter to the
correct specialized version of the S::print method.
The following table summarizes the reference collapsing rules for template argument
type deduction:
Summary
Rvalue references distinguish lvalues from rvalues. To improve the performance of your
applications, they can eliminate the need for unnecessary memory allocations and copy
operations. They also enable you to write a function that accepts arbitrary arguments.
That function can forward them to another function as if the other function had been
called directly.
See also
Expressions with unary operators
Lvalue reference declarator: &
Lvalues and rvalues
Move constructors and move assignment operators (C++)
C++ Standard Library
Reference-Type Function Arguments
Article • 08/03/2021 • 2 minutes to read
It is often more efficient to pass references, rather than large objects, to functions. This
allows the compiler to pass the address of the object while maintaining the syntax that
would have been used to access the object. Consider the following example that uses
the Date structure:
C++
// reference_type_function_arguments.cpp
#include <iostream>
struct Date
{
short Month;
short Day;
short Year;
};
// Add in year.
dateOfYear *= 10000;
dateOfYear += date.Year;
return dateOfYear;
}
int main()
{
Date date{ 8, 27, 2018 };
long dateOfYear = DateOfYear(date);
std::cout << dateOfYear << std::endl;
}
The preceding code shows that members of a structure passed by reference are
accessed using the member-selection operator (.) instead of the pointer member-
selection operator (->).
Although arguments passed as reference types observe the syntax of non-pointer types,
they retain one important characteristic of pointer types: they are modifiable unless
declared as const . Because the intent of the preceding code is not to modify the object
date , a more appropriate function prototype is:
C++
This prototype guarantees that the function DateOfYear will not change its argument.
Any function prototyped as taking a reference type can accept an object of the same
type in its place because there is a standard conversion from typename to typename&.
See also
References
Reference-Type Function Returns
Article • 10/17/2022 • 2 minutes to read
Functions can be declared to return a reference type. There are two reasons to make
such a declaration:
The information being returned is a large enough object that returning a reference
is more efficient than returning a copy.
The referred-to object will not go out of scope when the function returns.
Just as it can be more efficient to pass large objects to functions by reference, it also can
be more efficient to return large objects from functions by reference. Reference-return
protocol eliminates the necessity of copying the object to a temporary location prior to
returning.
Reference-return types can also be useful when the function must evaluate to an l-value.
Most overloaded operators fall into this category, particularly the assignment operator.
Overloaded operators are covered in Overloaded Operators.
Example
Consider the Point example:
C++
// refType_function_returns.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Point
{
public:
// Define "accessor" functions as
// reference types.
unsigned& x();
unsigned& y();
private:
// Note that these are declared at class scope:
unsigned obj_x;
unsigned obj_y;
};
unsigned& Point :: x()
{
return obj_x;
}
unsigned& Point :: y()
{
return obj_y;
}
int main()
{
Point ThePoint;
// Use x() and y() as l-values.
ThePoint.x() = 7;
ThePoint.y() = 9;
Output
Output
x = 7
y = 9
Notice that the functions x and y are declared as returning reference types. These
functions can be used on either side of an assignment statement.
Note also that in main, ThePoint object remains in scope, and therefore its reference
members are still alive and can be safely accessed.
Declarations of reference types must contain initializers except in the following cases:
C++
The compiler issues a warning in this case: warning C4172: returning address of local
variable or temporary . In simple programs it is possible that occasionally no access
violation will occur if the reference is accessed by the caller before the memory location
is overwritten. This is due to sheer luck. Heed the warning.
See also
References
References to pointers
Article • 08/03/2021 • 2 minutes to read
References to pointers can be declared in much the same way as references to objects.
A reference to a pointer is a modifiable value that's used like a normal pointer.
Example
This code sample shows the difference between using a pointer to a pointer and a
reference to a pointer.
Functions Add1 and Add2 are functionally equivalent, although they're not called the
same way. The difference is that Add1 uses double indirection, but Add2 uses the
convenience of a reference to a pointer.
C++
// references_to_pointers.cpp
// compile with: /EHsc
#include <iostream>
#include <string>
enum {
sizeOfBuffer = 132
};
if ( strlen( szBuf ) ) {
switch ( *argv[1] ) {
// Method 1: Use double indirection.
case '1':
Add1( &btRoot, szBuf );
break;
// Method 2: Use reference to a pointer.
case '2':
Add2( btRoot, szBuf );
break;
default:
cerr << "Illegal value '"
<< *argv[1]
<< "' supplied for add method.\n"
<< "Choose 1 or 2.\n";
return -1;
}
}
}
// Display the sorted list.
PrintTree( btRoot );
}
Output
Usage: references_to_pointers.exe [1 | 2]
where:
1 uses double indirection
2 uses a reference to a pointer.
See also
References
Pointers (C++)
Article • 08/03/2021 • 2 minutes to read
A pointer is a variable that stores the memory address of an object. Pointers are used
extensively in both C and C++ for three main purposes:
In C-style programming, raw pointers are used for all these scenarios. However, raw
pointers are the source of many serious programming errors. Therefore, their use is
strongly discouraged except where they provide a significant performance benefit and
there is no ambiguity as to which pointer is the owning pointer that is responsible for
deleting the object. Modern C++ provides smart pointers for allocating objects, iterators
for traversing data structures, and lambda expressions for passing functions. By using
these language and library facilities instead of raw pointers, you will make your program
safer, easier to debug, and simpler to understand and maintain. See Smart pointers,
Iterators, and Lambda expressions for more information.
In this section
Raw pointers
Const and volatile pointers
new and delete operators
Smart pointers
How to: Create and use unique_ptr instances
How to: Create and use shared_ptr instances
How to: Create and use weak_ptr instances
How to: Create and use CComPtr and CComQIPtr instances
See also
Iterators
Lambda expressions
Raw pointers (C++)
Article • 11/07/2022 • 9 minutes to read
A pointer is a type of variable. It stores the address of an object in memory, and is used
to access that object. A raw pointer is a pointer whose lifetime isn't controlled by an
encapsulating object, such as a smart pointer. A raw pointer can be assigned the
address of another non-pointer variable, or it can be assigned a value of nullptr. A
pointer that hasn't been assigned a value contains random data.
A pointer can also be dereferenced to retrieve the value of the object that it points at.
The member access operator provides access to an object's members.
C++
A pointer can point to a typed object or to void . When a program allocates an object
on the heap in memory, it receives the address of that object in the form of a pointer.
Such pointers are called owning pointers. An owning pointer (or a copy of it) must be
used to explicitly free the heap-allocated object when it's no longer needed. Failure to
free the memory results in a memory leak, and renders that memory location
unavailable to any other program on the machine. Memory allocated using new must be
freed by using delete (or delete[] ). For more information, see new and delete
operators.
C++
C++
// declare a C-style string. Compiler adds terminating '\0'.
const char* str = "Hello world";
const int c = 1;
const int* pconst = &c; // declare a non-const pointer to const int
const int c2 = 2;
pconst = &c2; // OK pconst itself isn't const
const int* const pconst2 = &c;
// pconst2 = &c2; // Error! pconst2 is const.
On 64-bit operating systems, a pointer has a size of 64 bits. A system's pointer size
determines how much addressable memory it can have. All copies of a pointer point to
the same memory location. Pointers (along with references) are used extensively in C++
to pass larger objects to and from functions. It's often more efficient to copy an object's
address than to copy the entire object. When defining a function, specify pointer
parameters as const unless you intend the function to modify the object. In general,
const references are the preferred way to pass objects to functions unless the value of
the object can possibly be nullptr .
Pointers to functions enable functions to be passed to other functions. They're used for
"callbacks" in C-style programming. Modern C++ uses lambda expressions for this
purpose.
C++
#include <iostream>
#include <string>
class MyClass
{
public:
int num;
std::string name;
void print() { std::cout << name << ":" << num << std::endl; }
};
int main()
{
// Use the * operator to declare a pointer type
// Use new to allocate and initialize memory
MyClass* pmc = new MyClass{ 108, "Nick" };
// Copy the pointer. Now pmc and pmc2 point to same object!
MyClass* pmc2 = pmc;
C++
#include <iostream>
int main()
{
Certain arithmetic operations can be used on non- const pointers to make them point
to another memory location. Pointers are incremented and decremented using the ++ ,
+= , -= and -- operators. This technique can be used in arrays and is especially useful in
buffers of untyped data. A void* gets incremented by the size of a char (1 byte). A
typed pointer gets incremented by size of the type it points to.
The following example demonstrates how pointer arithmetic can be used to access
individual pixels in a bitmap on Windows. Note the use of new and delete , and the
dereference operator.
C++
#include <Windows.h>
#include <fstream>
int main()
{
BITMAPINFOHEADER header;
header.biHeight = 100; // Multiple of 4 for simplicity.
header.biWidth = 100;
header.biBitCount = 24;
header.biPlanes = 1;
header.biCompression = BI_RGB;
header.biSize = sizeof(BITMAPINFOHEADER);
BITMAPFILEHEADER bf;
bf.bfType = 0x4D42;
bf.bfSize = header.biSize + 14 + bufferSize;
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //54
wf.write(reinterpret_cast<char*>(&bf), sizeof(bf));
wf.write(reinterpret_cast<char*>(&header), sizeof(header));
wf.write(reinterpret_cast<char*>(begin), bufferSize);
void* pointers
A pointer to void simply points to a raw memory location. Sometimes it's necessary to
use void* pointers, for example when passing between C++ code and C functions.
When a typed pointer is cast to a void pointer, the contents of the memory location are
unchanged. However, the type information is lost, so that you can't do increment or
decrement operations. A memory location can be cast, for example, from MyClass* to
void* and back again to MyClass* . Such operations are inherently error-prone and
require great care to avoid errors. Modern C++ discourages the use of void pointers in
almost all circumstances.
C++
//func.c
void func(void* data, int length)
{
char* c = (char*)(data);
// main.cpp
#include <iostream>
extern "C"
{
void func(void* data, int length);
}
class MyClass
{
public:
int num;
std::string name;
void print() { std::cout << name << ":" << num << std::endl; }
};
int main()
{
MyClass* mc = new MyClass{10, "Marian"};
void* p = static_cast<void*>(mc);
MyClass* mc2 = static_cast<MyClass*>(p);
std::cout << mc2->name << std::endl; // "Marian"
delete(mc);
Pointers to functions
In C-style programming, function pointers are used primarily to pass functions to other
functions. This technique allows the caller to customize the behavior of a function
without modifying it. In modern C++, lambda expressions provide the same capability
with greater type safety and other advantages.
A function pointer declaration specifies the signature that the pointed-to function must
have:
C++
The following example shows a function combine that takes as a parameter any function
that accepts a std::string and returns a std::string . Depending on the function that's
passed to combine , it either prepends or appends a string.
C++
#include <iostream>
#include <string>
string append(string s)
{
return base.append(" ").append(s);
}
string prepend(string s)
{
return s.append(" ").append(base);
}
int main()
{
cout << combine("from MSVC", append) << "\n";
cout << combine("Good morning and", prepend) << "\n";
}
See also
Smart pointers Indirection Operator: *
Address-of Operator: &
Welcome back to C++
const and volatile pointers
Article • 08/03/2021 • 3 minutes to read
The const and volatile keywords change how pointers are treated. The const keyword
specifies that the pointer cannot be modified after initialization; the pointer is protected
from modification thereafter.
The volatile keyword specifies that the value associated with the name that follows
can be modified by actions other than those in the user application. Therefore, the
volatile keyword is useful for declaring objects in shared memory that can be accessed
by multiple processes or global data areas used for communication with interrupt
service routines.
When a name is declared as volatile , the compiler reloads the value from memory
each time it is accessed by the program. This dramatically reduces the possible
optimizations. However, when the state of an object can change unexpectedly, it is the
only way to ensure predictable program performance.
To declare the object pointed to by the pointer as const or volatile , use a declaration
of the form:
C++
To declare the value of the pointer — that is, the actual address stored in the pointer —
as const or volatile , use a declaration of the form:
C++
The C++ language prevents assignments that would allow modification of an object or
pointer declared as const . Such assignments would remove the information that the
object or pointer was declared with, thereby violating the intent of the original
declaration. Consider the following declarations:
C++
const char cch = 'A';
char ch = 'B';
Given the preceding declarations of two objects ( cch , of type const char, and ch , of
type char), the following declaration/initializations are valid:
C++
C++
The declaration of pch2 declares a pointer through which a constant object might be
modified and is therefore disallowed. The declaration of pch3 specifies that the pointer
is constant, not the object; the declaration is disallowed for the same reason the pch2
declaration is disallowed.
The following eight assignments show assigning through pointer and changing of
pointer value for the preceding declarations; for now, assume that the initialization was
correct for pch1 through pch8 .
C++
Pointers declared as volatile , or as a mixture of const and volatile , obey the same
rules.
Pointers to const objects are often used in function declarations as follows:
C++
The preceding statement declares a function, strcpy_s, where two of the three
arguments are of type pointer to char . Because the arguments are passed by reference
and not by value, the function would be free to modify both strDestination and
strSource if strSource were not declared as const . The declaration of strSource as
const assures the caller that strSource cannot be changed by the called function.
7 Note
A const pointer of a given type can be assigned to a pointer of the same type. However,
a pointer that is not const cannot be assigned to a const pointer. The following code
shows correct and incorrect assignments:
C++
// const_pointer.cpp
int *const cpObject = 0;
int *pObject;
int main() {
pObject = cpObject;
cpObject = pObject; // C3892
}
The following sample shows how to declare an object as const if you have a pointer to a
pointer to an object.
C++
// const_pointer2.cpp
struct X {
X(int i) : m_i(i) { }
int m_i;
};
int main() {
// correct
const X cx(10);
const X * pcx = &cx;
const X ** ppcx = &pcx;
// also correct
X const cx2(20);
X const * pcx2 = &cx2;
X const ** ppcx2 = &pcx2;
}
See also
Pointers Raw pointers
new and delete operators
Article • 05/30/2022 • 7 minutes to read
C++ supports dynamic allocation and deallocation of objects using the new and delete
operators. These operators allocate memory for objects from a pool called the free store
(also known as the heap). The new operator calls the special function operator new, and
the delete operator calls the special function operator delete.
For a list of the library files in the C Runtime Library and the C++ Standard Library, see
CRT Library Features.
C++
If the request is for zero bytes of storage, operator new returns a pointer to a distinct
object. That is, repeated calls to operator new return different pointers.
If there's insufficient memory for the allocation request, operator new throws a
std::bad_alloc exception. Or, it returns nullptr if you've used the placement form
The two scopes for operator new functions are described in the following table.
Operator Scope
The first argument of operator new must be of type size_t , and the return type is
always void* .
The global operator new function is called when the new operator is used to allocate
objects of built-in types, objects of class type that don't contain user-defined operator
new functions, and arrays of any type. When the new operator is used to allocate objects
of a class type where an operator new is defined, that class's operator new is called.
An operator new function defined for a class is a static member function (which can't be
virtual) that hides the global operator new function for objects of that class type.
Consider the case where new is used to allocate and set memory to a given value:
C++
#include <malloc.h>
#include <memory.h>
class Blanks
{
public:
Blanks(){}
void *operator new( size_t stAllocateBlock, char chInit );
};
void *Blanks::operator new( size_t stAllocateBlock, char chInit )
{
void *pvTemp = malloc( stAllocateBlock );
if( pvTemp != 0 )
memset( pvTemp, chInit, stAllocateBlock );
return pvTemp;
}
// For discrete objects of type Blanks, the global operator new function
// is hidden. Therefore, the following code allocates an object of type
// Blanks and initializes it to 0xa5
int main()
{
Blanks *a5 = new(0xa5) Blanks;
return a5 != 0;
}
C++
The compiler supports member array new and delete operators in a class declaration.
For example:
C++
class MyClass
{
public:
void * operator new[] (size_t)
{
return 0;
}
void operator delete[] (void*)
{
}
};
int main()
{
MyClass *pMyClass = new MyClass[5];
delete [] pMyClass;
}
Older C++ code returned a null pointer for a failed allocation. If you have code that
expects the non-throwing version of new , link your program with nothrownew.obj . The
nothrownew.obj file replaces global operator new with a version that returns nullptr if
an allocation fails. operator new no longer throws std::bad_alloc . For more information
about nothrownew.obj and other linker option files, see Link options.
You can't mix code that checks for exceptions from global operator new with code that
checks for null pointers in the same application. However, you can still create class-local
operator new that behaves differently. This possibility means the compiler must act
defensively by default and include checks for null pointer returns in new calls. For more
information on a way to optimize these compiler checks, see /Zc:throwingnew.
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
try {
int *pI = new int[BIG_NUMBER];
}
catch (bad_alloc& ex) {
cout << "Caught bad_alloc: " << ex.what() << endl;
return -1;
}
}
When you use the nothrow form of new , you can test for an allocation failure as shown
in this sample:
C++
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new(nothrow) int[BIG_NUMBER];
if ( pI == nullptr ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
You can test for a failed memory allocation when you've used nothrownew.obj file to
replace global operator new as shown here:
C++
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new int[BIG_NUMBER];
if ( !pI ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
You can provide a handler for failed memory allocation requests. It's possible to write a
custom recovery routine to handle such a failure. It could, for example, release some
reserved memory, then allow the allocation to run again. For more information, see
_set_new_handler.
There are global and class-scoped operator delete functions. Only one operator
delete function can be defined for a given class; if defined, it hides the global operator
delete function. The global operator delete function is always called for arrays of any
type.
The global operator delete function. Two forms exist for the global operator delete
and class-member operator delete functions:
C++
Only one of the preceding two forms can be present for a given class. The first form
takes a single argument of type void * , which contains a pointer to the object to
deallocate. The second form, sized deallocation, takes two arguments: the first is a
pointer to the memory block to deallocate, and the second is the number of bytes to
deallocate. The return type of both forms is void ( operator delete can't return a value).
The intent of the second form is to speed up searching for the correct size category of
the object to delete. This information often isn't stored near the allocation itself, and is
likely uncached. The second form is useful when an operator delete function from a
base class is used to delete an object of a derived class.
The operator delete function is static, so it can't be virtual. The operator delete
function obeys access control, as described in Member-Access Control.
The following example shows user-defined operator new and operator delete functions
designed to log allocations and deallocations of memory:
C++
#include <iostream>
using namespace std;
free( pvMem );
}
The preceding code can be used to detect "memory leakage", that is, memory that's
allocated on the free store but never freed. To detect leaks, the global new and delete
operators are redefined to count allocation and deallocation of memory.
The compiler supports member array new and delete operators in a class declaration.
For example:
C++
// spec1_the_operator_delete_function2.cpp
// compile with: /c
class X {
public:
void * operator new[] (size_t) {
return 0;
}
void operator delete[] (void*) {}
};
void f() {
X *pX = new X[5];
delete [] pX;
}
Smart pointers (Modern C++)
Article • 08/03/2021 • 7 minutes to read
In modern C++ programming, the Standard Library includes smart pointers, which are
used to help ensure that programs are free of memory and resource leaks and are
exception-safe.
In most cases, when you initialize a raw pointer or resource handle to point to an actual
resource, pass the pointer to a smart pointer immediately. In modern C++, raw pointers
are only used in small code blocks of limited scope, loops, or helper functions where
performance is critical and there is no chance of confusion about ownership.
C++
void UseRawPointer()
{
// Using a raw pointer -- not recommended.
Song* pSong = new Song(L"Nothing on You", L"Bruno Mars");
// Use pSong...
void UseSmartPointer()
{
// Declare a smart pointer on stack and pass it the raw pointer.
unique_ptr<Song> song2(new Song(L"Nothing on You", L"Bruno Mars"));
// Use song2...
wstring s = song2->duration_;
//...
As shown in the example, a smart pointer is a class template that you declare on the
stack, and initialize by using a raw pointer that points to a heap-allocated object. After
the smart pointer is initialized, it owns the raw pointer. This means that the smart
pointer is responsible for deleting the memory that the raw pointer specifies. The smart
pointer destructor contains the call to delete, and because the smart pointer is declared
on the stack, its destructor is invoked when the smart pointer goes out of scope, even if
an exception is thrown somewhere further up the stack.
Access the encapsulated pointer by using the familiar pointer operators, -> and * ,
which the smart pointer class overloads to return the encapsulated raw pointer.
The C++ smart pointer idiom resembles object creation in languages such as C#: you
create the object and then let the system take care of deleting it at the correct time. The
difference is that no separate garbage collector runs in the background; memory is
managed through the standard C++ scoping rules so that the runtime environment is
faster and more efficient.
) Important
Always create smart pointers on a separate line of code, never in a parameter list,
so that a subtle resource leak won't occur due to certain parameter list allocation
rules.
The following example shows how a unique_ptr smart pointer type from the C++
Standard Library could be used to encapsulate a pointer to a large object.
C++
class LargeObject
{
public:
void DoSomething(){}
};
The example demonstrates the following essential steps for using smart pointers.
1. Declare the smart pointer as an automatic (local) variable. (Do not use the new or
malloc expression on the smart pointer itself.)
2. In the type parameter, specify the pointed-to type of the encapsulated pointer.
3. Pass a raw pointer to a new -ed object in the smart pointer constructor. (Some
utility functions or smart pointer constructors do this for you.)
Smart pointers are designed to be as efficient as possible both in terms of memory and
performance. For example, the only data member in unique_ptr is the encapsulated
pointer. This means that unique_ptr is exactly the same size as that pointer, either four
bytes or eight bytes. Accessing the encapsulated pointer by using the smart pointer
overloaded * and -> operators is not significantly slower than accessing the raw pointers
directly.
Smart pointers have their own member functions, which are accessed by using "dot"
notation. For example, some C++ Standard Library smart pointers have a reset member
function that releases ownership of the pointer. This is useful when you want to free the
memory owned by the smart pointer before the smart pointer goes out of scope, as
shown in the following example.
C++
void SmartPointerDemo2()
{
// Create the object and pass it to a smart pointer
std::unique_ptr<LargeObject> pLarge(new LargeObject());
Smart pointers usually provide a way to access their raw pointer directly. C++ Standard
Library smart pointers have a get member function for this purpose, and CComPtr has a
public p class member. By providing direct access to the underlying pointer, you can
use the smart pointer to manage memory in your own code and still pass the raw
pointer to code that does not support smart pointers.
C++
void SmartPointerDemo4()
{
// Create the object and pass it to a smart pointer
std::unique_ptr<LargeObject> pLarge(new LargeObject());
unique_ptr
Allows exactly one owner of the underlying pointer. Use as the default choice for
POCO unless you know for certain that you require a shared_ptr . Can be moved to
a new owner, but not copied or shared. Replaces auto_ptr , which is deprecated.
Compare to boost::scoped_ptr . unique_ptr is small and efficient; the size is one
pointer and it supports rvalue references for fast insertion and retrieval from C++
Standard Library collections. Header file: <memory> . For more information, see How
to: Create and Use unique_ptr Instances and unique_ptr Class.
shared_ptr
Reference-counted smart pointer. Use when you want to assign one raw pointer to
multiple owners, for example, when you return a copy of a pointer from a
container but want to keep the original. The raw pointer is not deleted until all
shared_ptr owners have gone out of scope or have otherwise given up ownership.
The size is two pointers; one for the object and one for the shared control block
that contains the reference count. Header file: <memory> . For more information, see
How to: Create and Use shared_ptr Instances and shared_ptr Class.
weak_ptr
CComPtr Class
Use this unless you cannot use ATL. Performs reference counting by using the AddRef
and Release methods. For more information, see How to: Create and Use CComPtr and
CComQIPtr Instances.
CComQIPtr Class
Resembles CComPtr but also provides simplified syntax for calling QueryInterface on
COM objects. For more information, see How to: Create and Use CComPtr and
CComQIPtr Instances.
CComHeapPtr Class
Smart pointer to objects that use CoTaskMemFree to free memory.
CComGITPtr Class
Smart pointer for interfaces that are obtained from the global interface table (GIT).
_com_ptr_t Class
Resembles CComQIPtr in functionality but does not depend on ATL headers.
CAutoPtr Class
Smart pointer that enforces unique ownership by transferring ownership on copy.
Comparable to the deprecated std::auto_ptr Class.
CHeapPtr Class
Smart pointer for objects that are allocated by using the C malloc function.
CAutoVectorPtr Class
Smart pointer for arrays that are allocated by using new[] .
CAutoPtrArray Class
Class that encapsulates an array of CAutoPtr elements.
CAutoPtrList Class
Class that encapsulates methods for manipulating a list of CAutoPtr nodes.
See also
Pointers
C++ Language Reference
C++ Standard Library
How to: Create and use unique_ptr
instances
Article • 11/12/2021 • 2 minutes to read
A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr ,
passed by value to a function, or used in any C++ Standard Library algorithm that
requires copies to be made. A unique_ptr can only be moved. This means that the
ownership of the memory resource is transferred to another unique_ptr and the original
unique_ptr no longer owns it. We recommend that you restrict an object to one owner,
because multiple ownership adds complexity to the program logic. Therefore, when you
need a smart pointer for a plain C++ object, use unique_ptr , and when you construct a
unique_ptr , use the make_unique helper function.
The following diagram illustrates the transfer of ownership between two unique_ptr
instances.
unique_ptr is defined in the <memory> header in the C++ Standard Library. It is exactly
as efficient as a raw pointer and can be used in C++ Standard Library containers. The
addition of unique_ptr instances to C++ Standard Library containers is efficient because
the move constructor of the unique_ptr eliminates the need for a copy operation.
Example 1
The following example shows how to create unique_ptr instances and pass them
between functions.
C++
void MakeSongs()
{
// Create a new unique_ptr with a new object.
auto song = make_unique<Song>(L"Mr. Children", L"Namonaki Uta");
Example 2
The following example shows how to create unique_ptr instances and use them in a
vector.
C++
void SongVector()
{
vector<unique_ptr<Song>> songs;
Example 3
The following example shows how to initialize a unique_ptr that is a class member.
C++
class MyClass
{
private:
// MyClass owns the unique_ptr.
unique_ptr<ClassFactory> factory;
public:
void MakeClass()
{
factory->DoSomething();
}
};
Example 4
You can use make_unique to create a unique_ptr to an array, but you cannot use
make_unique to initialize the array elements.
C++
See also
Smart Pointers (Modern C++)
make_unique
How to: Create and Use shared_ptr
instances
Article • 08/03/2021 • 6 minutes to read
The shared_ptr type is a smart pointer in the C++ standard library that is designed for
scenarios in which more than one owner might have to manage the lifetime of the
object in memory. After you initialize a shared_ptr you can copy it, pass it by value in
function arguments, and assign it to other shared_ptr instances. All the instances point
to the same object, and share access to one "control block" that increments and
decrements the reference count whenever a new shared_ptr is added, goes out of
scope, or is reset. When the reference count reaches zero, the control block deletes the
memory resource and itself.
The following illustration shows several shared_ptr instances that point to one memory
location.
Example setup
The examples that follow all assume that you've included the required headers and
declared the required types, as shown here:
C++
// shared_ptr-examples.cpp
// The following examples assume these declarations:
#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
struct MediaAsset
{
virtual ~MediaAsset() = default; // make it polymorphic
};
struct Song : public MediaAsset
{
std::wstring artist;
std::wstring title;
Song(const std::wstring& artist_, const std::wstring& title_) :
artist{ artist_ }, title{ title_ } {}
};
int main()
{
// The examples go here, in order:
// Example 1
// Example 2
// Example 3
// Example 4
// Example 6
}
Example 1
Whenever possible, use the make_shared function to create a shared_ptr when the
memory resource is created for the first time. make_shared is exception-safe. It uses the
same call to allocate the memory for the control block and the resource, which reduces
the construction overhead. If you don't use make_shared , then you have to use an
explicit new expression to create the object before you pass it to the shared_ptr
constructor. The following example shows various ways to declare and initialize a
shared_ptr together with a new object.
C++
Example 2
The following example shows how to declare and initialize shared_ptr instances that
take on shared ownership of an object that has already been allocated by another
shared_ptr . Assume that sp2 is an initialized shared_ptr .
C++
Example 3
shared_ptr is also helpful in C++ Standard Library containers when you're using
algorithms that copy elements. You can wrap elements in a shared_ptr , and then copy it
into other containers with the understanding that the underlying memory is valid as
long as you need it, and no longer. The following example shows how to use the
remove_copy_if algorithm on shared_ptr instances in a vector.
C++
vector<shared_ptr<Song>> v {
make_shared<Song>(L"Bob Dylan", L"The Times They Are A Changing"),
make_shared<Song>(L"Aretha Franklin", L"Bridge Over Troubled Water"),
make_shared<Song>(L"Thalía", L"Entre El Mar y Una Estrella")
};
vector<shared_ptr<Song>> v2;
remove_copy_if(v.begin(), v.end(), back_inserter(v2), [] (shared_ptr<Song>
s)
{
return s->artist.compare(L"Bob Dylan") == 0;
});
Example 4
You can use dynamic_pointer_cast , static_pointer_cast , and const_pointer_cast to
cast a shared_ptr . These functions resemble the dynamic_cast , static_cast , and
const_cast operators. The following example shows how to test the derived type of
each element in a vector of shared_ptr of base classes, and then copy the elements and
display information about them.
C++
vector<shared_ptr<MediaAsset>> assets {
make_shared<Song>(L"Himesh Reshammiya", L"Tera Surroor"),
make_shared<Song>(L"Penaz Masani", L"Tu Dil De De"),
make_shared<Photo>(L"2011-04-06", L"Redmond, WA", L"Soccer field at
Microsoft.")
};
vector<shared_ptr<MediaAsset>> photos;
Example 5
You can pass a shared_ptr to another function in the following ways:
Pass the shared_ptr by value. This invokes the copy constructor, increments the
reference count, and makes the callee an owner. There's a small amount of
overhead in this operation, which may be significant depending on how many
shared_ptr objects you're passing. Use this option when the implied or explicit
code contract between the caller and callee requires that the callee be an owner.
Pass the shared_ptr by reference or const reference. In this case, the reference
count isn't incremented, and the callee can access the pointer as long as the caller
doesn't go out of scope. Or, the callee can decide to create a shared_ptr based on
the reference, and become a shared owner. Use this option when the caller has no
knowledge of the callee, or when you must pass a shared_ptr and want to avoid
the copy operation for performance reasons.
Pass the underlying pointer or a reference to the underlying object. This enables
the callee to use the object, but doesn't enable it to share ownership or extend the
lifetime. If the callee creates a shared_ptr from the raw pointer, the new
shared_ptr is independent from the original, and doesn't control the underlying
resource. Use this option when the contract between the caller and callee clearly
specifies that the caller retains ownership of the shared_ptr lifetime.
When you're deciding how to pass a shared_ptr , determine whether the callee has
to share ownership of the underlying resource. An "owner" is an object or function
that can keep the underlying resource alive for as long as it needs it. If the caller
has to guarantee that the callee can extend the life of the pointer beyond its (the
function's) lifetime, use the first option. If you don't care whether the callee
extends the lifetime, then pass by reference and let the callee copy it or not.
If you have to give a helper function access to the underlying pointer, and you
know that the helper function will just use the pointer and return before the calling
function returns, then that function doesn't have to share ownership of the
underlying pointer. It just has to access the pointer within the lifetime of the
caller's shared_ptr . In this case, it's safe to pass the shared_ptr by reference, or
pass the raw pointer or a reference to the underlying object. Passing this way
provides a small performance benefit, and may also help you express your
programming intent.
Example 6
The following example shows how shared_ptr overloads various comparison operators
to enable pointer comparisons on the memory that is owned by the shared_ptr
instances.
C++
See also
Smart Pointers (Modern C++)
How to: Create and use weak_ptr
instances
Article • 08/03/2021 • 3 minutes to read
Sometimes an object must store a way to access the underlying object of a shared_ptr
without causing the reference count to be incremented. Typically, this situation occurs
when you have cyclic references between shared_ptr instances.
The best design is to avoid shared ownership of pointers whenever you can. However, if
you must have shared ownership of shared_ptr instances, avoid cyclic references
between them. When cyclic references are unavoidable, or even preferable for some
reason, use weak_ptr to give one or more of the owners a weak reference to another
shared_ptr . By using a weak_ptr , you can create a shared_ptr that joins to an existing
set of related instances, but only if the underlying memory resource is still valid. A
weak_ptr itself does not participate in the reference counting, and therefore, it cannot
prevent the reference count from going to zero. However, you can use a weak_ptr to try
to obtain a new copy of the shared_ptr with which it was initialized. If the memory has
already been deleted, the weak_ptr 's bool operator returns false . If the memory is still
valid, the new shared pointer increments the reference count and guarantees that the
memory will be valid as long as the shared_ptr variable stays in scope.
Example
The following code example shows a case where weak_ptr is used to ensure proper
deletion of objects that have circular dependencies. As you examine the example,
assume that it was created only after alternative solutions were considered. The
Controller objects represent some aspect of a machine process, and they operate
independently. Each controller must be able to query the status of the other controllers
at any time, and each one contains a private vector<weak_ptr<Controller>> for this
purpose. Each vector contains a circular reference, and therefore, weak_ptr instances are
used instead of shared_ptr .
C++
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Controller
{
public:
int Num;
wstring Status;
vector<weak_ptr<Controller>> others;
explicit Controller(int i) : Num(i), Status(L"On")
{
wcout << L"Creating Controller" << Num << endl;
}
~Controller()
{
wcout << L"Destroying Controller" << Num << endl;
}
void RunTest()
{
vector<shared_ptr<Controller>> v{
make_shared<Controller>(0),
make_shared<Controller>(1),
make_shared<Controller>(2),
make_shared<Controller>(3),
make_shared<Controller>(4),
};
int main()
{
RunTest();
wcout << L"Press any key" << endl;
char ch;
cin.getline(&ch, 1);
}
Output
Creating Controller0
Creating Controller1
Creating Controller2
Creating Controller3
Creating Controller4
push_back to v[0]: 1
push_back to v[0]: 2
push_back to v[0]: 3
push_back to v[0]: 4
push_back to v[1]: 0
push_back to v[1]: 2
push_back to v[1]: 3
push_back to v[1]: 4
push_back to v[2]: 0
push_back to v[2]: 1
push_back to v[2]: 3
push_back to v[2]: 4
push_back to v[3]: 0
push_back to v[3]: 1
push_back to v[3]: 2
push_back to v[3]: 4
push_back to v[4]: 0
push_back to v[4]: 1
push_back to v[4]: 2
push_back to v[4]: 3
use_count = 1
Status of 1 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 3 = On
Destroying Controller0
Destroying Controller1
Destroying Controller2
Destroying Controller3
Destroying Controller4
Press any key
See also
Smart Pointers (Modern C++)
How to: Create and use CComPtr and
CComQIPtr instances
Article • 08/03/2021 • 3 minutes to read
In classic Windows programming, libraries are often implemented as COM objects (or
more precisely, as COM servers). Many Windows operating system components are
implemented as COM servers, and many contributors provide libraries in this form. For
information about the basics of COM, see Component Object Model (COM).
When you instantiate a Component Object Model (COM) object, store the interface
pointer in a COM smart pointer, which performs the reference counting by using calls to
AddRef and Release in the destructor. If you are using the Active Template Library (ATL)
or the Microsoft Foundation Class Library (MFC), then use the CComPtr smart pointer. If
you are not using ATL or MFC, then use _com_ptr_t . Because there is no COM equivalent
to std::unique_ptr , use these smart pointers for both single-owner and multiple-owner
scenarios. Both CComPtr and ComQIPtr support move operations that have rvalue
references.
Example: CComPtr
The following example shows how to use CComPtr to instantiate a COM object and
obtain pointers to its interfaces. Notice that the CComPtr::CoCreateInstance member
function is used to create the COM object, instead of the Win32 function that has the
same name.
C++
void CComPtrDemo()
{
HRESULT hr = CoInitialize(NULL);
CoUninitialize();
CComPtr and its relatives are part of the ATL and are defined in <atlcomcli.h>.
_com_ptr_t is declared in <comip.h>. The compiler creates specializations of _com_ptr_t
Example: CComQIPt
ATL also provides CComQIPtr , which has a simpler syntax for querying a COM object to
retrieve an additional interface. However, we recommend CComPtr because it does
everything that CComQIPtr can do and is semantically more consistent with raw COM
interface pointers. If you use a CComPtr to query for an interface, the new interface
pointer is placed in an out parameter. If the call fails, an HRESULT is returned, which is
the typical COM pattern. With CComQIPtr , the return value is the pointer itself, and if the
call fails, the internal HRESULT return value cannot be accessed. The following two lines
show how the error handling mechanisms in CComPtr and CComQIPtr differ.
C++
Example: IDispatch
CComPtr provides a specialization for IDispatch that enables it to store pointers to COM
automation components and invoke the methods on the interface by using late binding.
CComDispatchDriver is a typedef for CComQIPtr<IDispatch, &IIDIDispatch> , which is
implicitly convertible to CComPtr<IDispatch> . Therefore, when any of these three names
appears in code, it is equivalent to CComPtr<IDispatch> . The following example shows
how to obtain a pointer to the Microsoft Word object model by using a
CComPtr<IDispatch> .
C++
void COMAutomationSmartPointerDemo()
{
CComPtr<IDispatch> pWord;
CComQIPtr<IDispatch, &IID_IDispatch> pqi = pWord;
CComDispatchDriver pDriver = pqi;
HRESULT hr;
_variant_t pOutVal;
CoInitialize(NULL);
hr = pWord.CoCreateInstance(L"Word.Application", NULL,
CLSCTX_LOCAL_SERVER);
if(FAILED(hr)){ /*... handle hr error*/ }
CoUninitialize();
}
See also
Smart Pointers (Modern C++)
Exception handling in MSVC
Article • 08/03/2021 • 2 minutes to read
An exception is an error condition, possibly outside the program's control, that prevents
the program from continuing along its regular execution path. Certain operations,
including object creation, file input/output, and function calls made from other modules,
are all potential sources of exceptions, even when your program is running correctly.
Robust code anticipates and handles exceptions. To detect logic errors, use assertions
rather than exceptions (see Using Assertions).
Kinds of exceptions
The Microsoft C++ compiler (MSVC) supports three kinds of exception handling:
For most C++ programs, you should use C++ exception handling. It's type-safe,
and ensures that object destructors are invoked during stack unwinding.
MFC exceptions
Since version 3.0, MFC has used C++ exceptions. It still supports its older exception
handling macros, which are similar to C++ exceptions in form. For advice about
mixing MFC macros and C++ exceptions, see Exceptions: Using MFC Macros and
C++ Exceptions.
Use an /EH compiler option to specify the exception handling model to use in a C++
project. Standard C++ exception handling (/EHsc) is the default in new C++ projects in
Visual Studio.
We don't recommend you mix the exception handling mechanisms. For example, don't
use C++ exceptions with structured exception handling. Using C++ exception handling
exclusively makes your code more portable, and it allows you to handle exceptions of
any type. For more information about the drawbacks of structured exception handling,
see Structured Exception Handling.
In this section
Modern C++ best practices for exceptions and error handling
Exception Specifications
noexcept
See also
C++ Language Reference
x64 exception handling
Exception Handling (C++/CLI and C++/CX)
Modern C++ best practices for
exceptions and error handling
Article • 10/17/2022 • 6 minutes to read
In modern C++, in most scenarios, the preferred way to report and handle both logic
errors and runtime errors is to use exceptions. It's especially true when the stack might
contain several function calls between the function that detects the error, and the
function that has the context to handle the error. Exceptions provide a formal, well-
defined way for code that detects errors to pass the information up the call stack.
An exception forces calling code to recognize an error condition and handle it.
Unhandled exceptions stop program execution.
An exception jumps to the point in the call stack that can handle the error.
Intermediate functions can let the exception propagate. They don't have to
coordinate with other layers.
An exception enables a clean separation between the code that detects the error
and the code that handles the error.
The following simplified example shows the necessary syntax for throwing and catching
exceptions in C++.
C++
#include <stdexcept>
#include <limits>
#include <iostream>
void MyFunc(int c)
{
if (c > numeric_limits< char> ::max())
throw invalid_argument("MyFunc argument too large.");
//...
}
int main()
{
try
{
MyFunc(256); //cause an exception to throw
}
catch (invalid_argument& e)
{
cerr << e.what() << endl;
return -1;
}
//...
return 0;
}
Exceptions in C++ resemble ones in languages such as C# and Java. In the try block, if
an exception is thrown it will be caught by the first associated catch block whose type
matches that of the exception. In other words, execution jumps from the throw
statement to the catch statement. If no usable catch block is found, std::terminate is
invoked and the program exits. In C++, any type may be thrown; however, we
recommend that you throw a type that derives directly or indirectly from
std::exception . In the previous example, the exception type, invalid_argument, is
defined in the standard library in the <stdexcept> header file. C++ doesn't provide or
require a finally block to make sure all resources are released if an exception is
thrown. The resource acquisition is initialization (RAII) idiom, which uses smart pointers,
provides the required functionality for resource cleanup. For more information, see How
to: Design for exception safety. For information about the C++ stack-unwinding
mechanism, see Exceptions and stack unwinding.
Basic guidelines
Robust error handling is challenging in any programming language. Although
exceptions provide several features that support good error handling, they can't do all
the work for you. To realize the benefits of the exception mechanism, keep exceptions in
mind as you design your code.
Use asserts to check for errors that should never occur. Use exceptions to check for
errors that might occur, for example, errors in input validation on parameters of
public functions. For more information, see the Exceptions versus assertions
section.
Use exceptions when the code that handles the error is separated from the code
that detects the error by one or more intervening function calls. Consider whether
to use error codes instead in performance-critical loops, when code that handles
the error is tightly coupled to the code that detects it.
For every function that might throw or propagate an exception, provide one of the
three exception guarantees: the strong guarantee, the basic guarantee, or the
nothrow (noexcept) guarantee. For more information, see How to: Design for
exception safety.
Throw exceptions by value, catch them by reference. Don't catch what you can't
handle.
Don't use exception specifications, which are deprecated in C++11. For more
information, see the Exception specifications and noexcept section.
Use standard library exception types when they apply. Derive custom exception
types from the exception Class hierarchy.
For more information about SEH, see Structured Exception Handling (C/C++).
See also
How to: Interface between exceptional and non-exceptional code
C++ language reference
C++ Standard Library
How to: Design for exception safety
Article • 08/03/2021 • 6 minutes to read
One of the advantages of the exception mechanism is that execution, together with data
about the exception, jumps directly from the statement that throws the exception to the
first catch statement that handles it. The handler may be any number of levels up in the
call stack. Functions that are called between the try statement and the throw statement
are not required to know anything about the exception that is thrown. However, they
have to be designed so that they can go out of scope "unexpectedly" at any point where
an exception might propagate up from below, and do so without leaving behind
partially created objects, leaked memory, or data structures that are in unusable states.
Basic techniques
A robust exception-handling policy requires careful thought and should be part of the
design process. In general, most exceptions are detected and thrown at the lower layers
of a software module, but typically these layers do not have enough context to handle
the error or expose a message to end users. In the middle layers, functions can catch
and rethrow an exception when they have to inspect the exception object, or they have
additional useful information to provide for the upper layer that ultimately catches the
exception. A function should catch and "swallow" an exception only if it is able to
completely recover from it. In many cases, the correct behavior in the middle layers is to
let an exception propagate up the call stack. Even at the highest layer, it might be
appropriate to let an unhandled exception terminate a program if the exception leaves
the program in a state in which its correctness cannot be guaranteed.
C++
// old-style new/delete version
class NDResourceClass {
private:
int* m_p;
float* m_q;
public:
NDResourceClass() : m_p(0), m_q(0) {
m_p = new int;
m_q = new float;
}
~NDResourceClass() {
delete m_p;
delete m_q;
}
// Potential leak! When a constructor emits an exception,
// the destructor will not be invoked.
};
// shared_ptr version
#include <memory>
class SPResourceClass {
private:
shared_ptr<int> m_p;
shared_ptr<float> m_q;
public:
SPResourceClass() : m_p(new int), m_q(new float) { }
// Implicitly defined dtor is OK for these members,
// shared_ptr will clean up and avoid leaks regardless.
};
class Shape {
// ...
};
class SPShapeResourceClass {
private:
shared_ptr<Shape> m_p;
shared_ptr<Shape> m_q;
public:
SPShapeResourceClass() : m_p(new Circle), m_q(new Triangle) { }
};
No-fail guarantee
The no-fail (or, "no-throw") guarantee is the strongest guarantee that a function can
provide. It states that the function will not throw an exception or allow one to
propagate. However, you cannot reliably provide such a guarantee unless (a) you know
that all the functions that this function calls are also no-fail, or (b) you know that any
exceptions that are thrown are caught before they reach this function, or (c) you know
how to catch and correctly handle all exceptions that might reach this function.
Both the strong guarantee and the basic guarantee rely on the assumption that the
destructors are no-fail. All containers and types in the Standard Library guarantee that
their destructors do not throw. There is also a converse requirement: The Standard
Library requires that user-defined types that are given to it—for example, as template
arguments—must have non-throwing destructors.
Strong guarantee
The strong guarantee states that if a function goes out of scope because of an
exception, it will not leak memory and program state will not be modified. A function
that provides a strong guarantee is essentially a transaction that has commit or rollback
semantics: either it completely succeeds or it has no effect.
Basic guarantee
The basic guarantee is the weakest of the three. However, it might be the best choice
when a strong guarantee is too expensive in memory consumption or in performance.
The basic guarantee states that if an exception occurs, no memory is leaked and the
object is still in a usable state even though the data might have been modified.
Exception-safe classes
A class can help ensure its own exception safety, even when it is consumed by unsafe
functions, by preventing itself from being partially constructed or partially destroyed. If a
class constructor exits before completion, then the object is never created and its
destructor will never be called. Although automatic variables that are initialized prior to
the exception will have their destructors invoked, dynamically allocated memory or
resources that are not managed by a smart pointer or similar automatic variable will be
leaked.
The built-in types are all no-fail, and the Standard Library types support the basic
guarantee at a minimum. Follow these guidelines for any user-defined type that must be
exception-safe:
Use smart pointers or other RAII-type wrappers to manage all resources. Avoid
resource management functionality in your class destructor, because the
destructor will not be invoked if the constructor throws an exception. However, if
the class is a dedicated resource manager that controls just one resource, then it's
acceptable to use the destructor to manage resources.
Consider whether to store all class state in a data member that is wrapped in a
smart pointer, especially if a class has a concept of "initialization that is permitted
to fail." Although C++ allows for uninitialized data members, it does not support
uninitialized or partially initialized class instances. A constructor must either
succeed or fail; no object is created if the constructor does not run to completion.
Do not allow any exceptions to escape from a destructor. A basic axiom of C++ is
that destructors should never allow an exception to propagate up the call stack. If
a destructor must perform a potentially exception-throwing operation, it must do
so in a try catch block and swallow the exception. The standard library provides
this guarantee on all destructors it defines.
See also
Modern C++ best practices for exceptions and error handling
How to: Interface Between Exceptional and Non-Exceptional Code
How to: Interface between exceptional
and non-exceptional code
Article • 03/02/2022 • 7 minutes to read
This article describes how to implement consistent exception-handling in C++ code, and
how to translate exceptions to and from error codes at exception boundaries.
Sometimes C++ code has to interface with code that doesn't use exceptions (non-
exceptional code). Such an interface is known as an exception boundary. For example,
you may want to call the Win32 function CreateFile in your C++ program. CreateFile
doesn't throw exceptions. Instead, it sets error codes that can be retrieved by the
GetLastError function. If your C++ program is non-trivial, then you probably prefer to
have a consistent exception-based error-handling policy. And, you probably don't want
to abandon exceptions just because you interface with non-exceptional code. You also
don't want to mix exception-based and non-exception-based error policies in your C++
code.
Example
The following example shows C++ functions that use the Win32 CreateFile and
ReadFile functions internally to open and read two files. The File class is a resource
acquisition is initialization (RAII) wrapper for the file handles. Its constructor detects a
"file not found" condition and throws an exception to propagate the error up the call
stack of the C++ executable (in this example, the main() function). If an exception is
thrown after a File object is fully constructed, the destructor automatically calls
CloseHandle to release the file handle. (If you prefer, you can use the Active Template
Library (ATL) CHandle class for this same purpose, or a unique_ptr together with a
custom deletion function.) The functions that call Win32 and CRT APIs detect errors and
then throw C++ exceptions using the locally defined ThrowLastErrorIf function, which
in turn uses the Win32Exception class, derived from the runtime_error class. All
functions in this example provide a strong exception guarantee: If an exception is
thrown at any point in these functions, no resources are leaked and no program state is
modified.
C++
class File
{
private:
HANDLE m_handle;
~File() { CloseHandle(m_handle); }
vector<char> readbuffer(filesize);
cout << filename << " file size: " << filesize << ", bytesRead: "
<< bytesRead << endl;
return readbuffer;
}
try
{
if(argc > 2) {
filename1 = argv[1];
filename2 = argv[2];
}
cout << "Using file names " << filename1 << " and " << filename2 <<
endl;
if (IsFileDiff(filename1, filename2)) {
cout << "+++ Files are different." << endl;
} else {
cout<< "=== Files match." << endl;
}
}
catch(const Win32Exception& e)
{
ios state(nullptr);
state.copyfmt(cout);
cout << e.what() << endl;
cout << "Error code: 0x" << hex << uppercase << setw(8) <<
setfill('0')
<< e.GetErrorCode() << endl;
cout.copyfmt(state); // restore previous formatting
}
}
We recommend your extern "C" C++ function specifically catch every exception that it
knows how to handle and, if appropriate, convert the exception to an error code that
the caller understands. If not all potential exceptions are known, the C++ function
should have a catch(...) block as the last handler. In such a case, it's best to report a
fatal error to the caller, because your program might be in an unknown and
unrecoverable state.
The following example shows a function that assumes that any exception that might be
thrown is either a Win32Exception or an exception type derived from std::exception .
The function catches any exception of these types and propagates the error information
as a Win32 error code to the caller.
C++
catch(std::exception& e)
{
SetLastError(MY_APPLICATION_GENERAL_ERROR);
}
return FALSE;
}
When you convert from exceptions to error codes, there's a potential issue: Error codes
often don't contain the richness of information that an exception can store. To address
this issue, you can provide a catch block for each specific exception type that might be
thrown, and perform logging to record the details of the exception before it's converted
to an error code. This approach can create repetitive code if multiple functions all use
the same set of catch blocks. A good way to avoid code repetition is by refactoring
those blocks into one private utility function that implements the try and catch blocks
and accepts a function object that is invoked in the try block. In each public function,
pass the code to the utility function as a lambda expression.
C++
template<typename Func>
bool Win32ExceptionBoundary(Func&& f)
{
try
{
return f();
}
catch(Win32Exception& e)
{
SetLastError(e.GetErrorCode());
}
catch(const std::exception& e)
{
SetLastError(MY_APPLICATION_GENERAL_ERROR);
}
return false;
}
The following example shows how to write the lambda expression that defines the
functor. A lambda expression is often easier to read inline than code that calls a named
function object.
C++
You can build the entire code path across the non-exception-aware code using
/EHs ,
There aren't any locally allocated resources that can leak when the stack is
unwound,
The code doesn't have any __except structured exception handlers that catch all
exceptions.
Because throwing exceptions across non-exceptional code is error-prone and may cause
difficult debugging challenges, we don't recommend it.
See also
Modern C++ best practices for exceptions and error handling
How to: Design for exception safety
try, throw, and catch Statements (C++)
Article • 02/14/2023 • 2 minutes to read
To implement exception handling in C++, you use try , throw , and catch expressions.
First, use a try block to enclose one or more statements that might throw an exception.
To handle exceptions that may be thrown, implement one or more catch blocks
immediately following a try block. Each catch block specifies the type of exception it
can handle.
This example shows a try block and its handlers. Assume that GetNetworkResource()
acquires data over a network connection and that the two exception types are user-
defined classes that derive from std::exception . Notice that the exceptions are caught
by const reference in the catch statement. We recommend that you throw exceptions
by value and catch them by const reference.
Example
C++
MyData md;
try {
// Code that could throw an exception
md = GetNetworkResource();
}
catch (const networkIOException& e) {
// Code that executes when an exception of type
// networkIOException is thrown in the try block
// ...
// Log error message in the exception object
cerr << e.what();
}
catch (const myDataFormatException& e) {
// Code that handles another exception type
// ...
cerr << e.what();
}
Remarks
The code after the try clause is the guarded section of code. The throw expression
throws—that is, raises—an exception. The code block after the catch clause is the
exception handler. This is the handler that catches the exception that's thrown if the
types in the throw and catch expressions are compatible. For a list of rules that govern
type-matching in catch blocks, see How Catch Blocks are Evaluated. If the catch
statement specifies an ellipsis (...) instead of a type, the catch block handles every type
of exception. When you compile with the /EHa option, these can include C structured
exceptions and system-generated or application-generated asynchronous exceptions
such as memory protection, divide-by-zero, and floating-point violations. Because catch
blocks are processed in program order to find a matching type, an ellipsis handler must
be the last handler for the associated try block. Use catch(...) with caution; don't
allow a program to continue unless the catch block knows how to handle the specific
exception that is caught. Typically, a catch(...) block is used to log errors and perform
special cleanup before program execution is stopped.
A throw expression that has no operand rethrows the exception currently being
handled. We recommend this form when rethrowing the exception, because this
preserves the original exception's polymorphic type information. Such an expression
should only be used in a catch handler or in a function that's called from a catch
handler. The rethrown exception object is the original exception object, not a copy.
C++
try {
throw CSomeOtherException();
}
catch(...) {
// Catch all exceptions - dangerous!!!
// Respond (perhaps only partially) to the exception, then
// re-throw to pass the exception to some other handler
// ...
throw;
}
See also
Modern C++ best practices for exceptions and error handling
Keywords
Unhandled C++ Exceptions
__uncaught_exception
How Catch Blocks are Evaluated (C++)
Article • 08/03/2021 • 2 minutes to read
If the type of thrown exception is a class, which also has a base class (or classes), it can
be caught by handlers that accept base classes of the exception's type, as well as
references to bases of the exception's type. Note that when an exception is caught by a
reference, it is bound to the actual thrown exception object; otherwise, it is a copy
(much the same as an argument to a function).
A handler that can accept any type (using the ellipsis syntax).
A handler that accepts the same type as the exception object; because it is a copy,
const and volatile modifiers are ignored.
A handler that accepts a reference to the same type as the exception object.
A handler that accepts a reference to a const or volatile form of the same type
as the exception object.
A handler that accepts a base class of the same type as the exception object; since
it is a copy, const and volatile modifiers are ignored. The catch handler for a
base class must not precede the catch handler for the derived class.
A handler that accepts a reference to a base class of the same type as the
exception object.
The order in which catch handlers appear is significant, because handlers for a given
try block are examined in order of their appearance. For example, it is an error to place
the handler for a base class before the handler for a derived class. After a matching
catch handler is found, subsequent handlers are not examined. As a result, an ellipsis
catch handler must be the last handler for its try block. For example:
C++
// ...
try
{
// ...
}
catch( ... )
{
// Handle exception here.
}
// Error: the next two handlers are never examined.
catch( const char * str )
{
cout << "Caught exception: " << str << endl;
}
catch( CExcptClass E )
{
// Handle CExcptClass exception here.
}
In this example, the ellipsis catch handler is the only handler that is examined.
See also
Modern C++ best practices for exceptions and error handling
Exceptions and Stack Unwinding in C++
Article • 11/14/2022 • 4 minutes to read
In the C++ exception mechanism, control moves from the throw statement to the first
catch statement that can handle the thrown type. When the catch statement is reached,
all of the automatic variables that are in scope between the throw and catch statements
are destroyed in a process that is known as stack unwinding. In stack unwinding,
execution proceeds as follows:
1. Control reaches the try statement by normal sequential execution. The guarded
section in the try block is executed.
5. If a matching catch handler is found, and it catches by value, its formal parameter
is initialized by copying the exception object. If it catches by reference, the
parameter is initialized to refer to the exception object. After the formal parameter
is initialized, the process of unwinding the stack begins. This involves the
destruction of all automatic objects that were fully constructed—but not yet
destructed—between the beginning of the try block that is associated with the
catch handler and the throw site of the exception. Destruction occurs in reverse
order of construction. The catch handler is executed and the program resumes
execution after the last handler—that is, at the first statement or construct that is
not a catch handler. Control can only enter a catch handler through a thrown
exception, never through a goto statement or a case label in a switch statement.
C++
#include <string>
#include <iostream>
using namespace std;
class MyException{};
class Dummy
{
public:
Dummy(string s) : MyName(s) { PrintMsg("Created Dummy:"); }
Dummy(const Dummy& other) : MyName(other.MyName){ PrintMsg("Copy created
Dummy:"); }
~Dummy(){ PrintMsg("Destroyed Dummy:"); }
void PrintMsg(string s) { cout << s << MyName << endl; }
string MyName;
int level;
};
int main()
{
cout << "Entering main" << endl;
try
{
Dummy d(" M");
A(d,1);
}
catch (MyException& e)
{
cout << "Caught an exception of type: " << typeid(e).name() << endl;
}
/* Output:
Entering main
Created Dummy: M
Copy created Dummy: M
Entering FunctionA
Copy created Dummy: A
Entering FunctionB
Copy created Dummy: B
Entering FunctionC
Destroyed Dummy: C
Destroyed Dummy: B
Destroyed Dummy: A
Destroyed Dummy: M
Caught an exception of type: class MyException
Exiting main.
*/
Exception specifications (throw,
noexcept) (C++)
Article • 08/17/2021 • 3 minutes to read
Exception specifications are a C++ language feature that indicate the programmer's
intent about the exception types that can be propagated by a function. You can specify
that a function may or may not exit by an exception by using an exception specification.
The compiler can use this information to optimize calls to the function, and to terminate
the program if an unexpected exception escapes the function.
Prior to C++17 there were two kinds of exception specification. The noexcept
specification was new in C++11. It specifies whether the set of potential exceptions that
can escape the function is empty. The dynamic exception specification, or
throw(optional_type_list) specification, was deprecated in C++11 and removed in
C++17, except for throw() , which is an alias for noexcept(true) . This exception
specification was designed to provide summary information about what exceptions can
be thrown out of a function, but in practice it was found to be problematic. The one
dynamic exception specification that did prove to be somewhat useful was the
unconditional throw() specification. For example, the function declaration:
C++
tells the compiler that the function does not throw any exceptions. However, in
/std:c++14 mode this could lead to undefined behavior if the function does throw an
exception. Therefore we recommend using the noexcept operator instead of the one
above:
C++
Exception Meaning
specification
Exception Meaning
specification
noexcept The function does not throw an exception. In /std:c++14 mode (which is the
noexcept(true) default), noexcept and noexcept(true) are equivalent. When an exception is
throw() thrown from a function that is declared noexcept or noexcept(true) ,
std::terminate is invoked. When an exception is thrown from a function
declared as throw() in /std:c++14 mode, the result is undefined behavior. No
specific function is invoked. This is a divergence from the C++14 standard,
which required the compiler to invoke std::unexpected.
Visual Studio 2017 version 15.5 and later: In /std:c++17 mode , noexcept ,
noexcept(true) , and throw() are all equivalent. In /std:c++17 mode, throw()
is an alias for noexcept(true) . In /std:c++17 mode and later, when an
exception is thrown from a function declared with any of these specifications,
std::terminate is invoked as required by the C++17 standard.
throw(type) (C++14 and earlier) The function can throw an exception of type type . The
compiler accepts the syntax, but interprets it as noexcept(false) . In
/std:c++17 mode and later, the compiler issues warning C5040.
If exception handling is used in an application, there must be a function in the call stack
that handles thrown exceptions before they exit the outer scope of a function marked
noexcept , noexcept(true) , or throw() . If any functions called between the one that
throws an exception and the one that handles the exception are specified as noexcept ,
noexcept(true) (or throw() in /std:c++17 mode), the program is terminated when the
The following table summarizes whether a C++ function may potentially throw under
various compiler exception handling options:
Function /EHsc /EHs /EHa /EHac
C++ function with noexcept(false) , throw(...) , or throw(type) Yes Yes Yes Yes
exception specification
Example
C++
// exception_specification.cpp
// compile with: /EHs
#include <stdio.h>
void handler() {
printf_s("in handler\n");
}
int main() {
f2();
try {
f4();
}
catch(...) {
printf_s("Caught exception from f4\n");
}
f5();
}
Output
About to throw 1
in handler
About to throw 1
Caught exception from f4
About to throw 1
in handler
See also
try, throw, and catch Statements (C++)
Modern C++ best practices for exceptions and error handling
noexcept (C++)
Article • 09/28/2022 • 2 minutes to read
Syntax
noexcept-specifier :
noexcept
noexcept-expression
throw ( )
noexcept-expression :
noexcept ( constant-expression )
Parameters
constant-expression
A constant expression of type bool that represents whether the set of potential
exception types is empty. The unconditional version is equivalent to noexcept(true) .
Remarks
A noexcept-expression is a kind of exception specification: a suffix to a function
declaration that represents a set of types that might be matched by an exception
handler for any exception that exits a function. Unary conditional operator
noexcept(constant_expression) when constant_expression yields true , and its
unconditional synonym noexcept , specify that the set of potential exception types that
can exit a function is empty. That is, the function never throws an exception and never
allows an exception to be propagated outside its scope. The operator
noexcept(constant_expression) when constant_expression yields false , or the absence
Mark a function as noexcept only if all the functions that it calls, either directly or
indirectly, are also noexcept or const . The compiler doesn't necessarily check every
code path for exceptions that might bubble up to a noexcept function. If an exception
does exit the outer scope of a function marked noexcept , std::terminate is invoked
immediately, and there's no guarantee that destructors of any in-scope objects will be
invoked. Use noexcept instead of the dynamic exception specifier throw() . The dynamic
exception specification, or throw(optional_type_list) specification, was deprecated in
C++11 and removed in C++17, except for throw() , which is an alias for noexcept(true) .
We recommended you apply noexcept to any function that never allows an exception to
propagate up the call stack. When a function is declared noexcept , it enables the
compiler to generate more efficient code in several different contexts. For more
information, see Exception specifications.
Example
A function template that copies its argument might be declared noexcept on the
condition that the object being copied is a plain old data type (POD). Such a function
could be declared like this:
C++
#include <type_traits>
See also
Modern C++ best practices for exceptions and error handling
Exception specifications (throw, noexcept)
Unhandled C++ exceptions
Article • 08/03/2021 • 2 minutes to read
If a matching handler (or ellipsis catch handler) cannot be found for the current
exception, the predefined terminate run-time function is called. (You can also explicitly
call terminate in any of your handlers.) The default action of terminate is to call abort .
If you want terminate to call some other function in your program before exiting the
application, call the set_terminate function with the name of the function to be called
as its single argument. You can call set_terminate at any point in your program. The
terminate routine always calls the last function given as an argument to set_terminate .
Example
The following example throws a char * exception, but does not contain a handler
designated to catch exceptions of type char * . The call to set_terminate instructs
terminate to call term_func .
C++
// exceptions_Unhandled_Exceptions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void term_func() {
cout << "term_func was called by terminate." << endl;
exit( -1 );
}
int main() {
try
{
set_terminate( term_func );
throw "Out of memory!"; // No catch handler for this exception
}
catch( int )
{
cout << "Integer exception raised." << endl;
}
return 0;
}
Output
Output
term_func was called by terminate.
The term_func function should terminate the program or current thread, ideally by
calling exit . If it doesn't, and instead returns to its caller, abort is called.
See also
Modern C++ best practices for exceptions and error handling
Mixing C (structured) and C++
exceptions
Article • 08/03/2021 • 2 minutes to read
If you want to write portable code, the use of structured exception handling (SEH) in a
C++ program isn't recommended. However, you may sometimes want to compile using
/EHa and mix structured exceptions and C++ source code, and need some facility for
handling both kinds of exceptions. Because a structured exception handler has no
concept of objects or typed exceptions, it can't handle exceptions thrown by C++ code.
However, C++ catch handlers can handle structured exceptions. C++ exception
handling syntax ( try , throw , catch ) isn't accepted by the C compiler, but structured
exception handling syntax ( __try , __except , __finally ) is supported by the C++
compiler.
If you mix structured and C++ exceptions, be aware of these potential issues:
C++ exceptions and structured exceptions can't be mixed within the same
function.
C++ exception handling can catch and preserve the unwind semantics in all
modules compiled with the /EH compiler options, which enable unwind semantics.
There may be some situations in which destructor functions aren't called for all
objects. For example, a structured exception could occur while attempting to make
a function call through an uninitialized function pointer. If the function parameters
are objects constructed before the call, the destructors of those objects don't get
called during stack unwind.
Next steps
Using setjmp or longjmp in C++ programs
See more information on the use of setjmp and longjmp in C++ programs.
See also
Modern C++ best practices for exceptions and error handling
Using setjmp and longjmp
Article • 08/03/2021 • 2 minutes to read
When setjmp and longjmp are used together, they provide a way to execute a non-local
goto . They are typically used in C code to pass execution control to error-handling or
recovery code in a previously called routine without using the standard calling or return
conventions.
U Caution
Because setjmp and longjmp don't support correct destruction of stack frame
objects portably between C++ compilers, and because they might degrade
performance by preventing optimization on local variables, we don't recommend
their use in C++ programs. We recommend you use try and catch constructs
instead.
If you decide to use setjmp and longjmp in a C++ program, also include <setjmp.h> or
<setjmpex.h> to assure correct interaction between the functions and Structured
Exception Handling (SEH) or C++ exception handling.
Microsoft Specific
If you use an /EH option to compile C++ code, destructors for local objects are called
during the stack unwind. However, if you use /EHs or /EHsc to compile, and one of your
functions that uses noexcept calls longjmp , then the destructor unwind for that function
might not occur, depending on the optimizer state.
See also
Mixing C (Structured) and C++ Exceptions
Handle structured exceptions in C++
Article • 08/03/2021 • 4 minutes to read
The major difference between C structured exception handling (SEH) and C++ exception
handling is that the C++ exception handling model deals in types, while the C
structured exception handling model deals with exceptions of one type; specifically,
unsigned int . That is, C exceptions are identified by an unsigned integer value, whereas
C++ exceptions are identified by data type. When a structured exception is raised in C,
each possible handler executes a filter that examines the C exception context and
determines whether to accept the exception, pass it to some other handler, or ignore it.
When an exception is thrown in C++, it may be of any type.
When you use the /EHs or /EHsc compiler option, no C++ exception handlers handle
structured exceptions. These exceptions are handled only by __except structured
exception handlers or __finally structured termination handlers. For information, see
Structured Exception Handling (C/C++).
Under the /EHa compiler option, if a C exception is raised in a C++ program, it can be
handled by a structured exception handler with its associated filter or by a C++ catch
handler, whichever is dynamically nearer to the exception context. For example, this
sample C++ program raises a C exception inside a C++ try context:
// exceptions_Exception_Handling_Differences.cpp
// compile with: /EHa
#include <iostream>
int main() {
try {
SEHFunc();
}
catch( ... ) {
cout << "Caught a C exception."<< endl;
}
}
void SEHFunc() {
__try {
int x, y = 0;
x = 5 / y;
}
__finally {
cout << "In finally." << endl;
}
}
Output
In finally.
Caught a C exception.
Your wrapper class might have an interface consisting of some member functions that
determine the value of the exception, and that access the extended exception context
information provided by the C exception model. You might also want to define a default
constructor and a constructor that accepts an unsigned int argument (to provide for
the underlying C exception representation), and a bitwise copy constructor. Here is a
possible implementation of a C exception wrapper class:
C++
// exceptions_Exception_Handling_Differences2.cpp
// compile with: /c
class SE_Exception {
private:
SE_Exception() {}
SE_Exception( SE_Exception& ) {}
unsigned int nSE;
public:
SE_Exception( unsigned int n ) : nSE( n ) {}
~SE_Exception() {}
unsigned int getSeNumber() {
return nSE;
}
};
To use this class, install a custom C exception translation function that is called by the
internal exception handling mechanism each time a C exception is thrown. Within your
translation function, you can throw any typed exception (perhaps an SE_Exception type,
or a class type derived from SE_Exception ) that can be caught by an appropriate
matching C++ catch handler. The translation function can instead return, which
indicates that it did not handle the exception. If the translation function itself raises a C
exception, terminate is called.
To specify a custom translation function, call the _set_se_translator function with the
name of your translation function as its single argument. The translation function that
you write is called once for each function invocation on the stack that has try blocks.
There is no default translation function; if you do not specify one by calling
_set_se_translator, the C exception can only be caught by an ellipsis catch handler.
C++
// exceptions_Exception_Handling_Differences3.cpp
// compile with: /EHa
#include <stdio.h>
#include <eh.h>
#include <windows.h>
class SE_Exception {
private:
SE_Exception() {}
unsigned int nSE;
public:
SE_Exception( SE_Exception& e) : nSE(e.nSE) {}
SE_Exception(unsigned int n) : nSE(n) {}
~SE_Exception() {}
unsigned int getSeNumber() { return nSE; }
};
void SEFunc() {
__try {
int x, y = 0;
x = 5 / y;
}
__finally {
printf_s( "In finally\n" );
}
}
int main() {
_set_se_translator( trans_func );
try {
SEFunc();
}
catch( SE_Exception e ) {
printf_s( "Caught a __try exception with SE_Exception.\n" );
printf_s( "nSE = 0x%x\n", e.getSeNumber() );
}
}
Output
In trans_func.
In finally
Caught a __try exception with SE_Exception.
nSE = 0xc0000094
See also
Mixing C (Structured) and C++ exceptions
Structured Exception Handling (C/C++)
Article • 02/09/2023 • 4 minutes to read
Microsoft-specific:
Grammar
try-except-statement :
__try compound-statement __except ( filter-expression ) compound-statement
try-finally-statement :
__try compound-statement __finally compound-statement
Remarks
With SEH, you can ensure that resources, such as memory blocks and files, get released
correctly if execution unexpectedly terminates. You can also handle specific problems—
for example, insufficient memory—by using concise structured code that doesn't rely on
goto statements or elaborate testing of return codes.
The try-except and try-finally statements referred to in this article are Microsoft
extensions to the C and C++ languages. They support SEH by enabling applications to
gain control of a program after events that would otherwise terminate execution.
Although SEH works with C++ source files, it's not specifically designed for C++. If you
use SEH in a C++ program that you compile by using the /EHa or /EHsc option,
destructors for local objects are called, but other execution behavior might not be what
you expect. For an illustration, see the example later in this article. In most cases, instead
of SEH we recommend that you use ISO-standard C++ exception handling. By using
C++ exception handling, you can ensure that your code is more portable, and you can
handle exceptions of any type.
If you have C code that uses SEH, you can mix it with C++ code that uses C++ exception
handling. For information, see Handle structured exceptions in C++.
There are two SEH mechanisms:
These two kinds of handlers are distinct, but are closely related through a process
known as unwinding the stack. When a structured exception occurs, Windows looks for
the most recently installed exception handler that's currently active. The handler can do
one of three things:
The exception handler that recognizes the exception may not be in the function that was
running when the exception occurred. It may be in a function much higher on the stack.
The currently running function and all other functions on the stack frame are
terminated. During this process, the stack is unwound. That is, local non-static variables
of terminated functions get cleared from the stack.
As it unwinds the stack, the operating system calls any termination handlers that you've
written for each function. By using a termination handler, you clean up resources that
otherwise would remain open because of an abnormal termination. If you've entered a
critical section, you can exit it in the termination handler. When the program is going to
shut down, you can do other housekeeping tasks such as closing and removing
temporary files.
Next steps
Writing an exception handler
C++
#include <stdio.h>
#include <Windows.h>
#include <exception>
class TestClass
{
public:
~TestClass()
{
printf("Destroying TestClass!\n");
}
};
int main()
{
__try
{
TestExceptions();
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("Executing SEH __except block\n");
}
return 0;
}
If you use /EHsc to compile this code but the local test control macro CPPEX is
undefined, the TestClass destructor doesn't run. The output looks like this:
Output
If you use /EHsc to compile the code and CPPEX is defined by using /DCPPEX (so that a
C++ exception is thrown), the TestClass destructor runs, and the output looks like this:
Output
If you use /EHa to compile the code, the TestClass destructor executes whether an
exception was thrown using a standard C++ throw expression or by using SEH. That is,
whether CPPEX is defined or not. The output looks like this:
Output
END Microsoft-specific
See also
Exception handling
Keywords
<exception>
Errors and exception handling
Structured Exception Handling (Windows)
Writing an Exception Handler
Article • 08/03/2021 • 2 minutes to read
Exception handlers are typically used to respond to specific errors. You can use the
exception-handling syntax to filter out all exceptions other than those you know how to
handle. Other exceptions should be passed to other handlers (possibly in the run-time
library or the operating system) written to look for those specific exceptions.
Hardware exceptions
See also
Structured Exception Handling (C/C++)
try-except statement
Article • 08/03/2021 • 4 minutes to read
C++
// . . .
__try {
// guarded code
}
__except ( /* filter expression */ ) {
// termination code
}
// . . .
Grammar
try-except-statement :
__try compound-statement __except ( expression ) compound-statement
Remarks
The try-except statement is a Microsoft extension to the C and C++ languages. It
enables target applications to gain control when events occur that normally terminate
program execution. Such events are called structured exceptions, or exceptions for short.
The mechanism that deals with these exceptions is called structured exception handling
(SEH).
7 Note
Structured exception handling works with Win32 for both C and C++ source files.
However, it's not specifically designed for C++. You can ensure that your code is
more portable by using C++ exception handling. Also, C++ exception handling is
more flexible, in that it can handle exceptions of any type. For C++ programs, we
recommend you use native C++ exception-handling: try, catch, and throw
statements.
The compound statement after the __try clause is the body or guarded section. The
__except expression is also known as the filter expression. Its value determines how the
exception is handled. The compound statement after the __except clause is the
exception handler. The handler specifies the actions to take if an exception is raised
during execution of the body section. Execution proceeds as follows:
up the stack for a handler, first for containing try-except statements, then
for handlers with the next highest precedence.
The __except expression is evaluated as a C expression. It's limited to a single value, the
conditional-expression operator, or the comma operator. If more extensive processing is
required, the expression can call a routine that returns one of the three values listed
above.
It's not valid to jump into a __try statement, but valid to jump out of one. The
exception handler isn't called if a process is terminated in the middle of executing a
try-except statement.
For compatibility with previous versions, _try, _except, and _leave are synonyms for
__try , __except , and __leave unless compiler option /Za (Disable language extensions)
is specified.
A goto statement can also jump out of the guarded section, and it doesn't degrade
performance as it does in a try-finally statement. That's because stack unwinding
doesn't occur. However, we recommend that you use the __leave keyword rather than a
goto statement. The reason is because you're less likely to make a programming
C++
The pointer types PEXCEPTION_RECORD and PCONTEXT are defined in the include file
<winnt.h>, and _EXCEPTION_RECORD and _CONTEXT are defined in the include file
<excpt.h>
You can use GetExceptionCode within the exception handler. However, you can use
GetExceptionInformation only within the exception filter expression. The information it
points to is generally on the stack and is no longer available when control gets
transferred to the exception handler.
Example
C++
// exceptions_try_except_Statement.cpp
// Example of try-except and try-finally statements
#include <stdio.h>
#include <windows.h> // for EXCEPTION_ACCESS_VIOLATION
#include <excpt.h>
int main()
{
int* p = 0x00000000; // pointer to NULL
puts("hello");
__try
{
puts("in try");
__try
{
puts("in try");
*p = 13; // causes an access violation exception;
}
__finally
{
puts("in finally. termination: ");
puts(AbnormalTermination() ? "\tabnormal" : "\tnormal");
}
}
__except(filter(GetExceptionCode(), GetExceptionInformation()))
{
puts("in except");
}
puts("world");
}
Output
Output
hello
in try
in try
in filter.
caught AV as expected.
in finally. termination:
abnormal
in except
world
See also
Writing an exception handler
Structured Exception Handling (C/C++)
Keywords
Writing an exception filter
Article • 08/03/2021 • 2 minutes to read
You can handle an exception either by jumping to the level of the exception handler or
by continuing execution. Instead of using the exception handler code to handle the
exception and falling through, you can use a filter expression to clean up the problem.
Then, by returning EXCEPTION_CONTINUE_EXECUTION (-1), you may resume normal flow
without clearing the stack.
7 Note
For example, the following code uses a function call in the filter expression: this function
handles the problem and then returns -1 to resume normal flow of control:
C++
// exceptions_Writing_an_Exception_Filter.cpp
#include <windows.h>
int main() {
int Eval_Exception( int );
__try {}
}
void ResetVars( int ) {}
int Eval_Exception ( int n_except ) {
if ( n_except != STATUS_INTEGER_OVERFLOW &&
n_except != STATUS_FLOAT_OVERFLOW ) // Pass on most exceptions
return EXCEPTION_CONTINUE_SEARCH;
It's a good idea to use a function call in the filter expression whenever filter needs to do
anything complex. Evaluating the expression causes execution of the function, in this
case, Eval_Exception .
Note the use of GetExceptionCode to determine the exception. This function must be
called inside the filter expression of the __except statement. Eval_Exception can't call
GetExceptionCode , but it must have the exception code passed to it.
This handler passes control to another handler unless the exception is an integer or
floating-point overflow. If it is, the handler calls a function ( ResetVars is only an
example, not an API function) to reset some global variables. The __except statement
block, which in this example is empty, can never be executed because Eval_Exception
never returns EXCEPTION_EXECUTE_HANDLER (1).
Using a function call is a good general-purpose technique for dealing with complex filter
expressions. Two other C language features that are useful are:
The conditional operator is frequently useful here. It can be used to check for a specific
return code and then return one of two different values. For example, the filter in the
following code recognizes the exception only if the exception is
STATUS_INTEGER_OVERFLOW :
C++
The purpose of the conditional operator in this case is mainly to provide clarity, because
the following code produces the same results:
C++
The conditional operator is more useful in situations where you might want the filter to
evaluate to -1, EXCEPTION_CONTINUE_EXECUTION .
The comma operator lets you execute multiple expressions in sequence. It then returns
the value of the last expression. For example, the following code stores the exception
code in a variable and then tests it:
C++
__except( nCode = GetExceptionCode(), nCode == STATUS_INTEGER_OVERFLOW )
See also
Writing an exception handler
Structured Exception Handling (C/C++)
Raising software exceptions
Article • 08/03/2021 • 2 minutes to read
Some of the most common sources of program errors are not flagged as exceptions by
the system. For example, if you attempt to allocate a memory block but there is
insufficient memory, the run-time or API function does not raise an exception but
returns an error code.
However, you can treat any condition as an exception by detecting that condition in
your code and then reporting it by calling the RaiseException function. By flagging
errors this way, you can bring the advantages of structured exception handling to any
kind of run-time error.
Use exception-handling filters to test for the exception code you defined.
The <winerror.h> file shows the format for exception codes. To make sure that you do
not define a code that conflicts with an existing exception code, set the third most
significant bit to 1. The four most-significant bits should be set as shown in the
following table.
31- 11 These two bits describe the basic status of the code: 11 = error, 00 =
30 success, 01 = informational, 10 = warning.
You can set the first two bits to a setting other than 11 binary if you want, although the
"error" setting is appropriate for most exceptions. The important thing to remember is
to set bits 29 and 28 as shown in the previous table.
The resulting error code should therefore have the highest four bits set to hexadecimal
E. For example, the following definitions define exception codes that do not conflict with
any Windows exception codes. (You may, however, need to check which codes are used
by third-party DLLs.)
C++
After you have defined an exception code, you can use it to raise an exception. For
example, the following code raises the STATUS_INSUFFICIENT_MEM exception in response
to a memory allocation problem:
C++
If you want to simply raise an exception, you can set the last three parameters to 0. The
three last parameters are useful for passing additional information and setting a flag
that prevents handlers from continuing execution. See the RaiseException function in
the Windows SDK for more information.
In your exception-handling filters, you can then test for the codes you've defined. For
example:
C++
__try {
...
}
__except (GetExceptionCode() == STATUS_INSUFFICIENT_MEM ||
GetExceptionCode() == STATUS_FILE_BAD_FORMAT )
See also
Writing an exception handler
Structured exception handling (C/C++)
Hardware exceptions
Article • 08/03/2021 • 2 minutes to read
Most of the standard exceptions recognized by the operating system are hardware-
defined exceptions. Windows recognizes a few low-level software exceptions, but these
are usually best handled by the operating system.
Windows maps the hardware errors of different processors to the exception codes in
this section. In some cases, a processor may generate only a subset of these exceptions.
Windows preprocesses information about the exception and issues the appropriate
exception code.
The hardware exceptions recognized by Windows are summarized in the following table:
Many of the exceptions listed in the previous table are intended to be handled by
debuggers, the operating system, or other low-level code. With the exception of integer
and floating-point errors, your code should not handle these errors. Thus, you should
usually use the exception-handling filter to ignore exceptions (evaluate to 0). Otherwise,
you may prevent lower-level mechanisms from responding appropriately. You can,
however, take appropriate precautions against the potential effect of these low-level
errors by writing termination handlers.
See also
Writing an exception handler
Structured Exception Handling (C/C++)
Restrictions on exception handlers
Article • 08/03/2021 • 2 minutes to read
The principal limitation to using exception handlers in code is that you can't use a goto
statement to jump into a __try statement block. Instead, you must enter the statement
block through normal flow of control. You can jump out of a __try statement block, and
you can nest exception handlers as you choose.
See also
Writing an exception handler
Structured Exception Handling (C/C++)
Writing a Termination Handler
Article • 08/03/2021 • 2 minutes to read
Cleaning up resources
See also
Structured Exception Handling (C/C++)
try-finally statement
Article • 04/10/2023
Syntax
The following syntax describes the try-finally statement:
C++
// . . .
__try {
// guarded code
}
__finally {
// termination code
}
// . . .
Grammar
try-finally-statement :
__try compound-statement __finally compound-statement
The try-finally statement is a Microsoft extension to the C and C++ languages that
enable target applications to guarantee execution of cleanup code when execution of a
block of code is interrupted. Cleanup consists of such tasks as deallocating memory,
closing files, and releasing file handles. The try-finally statement is especially useful
for routines that have several places where a check is made for an error that could cause
premature return from the routine.
For related information and a code sample, see try-except Statement. For more
information on structured exception handling in general, see Structured Exception
Handling. For more information on handling exceptions in managed applications with
C++/CLI, see Exception Handling under /clr.
7 Note
Structured exception handling works with Win32 for both C and C++ source files.
However, it is not specifically designed for C++. You can ensure that your code is
more portable by using C++ exception handling. Also, C++ exception handling is
more flexible, in that it can handle exceptions of any type. For C++ programs, it is
recommended that you use the C++ exception-handling mechanism (try, catch,
and throw statements).
The compound statement after the __try clause is the guarded section. The compound
statement after the __finally clause is the termination handler. The handler specifies a
set of actions that execute when the guarded section is exited, whether it exits the
guarded section by an exception (abnormal termination), or by standard fall through
(normal termination).
Control reaches a __try statement by simple sequential execution (fall through). When
control enters the __try , its associated handler becomes active. If the flow of control
reaches the end of the try block, execution proceeds as follows:
2. When the termination handler completes, execution continues after the __finally
statement. However the guarded section ends (for example, via a goto out of the
guarded body or a return statement), the termination handler is executed before
the flow of control moves out of the guarded section.
If an exception occurs in the __try block, the operating system must find a handler for
the exception, or the program will fail. If a handler is found, any and all __finally blocks
are executed and execution resumes in the handler.
For example, suppose a series of function calls links function A to function D, as shown
in the following figure. Each function has one termination handler. If an exception is
raised in function D and handled in A, the termination handlers are called in this order
as the system unwinds the stack: D, C, B.
Order of termination-handler execution
7 Note
The behavior of try-finally is different from some other languages that support the
use of finally , such as C#. A single __try may have either, but not both, of
__finally and __except . If both are to be used together, an outer try-except
statement must enclose the inner try-finally statement. The rules specifying when
each block executes are also different.
For compatibility with previous versions, _try , _finally , and _leave are synonyms for
__try , __finally , and __leave unless compiler option /Za (Disable language
extensions) is specified.
A goto statement can also jump out of the guarded section, but it degrades
performance because it invokes stack unwinding. The __leave statement is more
efficient because it doesn't cause stack unwinding.
Abnormal Termination
Exiting a try-finally statement using the longjmp run-time function is considered
abnormal termination. It isn't legal to jump into a __try statement, but it's legal to jump
out of one. All __finally statements that are active between the point of departure
(normal termination of the __try block) and the destination (the __except block that
handles the exception) must be run. It's called a local unwind.
If a __try block is prematurely terminated for any reason, including a jump out of the
block, the system executes the associated __finally block as a part of the process of
unwinding the stack. In such cases, the AbnormalTermination function returns true if
called from within the __finally block; otherwise, it returns false .
The termination handler isn't called if a process is killed in the middle of executing a
try-finally statement.
END Microsoft-specific
See also
Writing a termination handler
Structured Exception Handling (C/C++)
Keywords
Termination-handler syntax
Cleaning up resources
Article • 08/03/2021 • 2 minutes to read
During termination-handler execution, you may not know which resources have been
acquired before the termination handler was called. It's possible that the __try
statement block was interrupted before all resources were acquired, so that not all
resources were opened.
To be safe, you should check to see which resources are open before proceeding with
termination-handling cleanup. A recommended procedure is to:
2. In the __try statement block, acquire resources. Handles are set to positive values
as the resource is acquired.
Example
For example, the following code uses a termination handler to close three files and
release a memory block. These resources were acquired in the __try statement block.
Before cleaning up a resource, the code first checks to see if the resource was acquired.
C++
// exceptions_Cleaning_up_Resources.cpp
#include <stdlib.h>
#include <malloc.h>
#include <stdio.h>
#include <windows.h>
void fileOps() {
FILE *fp1 = NULL,
*fp2 = NULL,
*fp3 = NULL;
LPVOID lpvoid = NULL;
errno_t err;
__try {
lpvoid = malloc( BUFSIZ );
int main() {
fileOps();
}
See also
Writing a termination handler
Structured Exception Handling (C/C++)
Timing of exception handling: A
summary
Article • 08/03/2021 • 2 minutes to read
7 Note
The Microsoft C++ compiler supports two forms of the setjmp and longjmp
statements. The fast version bypasses termination handling but is more efficient. To
use this version, include the file <setjmp.h>. The other version supports
termination handling as described in the previous paragraph. To use this version,
include the file <setjmpex.h>. The increase in performance of the fast version
depends on hardware configuration.
The operating system executes all termination handlers in the proper order before any
other code can be executed, including the body of an exception handler.
When the cause for interruption is an exception, the system must first execute the filter
portion of one or more exception handlers before deciding what to terminate. The order
of events is:
1. An exception is raised.
2. The system looks at the hierarchy of active exception handlers and executes the
filter of the handler with highest precedence. That's the exception handler most
recently installed and most deeply nested, going by blocks and function calls.
3. If this filter passes control (returns 0), the process continues until a filter is found
that doesn't pass control.
4. If this filter returns -1, execution continues where the exception was raised, and no
termination takes place.
The system unwinds the stack: It clears all stack frames between where the
exception was raised and the stack frame that contains the exception handler.
As the stack is unwound, each termination handler on the stack is executed.
Control passes to the line of code after the end of this exception handler.
See also
Writing a termination handler
Structured Exception Handling (C/C++)
Restrictions on Termination Handlers
Article • 08/03/2021 • 2 minutes to read
You can't use a goto statement to jump into a __try statement block or a __finally
statement block. Instead, you must enter the statement block through normal flow of
control. (You can, however, jump out of a __try statement block.) Also, you can't nest
an exception handler or termination handler inside a __finally block.
unusual happens. But if the system is unwinding the stack, that unwinding stops. Then,
the current function gains control as if there were no abnormal termination.
A return statement inside a __finally statement block presents roughly the same
situation. Control returns to the immediate caller of the function that contains the
termination handler. If the system was unwinding the stack, this process is halted. Then,
the program proceeds as if no exception had been raised.
See also
Writing a termination handler
Structured Exception Handling (C/C++)
Transporting exceptions between
threads
Article • 05/02/2023
The Microsoft C++ compiler (MSVC) supports transporting an exception from one thread
to another. Transporting exceptions enables you to catch an exception in one thread
and then make the exception appear to be thrown in a different thread. For example,
you can use this feature to write a multithreaded application where the primary thread
handles all the exceptions thrown by its secondary threads. Transporting exceptions is
useful mostly to developers who create parallel programming libraries or systems. To
implement transporting exceptions, MSVC provides the exception_ptr type and the
current_exception, rethrow_exception, and make_exception_ptr functions.
Syntax
C++
namespace std
{
typedef unspecified exception_ptr;
exception_ptr current_exception();
void rethrow_exception(exception_ptr p);
template<class E>
exception_ptr make_exception_ptr(E e) noexcept;
}
Parameters
unspecified
An unspecified internal class that is used to implement the exception_ptr type.
Remarks
Scenario
Imagine that you want to create an application that can scale to handle a variable
amount of work. To achieve this objective, you design a multithreaded application where
an initial, primary thread creates as many secondary threads as it needs in order to do
the job. The secondary threads help the primary thread to manage resources, to balance
loads, and to improve throughput. By distributing the work, the multithreaded
application performs better than a single-threaded application.
However, if a secondary thread throws an exception, you want the primary thread to
handle it. This is because you want your application to handle exceptions in a consistent,
unified manner regardless of the number of secondary threads.
Solution
To handle the previous scenario, the C++ Standard supports transporting an exception
between threads. If a secondary thread throws an exception, that exception becomes
the current exception. By analogy to the real world, the current exception is said to be in
flight. The current exception is in flight from the time it's thrown until the exception
handler that catches it returns.
The secondary thread can catch the current exception in a catch block, and then call the
current_exception function to store the exception in an exception_ptr object. The
exception_ptr object must be available to the secondary thread and to the primary
thread. For example, the exception_ptr object can be a global variable whose access is
controlled by a mutex. The term transport an exception means an exception in one
thread can be converted to a form that can be accessed by another thread.
Next, the primary thread calls the rethrow_exception function, which extracts and then
throws the exception from the exception_ptr object. When the exception is thrown, it
becomes the current exception in the primary thread. That is, the exception appears to
originate in the primary thread.
Finally, the primary thread can catch the current exception in a catch block and then
process it or throw it to a higher level exception handler. Or, the primary thread can
ignore the exception and allow the process to end.
Most applications don't have to transport exceptions between threads. However, this
feature is useful in a parallel computing system because the system can divide work
among secondary threads, processors, or cores. In a parallel computing environment, a
single, dedicated thread can handle all the exceptions from the secondary threads and
can present a consistent exception-handling model to any application.
For more information about the C++ Standards committee proposal, search the Internet
for document number N2179, titled "Language Support for Transporting Exceptions
between Threads".
Only the following combination of compiler options and programming statements can
transport an exception. Other combinations either can't catch exceptions, or can catch
but can't transport exceptions.
The /EHa compiler option and the catch statement can transport SEH and C++
exceptions.
The /EHa , /EHs , and /EHsc compiler options and the catch statement can
transport C++ exceptions.
The /clr compiler option and the catch statement can transport C++ exceptions.
The /clr compiler option implies specification of the /EHa option. The compiler
doesn't support transporting managed exceptions. This is because managed
exceptions, which are derived from the System.Exception class, are already objects
that you can move between threads by using the facilities of the common
language runtime.
) Important
We recommend that you specify the /EHsc compiler option and catch only
C++ exceptions. You expose yourself to a security threat if you use the /EHa
or /clr compiler option and a catch statement with an ellipsis exception-
declaration ( catch(...) ). You probably intend to use the catch statement to
capture a few specific exceptions. However, the catch(...) statement
captures all C++ and SEH exceptions, including unexpected ones that should
be fatal. If you ignore or mishandle an unexpected exception, malicious code
can use that opportunity to undermine the security of your program.
Usage
The following sections describe how to transport exceptions by using the exception_ptr
type, and the current_exception , rethrow_exception , and make_exception_ptr functions.
exception_ptr type
Use an exception_ptr object to reference the current exception or an instance of a user-
specified exception. In the Microsoft implementation, an exception is represented by an
EXCEPTION_RECORD structure. Each exception_ptr object includes an exception
reference field that points to a copy of the EXCEPTION_RECORD structure that represents
the exception.
When you declare an exception_ptr variable, the variable isn't associated with any
exception. That is, its exception reference field is NULL. Such an exception_ptr object is
called a null exception_ptr.
Comparisons
You can use the equal ( == ) and not-equal ( != ) operators to compare two exception_ptr
objects. The operators don't compare the binary value (bit pattern) of the
EXCEPTION_RECORD structures that represent the exceptions. Instead, the operators
compare the addresses in the exception reference field of the exception_ptr objects. So,
a null exception_ptr and the NULL value compare as equal.
current_exception function
Call the current_exception function in a catch block. If an exception is in flight and the
catch block can catch the exception, the current_exception function returns an
exception_ptr object that references the exception. Otherwise, the function returns a
Details
The current_exception function captures the exception that is in flight regardless of
whether the catch statement specifies an exception-declaration statement.
The destructor for the current exception is called at the end of the catch block if you
don't rethrow the exception. However, even if you call the current_exception function in
the destructor, the function returns an exception_ptr object that references the current
exception.
SEH exceptions
If you use the /EHa compiler option, you can catch an SEH exception in a C++ catch
block. The current_exception function returns an exception_ptr object that references
the SEH exception. And the rethrow_exception function throws the SEH exception if you
call it with the transported exception_ptr object as its argument.
If you catch an SEH exception, you must manage the memory referenced by any pointer
in the EXCEPTION_RECORD.ExceptionInformation data member array. You must guarantee
that the memory is valid during the lifetime of the corresponding exception_ptr object,
and that the memory is freed when the exception_ptr object is deleted.
You can use structured exception (SE) translator functions together with the transport
exceptions feature. If an SEH exception is translated to a C++ exception, the
current_exception function returns an exception_ptr that references the translated
exception instead of the original SEH exception. The rethrow_exception function throws
the translated exception, not the original exception. For more information about SE
translator functions, see _set_se_translator.
rethrow_exception function
After you store a caught exception in an exception_ptr object, the primary thread can
process the object. In your primary thread, call the rethrow_exception function together
with the exception_ptr object as its argument. The rethrow_exception function extracts
the exception from the exception_ptr object and then throws the exception in the
context of the primary thread. If the p parameter of the rethrow_exception function is a
null exception_ptr , the function throws std::bad_exception.
The extracted exception is now the current exception in the primary thread, and you can
handle it as you would any other exception. If you catch the exception, you can handle it
immediately or use a throw statement to send it to a higher level exception handler.
Otherwise, do nothing and let the default system exception handler terminate your
process.
make_exception_ptr function
The make_exception_ptr function takes an instance of a class as its argument and then
returns an exception_ptr that references the instance. Usually, you specify an exception
class object as the argument to the make_exception_ptr function, although any class
object can be the argument.
Example
The following example transports a standard C++ exception and a custom C++
exception from one thread to another.
C++
// transport_exception.cpp
// compile with: /EHsc /MD
#include <windows.h>
#include <stdio.h>
#include <exception>
#include <stdexcept>
Output
Requirements
Header: <exception>
See also
Exception Handling /EH (Exception Handling Model)
/clr (Common Language Runtime Compilation)
Assertion and User-Supplied Messages
(C++)
Article • 08/03/2021 • 2 minutes to read
The C++ language supports three error handling mechanisms that help you debug your
application: the #error directive, the static_assert keyword, and the assert Macro, _assert,
_wassert macro. All three mechanisms issue error messages, and two also test software
assertions. A software assertion specifies a condition that you expect to be true at a
particular point in your program. If a compile time assertion fails, the compiler issues a
diagnostic message and a compilation error. If a run-time assertion fails, the operating
system issues a diagnostic message and closes your application.
Remarks
The lifetime of your application consists of a preprocessing, compile, and run time
phase. Each error handling mechanism accesses debug information that is available
during one of these phases. To debug effectively, select the mechanism that provides
appropriate information about that phase:
The assert Macro, _assert, _wassert macro is in effect at run time. It evaluates a
user-specified expression, and if the result is zero, the system issues a diagnostic
message and closes your application. Many other macros, such as_ASSERT and
_ASSERTE, resemble this macro but issue different system-defined or user-defined
diagnostic messages.
See also
#error Directive (C/C++)
assert Macro, _assert, _wassert
_ASSERT, _ASSERTE, _ASSERT_EXPR Macros
static_assert
_STATIC_ASSERT Macro
Templates
static_assert
Article • 08/03/2021 • 3 minutes to read
Tests a software assertion at compile time. If the specified constant expression is false ,
the compiler displays the specified message, if one is provided, and the compilation fails
with error C2338; otherwise, the declaration has no effect.
Syntax
Parameters
constant-expression
An integral constant expression that can be converted to a Boolean. If the evaluated
expression is zero (false), the string-literal parameter is displayed and the compilation
fails with an error. If the expression is nonzero (true), the static_assert declaration has
no effect.
string-literal
An message that is displayed if the constant-expression parameter is zero. The message
is a string of characters in the base character set of the compiler; that is, not multibyte or
wide characters.
Remarks
The constant-expression parameter of a static_assert declaration represents a software
assertion. A software assertion specifies a condition that you expect to be true at a
particular point in your program. If the condition is true, the static_assert declaration
has no effect. If the condition is false, the assertion fails, the compiler displays the
message in string-literal parameter, and the compilation fails with an error. In Visual
Studio 2017 and later, the string-literal parameter is optional.
The compiler examines the static_assert declaration for syntax errors when the
declaration is encountered. The compiler evaluates the constant-expression parameter
immediately if it does not depend on a template parameter. Otherwise, the compiler
evaluates the constant-expression parameter when the template is instantiated.
Consequently, the compiler might issue a diagnostic message once when the
declaration is encountered, and again when the template is instantiated.
You can use the static_assert keyword at namespace, class, or block scope. (The
static_assert keyword is technically a declaration, even though it does not introduce
new name into your program, because it can be used at namespace scope.)
compiler examines the static_assert declaration when it is declared, but does not
evaluate the constant-expression parameter until the basic_string class template is
instantiated in main() .
#include <type_traits>
#include <iosfwd>
namespace std {
template <class CharT, class Traits = std::char_traits<CharT> >
class basic_string {
static_assert(std::is_pod<CharT>::value,
"Template argument CharT must be a POD type in class
template basic_string");
// ...
};
}
struct NonPOD {
NonPOD(const NonPOD &) {}
virtual ~NonPOD() {}
};
int main()
{
std::basic_string<char> bs;
}
C++20 introduces modules, a modern solution that turns C++ libraries and programs
into components. A module is a set of source code files that are compiled independently
of the translation units that import them. Modules eliminate or reduce many of the
problems associated with the use of header files. They often reduce compilation times.
Macros, preprocessor directives, and non-exported names declared in a module aren't
visible outside the module. They have no effect on the compilation of the translation
unit that imports the module. You can import modules in any order without concern for
macro redefinitions. Declarations in the importing translation unit don't participate in
overload resolution or name lookup in the imported module. After a module is compiled
once, the results are stored in a binary file that describes all the exported types,
functions, and templates. The compiler can process that file much faster than a header
file. And, the compiler can reuse it every place where the module is imported in a
project.
You can use modules side by side with header files. A C++ source file can import
modules and also #include header files. In some cases, you can import a header file as a
module rather than include it textually by using #include in the preprocessor. We
recommend you use modules in new projects rather than header files as much as
possible. For larger existing projects under active development, experiment with
converting legacy headers to modules. Base your adoption on whether you get a
meaningful reduction in compilation times.
To contrast modules with other ways to import the standard library, see Compare
header units, modules, and precompiled headers.
Before it was specified by the C++20 standard, Microsoft had experimental support for
modules in the Microsoft C++ compiler. The compiler also supported importing the
Standard Library as modules, described below.
Starting with Visual Studio 2022 version 17.5, importing the Standard Library as a
module is both standardized and fully implemented in the Microsoft C++ compiler. This
section describes the older, experimental method, which is still supported. For
information about the new standardized way to import the Standard Library using
modules, see Import the C++ standard library using modules.
You can use the modules feature to create single-partition modules and to import the
Standard Library modules provided by Microsoft. To enable support for Standard Library
modules, compile with /experimental:module and /std:c++latest. In a Visual Studio
project, right-click the project node in Solution Explorer and choose Properties. Set the
Configuration drop-down to All Configurations, then choose Configuration Properties
> C/C++ > Language > Enable C++ Modules (experimental).
A module and the code that consumes it must be compiled with the same compiler
options.
By importing the C++ Standard Library as modules rather than including it through
header files, you can potentially speed up compilation times depending on the size of
your project. The experimental library is split into the following named modules:
To consume these modules, add an import declaration to the top of the source code file.
For example:
C++
import std.core;
import std.regex;
To consume the Microsoft Standard Library modules, compile your program with /EHsc
and /MD options.
Basic example
The following example shows a simple module definition in a source file called
Example.ixx . The .ixx extension is required for module interface files in Visual Studio.
In this example, the interface file contains both the function definition and the
declaration. However, you can also place the definitions in one or more separate module
implementation files, as shown in a later example. The export module Example;
statement indicates that this file is the primary interface for a module called Example .
The export modifier on f() indicates that this function is visible when Example is
imported by another program or module. The module references a namespace
Example_NS .
C++
// Example.ixx
export module Example;
#define ANSWER 42
namespace Example_NS
{
int f_internal() {
return ANSWER;
}
The file MyProgram.cpp uses the import declaration to access the name that is exported
by Example . The name Example_NS is visible here, but not all of its members. Also, the
macro ANSWER isn't visible.
C++
// MyProgram.cpp
import Example;
import std.core;
int main()
{
cout << "The result of f() is " << Example_NS::f() << endl; // 42
// int i = Example_NS::f_internal(); // C2039
// int j = ANSWER; //C2065
}
Module grammar
module-name :
module-name-qualifier-seq :
identifier .
module-name-qualifier-seq identifier .
module-partition :
: module-name
module-declaration :
module-import-declaration :
export opt import module-name attribute-specifier-seq opt ;
Implementing modules
A module interface exports the module name and all the namespaces, types, functions,
and so on that make up the public interface of the module. A module implementation
defines the things exported by the module. In its simplest form, a module can consist of
a single file that combines the module interface and implementation. You can also put
the implementations in one or more separate module implementation files, similar to
how .h and .cpp files are used.
For larger modules, you can split parts of the module into submodules called partitions.
Each partition consists of a module interface file that exports a module partition name. A
partition may also have one or more partition implementation files. The module as a
whole has one primary module interface, the public interface of the module that may
also import and export the partition interfaces.
A module consists of one or more module units. A module unit is a translation unit (a
source file) that contains a module declaration. There are several types of module units:
A module interface unit is a module unit that exports a module name or module
partition name. A module interface unit has export module in its module
declaration.
A module implementation unit is a module unit that doesn't export a module name
or module partition name. As the name implies, it's used to implement a module.
A primary module interface unit is a module interface unit that exports the module
name. There must be one and only one primary module interface unit in a module.
A module partition interface unit is a module interface unit that exports a module
partition name.
The export keyword is used in interface files only. An implementation file can import
another module, but can't export any names. Implementation files can have any
extension.
Module partitions
A module partition is similar to a module, except it shares ownership of all declarations
in the entire module. All names exported by partition interface files are imported and re-
exported by the primary interface file. A partition's name must begin with the module
name followed by a colon. Declarations in any of the partitions are visible within the
entire module. No special precautions are needed to avoid one-definition-rule (ODR)
errors. You can declare a name (function, class, and so on) in one partition and define it
in another. A partition implementation file begins like this:
C++
module Example:part1;
C++
To access declarations in another partition, a partition must import it, but it can only use
the partition name, not the module name:
C++
module Example:part2;
import :part1;
The primary interface unit must import and re-export all of the module's interface
partition files like this:
C++
The primary interface unit can import partition implementation files, but can't export
them. Those files aren't allowed to export any names. This restriction enables a module
to keep implementation details internal to the module.
C++
// MyModuleA.cpp
#include "customlib.h"
#include "anotherlib.h"
import std.core;
import MyModuleB;
You can use a traditional header file to control which modules are imported:
C++
// MyProgram.h
import std.core;
#ifdef DEBUG_LOGGING
import std.filesystem;
#endif
module is that any preprocessor definitions in the header are visible in the importing
program immediately after the import statement.
C++
import <vector>;
import "myheader.h";
See also
module, import, export
Named modules tutorial
Compare header units, modules, and precompiled headers
module , import , export
Article • 02/15/2022 • 2 minutes to read
The module , import , and export declarations are available in C++20 and require the
/experimental:module compiler switch along with /std:c++20 or later (such as
/std:c++latest ). For more information, see Overview of modules in C++.
module
Place a module declaration at the beginning of a module implementation file to specify
that the file contents belong to the named module.
C++
module ModuleA;
export
Use an export module declaration for the module's primary interface file, which must
have extension .ixx :
C++
In an interface file, use the export modifier on names that are intended to be part of the
public interface:
C++
// ModuleA.ixx
namespace ModuleA_NS
{
export int f();
export double d();
double internal_f(); // not exported
}
Non-exported names aren't visible to code that imports the module:
C++
//MyProgram.cpp
import ModuleA;
int main() {
ModuleA_NS::f(); // OK
ModuleA_NS::d(); // OK
ModuleA_NS::internal_f(); // Ill-formed: error C2065: 'internal_f':
undeclared identifier
}
The export keyword may not appear in a module implementation file. When export is
applied to a namespace name, all names in the namespace are exported.
import
Use an import declaration to make a module's names visible in your program. The
import declaration must appear after the module declaration and after any #include
C++
module ModuleA;
#include "custom-lib.h"
import std.core;
import std.regex;
import ModuleB;
Remarks
Both import and module are treated as keywords only when they appear at the start of a
logical line:
C++
// OK:
module ;
module module-name
import :
import <
import "
import module-name
export module ;
export module module-name
export import :
export import <
export import "
export import module-name
// Error:
int i; module ;
Microsoft Specific
In Microsoft C++, the tokens import and module are always identifiers and never
keywords when they're used as arguments to a macro.
Example
C++
See Also
Overview of modules in C++
Tutorial: Import the C++ standard
library using modules from the
command line
Article • 02/27/2023 • 14 minutes to read
Learn how to import the C++ standard library using C++ library modules. This is
significantly faster to compile and more robust than using header files or header units
or precompiled headers (PCH).
How to import the standard library as a module from the command line.
The performance and usability benefits of modules.
The two standard library modules std and std.compat and the difference between
them.
Prerequisites
This tutorial requires Visual Studio 2022 17.5 or later.
2 Warning
This tutorial is for a preview feature. The feature is subject to change between
preview releases. You shouldn't use preview features in production code.
It's now possible to import the standard library as a module instead of as a tangle of
header files. This is significantly faster and more robust than including header files or
header units or precompiled headers (PCH).
The C++23 standard library introduces two named modules: std and std.compat .
std exports the declarations and names defined in the C++ standard library
namespace std such as std::vector and std::sort . It also exports the contents of
C wrapper headers such as <cstdio> and <cstdlib> , which provide functions like
std::printf() . C functions defined in the global namespace, such as ::printf() ,
aren't exported. This improves the situation where including a C wrapper header
like <cstdio> also included C header files like stdio.h , which brought in the C
global namespace versions. This is no longer a problem if you import std .
std.compat exports everything in std and adds the global namespace
The compiler imports the entire standard library when you use import std; or import
std.compat; and does it faster than bringing in a single header file. That is, it's faster to
bring in the entire standard library with import std; (or import std.compat ) than it's to
#include <vector> , for example.
Because named modules don't expose macros, macros like assert , errno , offsetof ,
va_arg , and others aren't available when you import std or std.compat . See Standard
library named module considerations for workarounds.
Like header files, modules allow you to share declarations and definitions across source
files. But unlike header files, modules aren't fragile and are easier to compose because
their semantics don't change due to macro definitions or the order in which you import
them. The compiler can process modules significantly faster than it can process
#include files, and uses less memory at compile time as well. Named modules don't
This article demonstrates the new and best way to consume the standard library. For
more information about alternative ways to consume the standard library, see Compare
header units, modules, and precompiled headers.
The statement import std; or import std.compat; imports the standard library into
your application. But first, you must compile the standard library named modules. The
following steps demonstrate how.
Example: std
1. Open a x86 Native Tools Command Prompt for VS: from the Windows Start menu,
type x86 native and the prompt should appear in the list of apps. Ensure that the
prompt is for Visual Studio 2022 preview version 17.5 or above. You'll get errors if
you use the wrong version of the prompt. The examples used in this tutorial are for
the CMD shell. If you use PowerShell, substitute
"$Env:VCToolsInstallDir\modules\std.ixx" for
"%VCToolsInstallDir\modules\std.ixx" .
dos
If you get errors, ensure that you're using the correct version of the command
prompt. If you're still having issues, please file a bug at Visual Studio Developer
Community .
You should compile the std named module using the same compiler settings that
you intend to use with the code that imports it. If you have a multi-project
solution, you can compile the standard library named module once, and then refer
to it from all of your projects by using the /reference compiler option.
Using the previous compiler command, the compiler outputs two files:
interface that the compiler consults to process the import std; statement.
This is a compile-time only artifact. It doesn't ship with your application.
std.obj contains the implementation of the named module. Add std.obj to
the command line when you compile the sample app to statically link the
functionality you use from the standard library into your application.
Switch Meaning
/std:c++:latest Use the latest version of the C++ language standard and library. Although
module support is available under /std:c++20 , you need the latest
standard library to get support for standard library named modules.
/EHsc Use C++ exception handling, except for functions marked extern "C" .
4. To try out importing the std library, start by creating a file named
importExample.cpp with the following content:
C++
// requires /std:c++latest
import std;
int main()
{
std::cout << "Import the STL library for best performance\n";
std::vector<int> v{5, 5, 5};
for (const auto& e : v)
{
std::cout << e;
}
}
In the preceding code, import std; replaces #include <vector> and #include
<iostream> . The statement import std; makes all of the standard library available
with one statement. If you're concerned about performance, it may help to know
that importing the entire standard library is often significantly faster than
processing a single standard library header file such as #include <vector> .
5. Compile the example by using the following command in the same directory as the
previous step:
dos
We didn't have to specify std.ifc on the command line because the compiler
automatically looks for the .ifc file that matches the module name specified by
an import statement. When the compiler encounters import std; , it finds std.ifc
since we put it in the same directory as the source code--relieving us of the need
to specify it on the command line. If the .ifc file is in a different directory than the
source code, use the /reference compiler switch to refer to it.
If you're building a single project, you can combine the steps of building the std
standard library named module and the step of building your application by
adding "%VCToolsInstallDir%\modules\std.ixx" to the command line. Make sure
to put it before any .cpp files that consume it. By default, the output executable's
name is taken from the first input file. Use the /Fe compiler option to specify the
output file name you want. This tutorial shows compiling the std named module
as a separate step because you only need to build the standard library named
module once, and then you can refer to it from your project, or from multiple
projects. But it may be convenient to build everything together, as shown by this
command line:
dos
Given the previous command line, the compiler produces an executable named
importExample.exe . When you run it, it produces the following output:
Output
Import the STL library for best performance
555
The key command-line switches in this example are the same as the previous
example, except that the /c switch isn't used.
Example: std.compat
Before you can use import std.compat; in your code, you must compile the named
module std.compat.ixx . The steps are similar to for building the std named module.
The steps include building the std named module first because std.compat depends on
it:
1. Open a Native Tools Command Prompt for VS: from the Windows Start menu, type
x86 native and the prompt should appear in the list of apps. Ensure that the
prompt is for Visual Studio 2022 preview version 17.5 or above. You'll get compiler
errors if you use the wrong version of the prompt.
2. Create a directory to try this example, such as
%USERPROFILE%\source\repos\STLModules , and make it the current directory. If you
choose a directory that you don't have write access to, you'll get errors such as not
being able to open the output file std.ifc .
3. Compile the std and std.compat named modules with the following command:
dos
You should compile std and std.compat using the same compiler settings that you
intend to use with the code that imports them. If you have a multi-project solution,
you can compile them once, and then refer to them from all of your projects using
the /reference compiler option.
If you get errors, ensure that you're using the correct version of the command
prompt. If you're still having issues, please file a bug at Visual Studio Developer
Community . While this feature is still in preview, you can find a list of known
problems under Standard library header units and modules tracking issue 1694 .
The compiler outputs four files from the previous two steps:
std.ifc is the compiled binary named module interface that the compiler
consults to process the import std; statement. The compiler also consults
std.ifc to process import std.compat; because std.compat builds on std .
C++
import std.compat;
int main()
{
printf("Import std.compat to get global names like printf()\n");
and C runtime functions available with one statement. If you're concerned about
performance, the performance of modules is such that importing this named
module, which includes the C++ standard library and C runtime library global
namespace functions, is faster than even processing a single include like #include
<vector> .
dos
us of the need to specify it on the command line. If the .ifc file is in a different
directory than the source code, use the /reference compiler switch to refer to it.
Even though we're importing std.compat , you must also link against std.obj
because that is where the standard library implementation lives that std.compat
builds upon.
If you're building a single project, you can combine the step of building the std
and std.compat standard library named modules with the step of building your
application by adding "%VCToolsInstallDir%\modules\std.ixx" and
"%VCToolsInstallDir%\modules\std.compat.ixx" (in that order) to the command
line. Make sure to put them before any .cpp files that consume them, and specify
/Fe to name the built exe as shown in this example:
dos
I've shown them as separate steps in this tutorial because you only need to build
the standard library named modules once, and then you can refer to them from
your project, or from multiple projects. But it may be convenient to build them all
at once.
Output
tools used at the time of this writing. Select the version of the named module to use the
same way you choose the version of the header file to use--by the directory you refer to
them from.
Don't mix and match importing header units and named modules. For example, don't
import <vector>; and import std; in the same file.
Don't mix and match importing C++ standard library header files and named modules.
For example, don't #include <vector> and import std; in the same file. However, you
can include C headers and import named modules in the same file. For example, you
can import std; and #include <math.h> in the same file. Just don't include the C++
standard library version, <cmath> .
You don't have to defend against importing a module multiple times: no header guard
#ifndef required. The compiler knows when it has already imported a named module
and ignores duplicate attempts to do so.
If you need to use the errno macro, #include <errno.h> . Because named modules don't
expose macros, this is the workaround if you need to check for errors from <math.h> , for
example.
Macros such as NAN , INFINITY , and INT_MIN are defined by <limits.h> , which you can
include. However, if you import std; you can use numeric_limits<double>::quiet_NaN()
and numeric_limits<double>::infinity() instead of NAN and INFINITY , and
std::numeric_limits<int>::min() instead of INT_MIN .
Summary
In this tutorial, you've imported the standard library using modules. Next, learn about
creating and importing your own modules in Named modules tutorial in C++.
See also
Compare header units, modules, and precompiled headers
Overview of modules in C++
A Tour of C++ Modules in Visual Studio
Moving a project to C++ named Modules
Named modules tutorial (C++)
Article • 02/14/2023 • 21 minutes to read
This tutorial is about creating C++20 modules. Modules replace header files. You'll learn
how modules are an improvement on header files.
Prerequisites
This tutorial requires Visual Studio 2022 17.1.0 or later.
You might get IntelliSense errors while working on the code example in this tutorial.
Work on the IntelliSense engine is catching up with the compiler. IntelliSense errors can
be ignored and won't prevent the code example from building. To track progress on the
IntelliSense work, see this issue .
Like header files, modules allow you to share declarations and definitions across source
files. But unlike header files, modules don't leak macro definitions or private
implementation details.
Modules are easier to compose because their semantics don't change because of macro
definitions or what else has been imported, the order of imports, and so on. They also
make it easier to control what is visible to consumers.
Modules provide extra safety guarantees that header files don't. The compiler and linker
work together to prevent possible name collision issues, and provide stronger one
definition rule (ODR ) guarantees.
A strong ownership model avoids clashes between names at link time because the linker
attaches exported names to the module that exports them. This model allows the
Microsoft Visual C++ compiler to prevent undefined behavior caused by linking
different modules that report similar names in the same program. For more information,
see Strong Ownership .
A module is made up of one or more source code files compiled into a binary file. The
binary file describes all the exported types, functions, and templates in the module.
When a source file imports a module, the compiler reads in the binary file that contains
the contents of the module. Reading the binary file is much faster than processing a
header file. Also, the binary file is reused by the compiler every time the module is
imported, saving even more time. Because a module is built once rather than every time
it's imported, build time can be reduced, sometimes dramatically.
More importantly, modules don't have the fragility problems that header files do.
Importing a module doesn't change the module's semantics, or the semantics of any
other imported module. Macros, preprocessor directives, and non-exported names
declared in a module aren't visible to the source file that imports it. You can import
modules in any order and it won't change the meaning of the modules.
Modules can be used side by side with header files. This feature is convenient if you're
migrating a code base to use modules because you can do it in stages.
In some cases, a header file can be imported as a header unit rather than as an #include
file. Header units are the recommended alternative to precompiled header files (PCH).
They're easier to set up and use than shared PCH files, but they provide similar
performance benefits. For more information, see Walkthrough: Build and import header
units in Microsoft Visual C++.
Your code can consume modules in the same project, or any referenced projects,
automatically by using project-to-project references to static library projects.
In Visual Studio 2022 or later, choose Create a new project and then the Console App
(for C++) project type. If this project type isn't available, you may not have selected the
Desktop development with C++ workload when you installed Visual Studio. You can
use the Visual Studio Installer to add the C++ workload.
Give the new project the name ModulesTutorial and create the project.
Because modules are a C++20 feature, use the /std:c++20 or /std:c++latest compiler
option. In the Solution Explorer, right-click on the project name ModulesTutorial , then
choose Properties. In the project Property Pages dialog, change Configuration to All
Configurations and Platform to All Platforms. Select Configuration Properties >
General in the tree view pane on the left. Select the C++ Language Standard property.
Use the dropdown to change the property value to ISO C++20 Standard (/std:c++20).
Select OK to accept the change.
To add a primary module interface unit, in Solution Explorer, right-click Source Files
then select Add > Module.
In the Add New Item dialog that appears, give the new module the name
BasicPlane.Figures.ixx and choose Add.
The default contents of the created module file has two lines:
C++
The export module keywords in the first line declare that this file is a module interface
unit. There's a subtle point here: for every named module, there must be exactly one
module interface unit with no module partition specified. That module unit is called the
primary module interface unit.
The primary module interface unit is where you declare the functions, types, templates,
other modules, and module partitions to expose when source files import the module. A
module can consist of multiple files, but only the primary module interface file identifies
what to expose.
This line identifies this file as the primary module interface and gives the module a
name: BasicPlane.Figures . The period in the module name has no special meaning to
the compiler. A period can be used to convey how your module is organized. If you have
multiple module files that work together, you can use periods to indicate a separation of
concerns. In this tutorial, we'll use periods to indicate different functional areas of the
API.
This name is also where the "named" in "named module" comes from. The files that are
part of this module use this name to identify themselves as part of the named module. A
named module is the collection of module units with the same module name.
We should talk about the API we'll implement for a moment before going further. It
impacts the choices we make next. The API represents different shapes. We're only
going to provide a couple shapes in this example: Point and Rectangle . Point is meant
to be used as part of more complex shapes, such as Rectangle .
To illustrate some features of modules, we'll factor this API into pieces. One piece will be
the Point API. The other part will be Rectangle . Imagine that this API will grow into
something more complex. The division is useful for separating concerns or easing code
maintenance.
So far, we've created the primary module interface that will expose this API. Let's now
build the Point API. We want it to be part of this module. For reasons of logical
organization, and potential build efficiency, we want to make this part of the API easily
understandable on its own. To do so, we'll create a module partition file.
When you import a partition into the primary module, all its declarations become visible
to the primary module regardless of whether they're exported. Partitions can be
imported into any partition interface, primary module interface, or module unit that
belongs to the named module.
To create a module partition file, in the Solution Explorer right-click Source Files, then
select Add > Module. Name the file BasicPlane.Figures-Point.ixx and choose Add.
Because it's a module partition file, we've added a hyphen and the name of the partition
to the module name. This convention aids the compiler in the command-line case
because the compiler uses name lookup rules based on the module name to find the
compiled .ifc file for the partition. This way you don't have to provide explicit
/reference command-line arguments to find the partitions that belong to the module.
It's also helpful for organizing the files that belong to a module by name because you
can easily see which files belong to which modules.
C++
The file starts with export module . These keywords are also how the primary module
interface begins. What makes this file different is the colon ( : ) following the module
name, followed by the partition name. This naming convention identifies the file as a
module partition. Because it defines the module interface for a partition, it isn't
considered the primary module interface.
In this file, the export keyword makes struct Point visible to consumers.
The next partition we'll define is Rectangle . Create another module file using the same
steps as before: In Solution Explorer, right-click on Source Files, then select Add >
Module. Name the file BasicPlane.Figures-Rectangle.ixx and select Add.
C++
import :Point;
Next, import :Point; shows how to import a module partition. The import statement
makes all the exported types, functions, and templates in the module partition visible to
the module. You don't have to specify the module name. The compiler knows that this
file belongs to the BasicPlane.Figures module because of the export module
BasicPlane.Figures:Rectangle; at the top of the file.
Next, the code exports the definition of struct Rectangle and declarations for some
functions that return various properties of the rectangle. The export keyword indicates
whether to make what it precedes visible to consumers of the module. It's used to make
the functions area , height , and width visible outside of the module.
All definitions and declarations in a module partition are visible to the importing module
unit whether they have the export keyword or not. The export keyword governs
whether the definition, declaration, or typedef will be visible outside of the module
when you export the partition in the primary module interface.
All module partitions must be exposed as part of the module definition that they belong
to. Partitions are exposed in the primary module interface. Open the
BasicPlane.Figures.ixx file, which defines the primary module interface. Replace its
contents with:
C++
The two lines that begin with export import are new here. When combined like this,
these two keywords instruct the compiler to import the specified module and make it
visible to consumers of this module. In this case, the colon ( : ) in the module name
indicates that we are importing a module partition.
The imported names don't include the full module name. For example, the :Point
partition was declared as export module BasicPlane.Figures:Point . Yet here we're
importing :Point . Because we're in the primary module interface file for the module
BasicPlane.Figures , the module name is implied, and only the partition name is
specified.
So far, we've defined the primary module interface, which exposes the API surface we
want to make available. But we've only declared, not defined, area() , height() , or
width() . We'll do that next by creating a module implementation file.
click in the Solution Explorer on Source Files, select Add > New item and then select
C++ File (.cpp). Give the new file the name BasicPlane.Figures-Rectangle.cpp , then
choose Add.
The naming convention for the module partition's implementation file follows the
naming convention for a partition. But it has a .cpp extension because it's an
implementation file.
C++
module;
module BasicPlane.Figures:Rectangle;
This file begins with module; which introduces a special area of the module called the
global module fragment. It precedes the code for the named module and is where you
can use preprocessor directives such as #include . Code in the global module fragment
isn't owned or exported by the module interface.
When you include a header file, you generally don't want it to be treated as an exported
part of the module. You typically include the header file as an implementation detail that
shouldn't be part of the module interface. There may be advanced cases where want to
do that, but generally you don't. No separate metadata ( .ifc files) are generated for
#include directives in the global module fragment. Global module fragments provide a
The module implementation file we're building doesn't include any libraries because it
doesn't need them as part of its implementation. But if it did, this area is where the
#include directives would go.
The line module BasicPlane.Figures:Rectangle; indicates that this file is part of the
named module BasicPlane.Figures . The compiler automatically brings the types and
functions exposed by the primary module interface into this file. A module
implementation unit doesn't have the export keyword before the module keyword in its
module declaration.
Next are the definition of the functions area() , height() , and width() . They were
declared in the Rectangle partition in BasicPlane.Figures-Rectangle.ixx . Because the
primary module interface for this module imported the Point and Rectangle module
partitions, those types are visible here in the module unit implementation file. An
interesting feature of module implementation units: The compiler automatically makes
everything in the corresponding module primary interface visible to the file. No imports
<module-name> is needed.
Anything you declare within an implementation unit is only visible to the module that it
belongs to.
C++
#include <iostream>
import BasicPlane.Figures;
int main()
{
Rectangle r{ {1,8}, {11,3} };
std::cout << "area: " << area(r) << '\n';
std::cout << "width: " << width(r) << '\n';
return 0;
}
The statement import BasicPlane.Figures; makes all the exported functions and types
from the BasicPlane.Figures module visible to this file. It can come before or after any
#include directives.
The app then uses the types and functions from the module to output the area and
width of the defined rectangle:
Output
area: 50
width: 10
Anatomy of a module
Let's now look in more detail at the various module files.
It has an .ixx extension by default. However, you can treat a source file with any
extension as a module interface file. To do so, set the Compile As property in the
Advanced tab for the source file's properties page to Compile As Module (/interface):
The basic outline of a module interface definition file is:
C++
// Everything after this point is visible only within this file, and isn't
// visible to any of the other files that belong to the named module.
This file must begin with either module; to indicate the beginning of the global module
fragment, or export module [module-name]; to indicate the start of the module purview.
The module purview is where functions, types, templates, and so on, go that you want to
expose from the module.
It's also where you can expose other modules or module partitions via the export
import keywords, as shown in the BasicPlane.Figures.ixx file.
The primary interface file must export all the interface partitions defined for the module
directly or indirectly, or the program is ill-formed.
The private module partition is where you can put things that you want to be only
visible in this file.
Module interface units preface the keyword module with the keyword export .
Module implementation units are useful for breaking up a large module into smaller
pieces, which can result in faster build times. This technique is covered briefly in the Best
practices section.
Module implementation unit files have a .cpp extension. The basic outline of a module
implementation unit file is:
C++
// implementation
All names exported by partition interface files must be imported and re-exported
( export import ) by the primary interface file. A partition's name must begin with the
module name, followed by a colon, and then the name of the partition.
C++
// This is where #include directives go. They only apply to this file and
aren't shared
// with other module implementation files.
// Macro definitions aren't visible outside of this file or to importers
// import statements aren't allowed here. They go in the module preamble,
below
Module naming
You can use periods ('.') in your module names but they have no special meaning
to the compiler. Use them to convey meaning to the users of your module. For
example, start with the library or project top namespace. Finish with a name that
describes the module's functionality. BasicPlane.Figures is meant to convey an
API for geometric planes, and specifically figures that can be represented on a
plane.
The name of the file that contains the module primary interface is generally the
name of the module. For example, given the module name BasicPlane.Figures ,
the name of the file containing the primary interface would be named
BasicPlane.Figures.ixx .
If you're building from the command line and you use this naming convention for
module partitions, then you won't have to explicitly add /reference for each module
partition file. The compiler will look for them automatically based on the name of the
module. The name of the compiled partition file (ending with an .ifc extension) is
generated from the module name. Consider the module name
BasicPlane.Figures:Rectangle : the compiler will anticipate that the corresponding
compiled partition file for Rectangle is named BasicPlane.Figures-Rectangle.ifc . The
compiler uses this naming scheme to make it easier to use module partitions by
automatically finding the interface unit files for partitions.
You can name them using your own convention. But then you'll need to specify
corresponding /reference arguments to the command-line compiler.
Factor modules
Use module implementation files and partitions to factor your module for easier code
maintenance and potentially faster compilation times.
For example, moving the implementation of a module out of the module interface
definition file and into a module implementation file means that changes to the
implementation won't necessarily cause every file that imports the module to recompile
(unless you have inline implementations).
Module partitions make it easier to logically factor a large module. They can be used to
improve compilation time so that changes to a portion of the implementation don't
cause all the module's files to be recompiled.
Summary
In this tutorial, you've been introduced to the basics of C++20 modules. You've created
a primary module interface, defined a module partition, and built a module
implementation file.
See also
Overview of modules in C++
module, import, export keywords
A Tour of C++ Modules in Visual Studio
Practical C++20 Modules and the future of tooling around C++ Modules
Moving a project to C++ named Modules
Walkthrough: Build and import header units in Microsoft Visual C++
Templates (C++)
Article • 10/17/2022 • 7 minutes to read
Templates are the basis for generic programming in C++. As a strongly-typed language,
C++ requires all variables to have a specific type, either explicitly declared by the
programmer or deduced by the compiler. However, many data structures and
algorithms look the same no matter what type they are operating on. Templates enable
you to define the operations of a class or function, and let the user specify what
concrete types those operations should work on.
C++
The above code describes a template for a generic function with a single type parameter
T, whose return value and call parameters (lhs and rhs) are all of this type. You can name
a type parameter anything you like, but by convention single upper case letters are most
commonly used. T is a template parameter; the typename keyword says that this
parameter is a placeholder for a type. When the function is called, the compiler will
replace every instance of T with the concrete type argument that is either specified by
the user or deduced by the compiler. The process in which the compiler generates a
class or function from a template is referred to as template instantiation; minimum<int> is
an instantiation of the template minimum<T> .
Elsewhere, a user can declare an instance of the template that is specialized for int.
Assume that get_a() and get_b() are functions that return an int:
C++
int a = get_a();
int b = get_b();
int i = minimum<int>(a, b);
However, because this is a function template and the compiler can deduce the type of T
from the arguments a and b, you can call it just like an ordinary function:
C++
When the compiler encounters that last statement, it generates a new function in which
every occurrence of T in the template is replaced with int :
C++
The rules for how the compiler performs type deduction in function templates are based
on the rules for ordinary functions. For more information, see Overload Resolution of
Function Template Calls.
Type parameters
In the minimum template above, note that the type parameter T is not qualified in any
way until it is used in the function call parameters, where the const and reference
qualifiers are added.
C++
The keyword class is equivalent to typename in this context. You can express the
previous example as:
C++
C++
Any built-in or user-defined type can be used as a type argument. For example, you can
use std::vector in the Standard Library to store variables of type int , double , std::string,
MyClass , const MyClass *, MyClass& , and so on. The primary restriction when using
templates is that a type argument must support any operations that are applied to the
type parameters. For example, if we call minimum using MyClass as in this example:
C++
class MyClass
{
public:
int num;
std::wstring description;
};
int main()
{
MyClass mc1 {1, L"hello"};
MyClass mc2 {2, L"goodbye"};
auto result = minimum(mc1, mc2); // Error! C2678
}
A compiler error will be generated because MyClass does not provide an overload for
the < operator.
There is no inherent requirement that the type arguments for any particular template all
belong to the same object hierarchy, although you can define a template that enforces
such a restriction. You can combine object-oriented techniques with templates; for
example, you can store a Derived* in a vector<Base*>. Note that the arguments must be
pointers
C++
vector<MyClass*> vec;
MyDerived d(3, L"back again", time(0));
vec.push_back(&d);
// or more realistically:
vector<shared_ptr<MyClass>> vec2;
vec2.push_back(make_shared<MyDerived>());
The basic requirements that std::vector and other standard library containers impose
on elements of T is that T be copy-assignable and copy-constructible.
Non-type parameters
Unlike generic types in other languages such as C# and Java, C++ templates support
non-type parameters, also called value parameters. For example, you can provide a
constant integral value to specify the length of an array, as with this example that is
similar to the std::array class in the Standard Library:
C++
Note the syntax in the template declaration. The size_t value is passed in as a template
argument at compile time and must be const or a constexpr expression. You use it like
this:
C++
Other kinds of values including pointers and references can be passed in as non-type
parameters. For example, you can pass in a pointer to a function or function object to
customize some operation inside the template code.
C++
template <auto x> constexpr auto constant = x;
C++
Because the Arr parameter itself has no body, its parameter names are not needed. In
fact, it is an error to refer to Arr's typename or class parameter names from within the
body of MyClass2 . For this reason, Arr's type parameter names can be omitted, as shown
in this example:
C++
C++
C++
vector<int> myInts;
C++
For multiple template arguments, all arguments after the first default argument must
have default arguments.
When using a template whose parameters are all defaulted, use empty angle brackets:
C++
Template specialization
In some cases, it isn't possible or desirable for a template to define exactly the same
code for any type. For example, you might wish to define a code path to be executed
only if the type argument is a pointer, or a std::wstring, or a type derived from a
particular base class. In such cases you can define a specialization of the template for
that particular type. When a user instantiates the template with that type, the compiler
uses the specialization to generate the class, and for all other types, the compiler
chooses the more general template. Specializations in which all parameters are
specialized are complete specializations. If only some of the parameters are specialized, it
is called a partial specialization.
C++
template <typename K, typename V>
class MyMap{/*...*/};
A template can have any number of specializations as long as each specialized type
parameter is unique. Only class templates may be partially specialized. All complete and
partial specializations of a template must be declared in the same namespace as the
original template.
Syntax
typename identifier ;
Remarks
The typename keyword must be used if a name in a template definition is a qualified
name that is dependent on a template argument; it's optional if the qualified name isn't
dependent. For more information, see Templates and Name Resolution.
C++
The typename keyword can also be used in place of class in template parameter lists.
For example, the following statements are semantically equivalent:
C++
Example
C++
// typename.cpp
template<class T> class X
{
typename T::Y m_y; // treat Y as a type
};
int main()
{
}
See also
Templates
Keywords
Class Templates
Article • 07/01/2022 • 7 minutes to read
This article describes rules that are specific to C++ class templates.
C++
// member_function_templates1.cpp
template<class T, int i> class MyStack
{
T* pStack;
T StackBuffer[i];
static const int cItems = i * sizeof(T);
public:
MyStack( void );
void push( const T item );
T& pop( void );
};
int main()
{
}
As with any template class member function, the definition of the class's constructor
member function includes the template argument list twice.
Member functions can themselves be function templates and specify extra parameters,
as in the following example.
C++
// member_templates.cpp
template<typename T>
class X
{
public:
template<typename U>
void mf(const U &u);
};
int main()
{
}
Nested class templates are declared as class templates inside the scope of the outer
class. They can be defined inside or outside of the enclosing class.
The following code demonstrates a nested class template inside an ordinary class.
C++
// nested_class_template1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class X
{
Y<int> yInt;
Y<char> yChar;
public:
X(int i, char c) : yInt(i), yChar(c) { }
void print()
{
cout << yInt.m_t << " " << yChar.m_t << endl;
}
};
int main()
{
X x(1, 'a');
x.print();
}
The following code uses nested template type parameters to create nested class
templates:
C++
// nested_class_template2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
Y<int> y;
public:
X(T t) { y.Value() = t; }
void print() { y.print(); }
};
int main()
{
X<int>* xi = new X<int>(10);
X<char>* xc = new X<char>('c');
xi->print();
xc->print();
delete xi;
delete xc;
}
/* Output:
X<T>::Y<U>::Y()
X<T>::Y<U>::Y()
10
99
X<T>::Y<U>::~Y()
X<T>::Y<U>::~Y()
*/
Template friends
Class templates can have friends. A class or class template, function, or function
template can be a friend to a template class. Friends can also be specializations of a
class template or function template, but not partial specializations.
In the following example, a friend function is defined as a function template within the
class template. This code produces a version of the friend function for every
instantiation of the template. This construct is useful if your friend function depends on
the same template parameters as the class does.
C++
// template_friend1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
public:
Array(int sz): size(sz) {
array = new T[size];
memset(array, 0, size * sizeof(T));
}
Array(const Array& a) {
size = a.size;
array = new T[size];
memcpy_s(array, a.array, sizeof(T));
}
T& operator[](int i) {
return *(array + i);
}
void print() {
for (int i = 0; i < size; i++)
cout << *(array + i) << " ";
template<class T>
friend Array<T>* combine(Array<T>& a1, Array<T>& a2);
};
template<class T>
Array<T>* combine(Array<T>& a1, Array<T>& a2) {
Array<T>* a = new Array<T>(a1.size + a2.size);
for (int i = 0; i < a1.size; i++)
(*a)[i] = *(a1.array + i);
return a;
}
int main() {
Array<char> alpha1(26);
for (int i = 0 ; i < alpha1.Length() ; i++)
alpha1[i] = 'A' + i;
alpha1.print();
Array<char> alpha2(26);
for (int i = 0 ; i < alpha2.Length() ; i++)
alpha2[i] = 'a' + i;
alpha2.print();
Array<char>*alpha3 = combine(alpha1, alpha2);
alpha3->print();
delete alpha3;
}
/* Output:
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
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
*/
The next example involves a friend that has a template specialization. A function
template specialization is automatically a friend if the original function template is a
friend.
It's also possible to declare only the specialized version of the template as the friend, as
the comment before the friend declaration in the following code indicates. If you declare
a specialization as a friend, you must put the definition of the friend template
specialization outside of the template class.
C++
// template_friend2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
Array<char> ac(10);
f(ac);
Array<int> a(10);
f(a);
}
/* Output:
10 generic
10 int
*/
The next example shows a friend class template declared within a class template. The
class template is then used as the template argument for the friend class. Friend class
templates must be defined outside of the class template in which they're declared. Any
specializations or partial specializations of the friend template are also friends of the
original class template.
C++
// template_friend3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
Factory< X<int> > XintFactory;
X<int>* x1 = XintFactory.GetNewObject(65);
X<int>* x2 = XintFactory.GetNewObject(97);
Factory< X<char> > XcharFactory;
X<char>* x3 = XcharFactory.GetNewObject(65);
X<char>* x4 = XcharFactory.GetNewObject(97);
x1->print();
x2->print();
x3->print();
x4->print();
}
/* Output:
65
97
A
a
*/
C++
// template_specifications2.cpp
class Y
{
};
template<class T, T* pT> class X1
{
};
template<class T1, class T2 = T1> class X2
{
};
Y aY;
int main()
{
}
See also
Templates
Function Templates
Article • 08/03/2021 • 2 minutes to read
Class templates define a family of related classes that are based on the type arguments
passed to the class upon instantiation. Function templates are similar to class templates
but define a family of functions. With function templates, you can specify a set of
functions that are based on the same code but act on different types or classes. The
following function template swaps two items:
C++
// function_templates1.cpp
template< class T > void MySwap( T& a, T& b ) {
T c(a);
a = b;
b = c;
}
int main() {
}
This code defines a family of functions that swap the values of the arguments. From this
template, you can generate functions that will swap int and long types and also user-
defined types. MySwap will even swap classes if the class's copy constructor and
assignment operator are properly defined.
In addition, the function template will prevent you from swapping objects of different
types, because the compiler knows the types of the a and b parameters at compile time.
C++
int j = 10;
int k = 18;
CString Hello = "Hello, Windows!";
MySwap( j, k ); //OK
MySwap( j, Hello ); //error
The second MySwap call triggers a compile-time error, because the compiler cannot
generate a MySwap function with parameters of different types. If void pointers were
used, both function calls would compile correctly, but the function would not work
properly at run time.
Explicit specification of the template arguments for a function template is allowed. For
example:
C++
// function_templates2.cpp
template<class T> void f(T) {}
int main(int j) {
f<char>(j); // Generate the specialization f(char).
// If not explicitly specified, f(int) would be deduced.
}
When the template argument is explicitly specified, normal implicit conversions are
done to convert the function argument to the type of the corresponding function
template parameters. In the above example, the compiler will convert j to type char .
See also
Templates
Function Template Instantiation
Explicit Instantiation
Explicit Specialization of Function Templates
Function Template Instantiation
Article • 08/03/2021 • 2 minutes to read
When a function template is first called for each type, the compiler creates an
instantiation. Each instantiation is a version of the templated function specialized for the
type. This instantiation will be called every time the function is used for the type. If you
have several identical instantiations, even in different modules, only one copy of the
instantiation will end up in the executable file.
C++
// function_template_instantiation.cpp
template<class T> void f(T) { }
See also
Function Templates
Explicit instantiation
Article • 09/28/2022 • 2 minutes to read
Examples
This code explicitly instantiates MyStack for int variables and six items:
C++
This statement creates an instantiation of MyStack without reserving any storage for an
object. Code is generated for all members.
The next line explicitly instantiates only the constructor member function:
C++
You can explicitly instantiate function templates by using a specific type argument to
redeclare them, as shown in the example in Function template instantiation.
You can use the extern keyword to prevent the automatic instantiation of members. For
example:
C++
Similarly, you can mark specific members as being external and not instantiated:
C++
7 Note
The extern keyword in the specialization only applies to member functions defined
outside of the body of the class. Functions defined inside the class declaration are
considered inline functions and are always instantiated.
See also
Function templates
Explicit Specialization of Function
Templates
Article • 08/03/2021 • 2 minutes to read
With a function template, you can define special behavior for a specific type by
providing an explicit specialization (override) of the function template for that type. For
example:
C++
This declaration enables you to define a different function for double variables. Like
non-template functions, standard type conversions (such as promoting a variable of
type float to double ) are applied.
Example
C++
// explicit_specialization.cpp
template<class T> void f(T t)
{
};
See also
Function Templates
Partial ordering of function templates
(C++)
Article • 09/28/2022 • 2 minutes to read
Multiple function templates that match the argument list of a function call can be
available. C++ defines a partial ordering of function templates to specify which function
should be called. The ordering is partial because there can be some templates that are
considered equally specialized.
The compiler chooses the most specialized function template available from the
possible matches. For example, if a function template takes a type T and another
function template that takes T* is available, the T* version is said to be more
specialized. It's preferred over the generic T version whenever the argument is a pointer
type, even though both would be allowable matches.
Use the following process to determine if one function template candidate is more
specialized:
3. With the parameter list in T1 , see if T2 is a valid template for that parameter list.
Ignore any implicit conversions.
5. If one template is a valid template argument list for the other template, but the
converse isn't true, then that template is considered to be less specialized than the
other template. If by using the previous step, both templates form valid arguments
for each other, then they're considered to be equally specialized, and an
ambiguous call results when you attempt to use them.
a. A template specialization for a specific type is more specialized than one taking
a generic type argument.
b. A template taking only T* is more specialized than one taking only T , because
a hypothetical type X* is a valid argument for a T template argument, but X
isn't a valid argument for a T* template argument.
c. const T is more specialized than T , because const X is a valid argument for a
T template argument, but X isn't a valid argument for a const T template
argument.
Example
The following sample works as specified in the standard:
C++
// partial_ordering_of_function_templates.cpp
// compile with: /EHsc
#include <iostream>
int main() {
int i =0;
const int j = 0;
int *pi = &i;
const int *cpi = &j;
Output
Output
Less specialized function called
More specialized function called
Even more specialized function for const T*
See also
Function templates
Member function templates
Article • 09/28/2022 • 2 minutes to read
The term member template refers to both member function templates and nested class
templates. Member function templates are function templates that are members of a
class or class template.
Member functions can be function templates in several contexts. All functions of class
templates are generic but aren't referred to as member templates or member function
templates. If these member functions take their own template arguments, they're
considered to be member function templates.
C++
// member_function_templates.cpp
struct X
{
template <class T> void mf(T* t) {}
};
int main()
{
int i;
X* x = new X();
x->mf(&i);
}
C++
// member_function_templates2.cpp
template<typename T>
class X
{
public:
template<typename U>
void mf(const U &u)
{
}
};
int main()
{
}
// defining_member_templates_outside_class.cpp
template<typename T>
class X
{
public:
template<typename U>
void mf(const U &u);
};
int main()
{
}
Member function templates can't be virtual functions. And, they can't override virtual
functions from a base class when they're declared with the same name as a base class
virtual function.
C++
// templated_user_defined_conversions.cpp
template <class T>
struct S
{
template <class U> operator S<U>()
{
return S<U>();
}
};
int main()
{
S<int> s1;
S<long> s2 = s1; // Convert s1 using UDC and copy constructs S<long>.
}
See also
Function templates
Template Specialization (C++)
Article • 08/03/2021 • 5 minutes to read
Class templates can be partially specialized, and the resulting class is still a template.
Partial specialization allows template code to be partially customized for specific types in
situations, such as:
A template has multiple types and only some of them need to be specialized. The
result is a template parameterized on the remaining types.
A template has only one type, but a specialization is needed for pointer, reference,
pointer to member, or function pointer types. The specialization itself is still a
template on the type pointed to or referenced.
// partial_specialization_of_class_templates.cpp
#include <stdio.h>
struct S{};
int main() {
printf_s("PTS<S>::IsPointer == %d \nPTS<S>::IsPointerToDataMember ==
%d\n",
PTS<S>::IsPointer, PTS<S>:: IsPointerToDataMember);
printf_s("PTS<S*>::IsPointer == %d \nPTS<S*>::IsPointerToDataMember ==
%d\n"
, PTS<S*>::IsPointer, PTS<S*>:: IsPointerToDataMember);
printf_s("PTS<int S::*>::IsPointer == %d \nPTS"
"<int S::*>::IsPointerToDataMember == %d\n",
PTS<int S::*>::IsPointer, PTS<int S::*>::
IsPointerToDataMember);
}
Output
PTS<S>::IsPointer == 0
PTS<S>::IsPointerToDataMember == 0
PTS<S*>::IsPointer == 1
PTS<S*>::IsPointerToDataMember == 0
PTS<int S::*>::IsPointer == 0
PTS<int S::*>::IsPointerToDataMember == 1
C++
// partial_specialization_of_class_templates2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
public:
Bag() : elem(0), size(0), max_size(1) {}
void add(T t) {
T* tmp;
if (size + 1 >= max_size) {
max_size *= 2;
tmp = new T [max_size];
for (int i = 0; i < size; i++)
tmp[i] = elem[i];
tmp[size++] = t;
delete[] elem;
elem = tmp;
}
else
elem[size++] = t;
}
void print() {
for (int i = 0; i < size; i++)
cout << elem[i] << " ";
cout << endl;
}
};
public:
Bag() : elem(0), size(0), max_size(1) {}
void add(T* t) {
T* tmp;
if (t == NULL) { // Check for NULL
cout << "Null pointer!" << endl;
return;
}
void print() {
for (int i = 0; i < size; i++)
cout << elem[i] << " ";
cout << endl;
}
};
int main() {
Bag<int> xi;
Bag<char> xc;
Bag<int*> xp; // Uses partial specialization for pointer types.
xi.add(10);
xi.add(9);
xi.add(8);
xi.print();
xc.add('a');
xc.add('b');
xc.add('c');
xc.print();
Output
10 9 8
a b c
Null pointer!
3 87 8 100
C++
// partial_specialization_of_class_templates3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void print() {
for (int i = 0; i < size; i++)
cout << "{" << keys[i] << ", " << values[i] << "}" << endl;
}
};
void sort() {
// Sort method is defined.
int smallest = 0;
for (int i = 0; i < size - 1; i++) {
for (int j = i; j < size; j++) {
if (keys[j] < keys[smallest])
smallest = j;
}
swap(keys[i], keys[smallest]);
swap(values[i], values[smallest]);
}
}
void print() {
for (int i = 0; i < size; i++)
cout << "{" << keys[i] << ", " << values[i] << "}" << endl;
}
};
int main() {
Dictionary<const char*, const char*> dict(10);
dict.print();
dict.add("apple", "fruit");
dict.add("banana", "fruit");
dict.add("dog", "animal");
dict.print();
Output
{apple, fruit}
{banana, fruit}
{dog, animal}
{100, apple}
{101, banana}
{103, dog}
{89, cat}
Sorted list:
{89, cat}
{100, apple}
{101, banana}
{103, dog}
Templates and Name Resolution
Article • 08/03/2021 • 2 minutes to read
Locally declared names, including the name of the template itself and any names
declared inside the template definition.
While the first two names also pertain to class and function scopes, special rules for
name resolution are required in template definitions to deal with the added complexity
of dependent names. This is because the compiler knows little about these names until
the template is instantiated, because they could be totally different types depending on
which template arguments are used. Nondependent names are looked up according to
the usual rules and at the point of definition of the template. These names, being
independent of the template arguments, are looked up once for all template
specializations. Dependent names are not looked up until the template is instantiated
and are looked up separately for each specialization.
C++
C++
T::myType
C++
N::T
A const or volatile type for which the base type is a dependent type:
C++
const T
C++
C++
C++
T<int>, MyTemplate<T>
See also
Templates
Name Resolution for Dependent Types
Article • 08/03/2021 • 2 minutes to read
Use typename for qualified names in template definitions to tell the compiler that the
given qualified name identifies a type. For more information, see typename.
C++
// template_name_resolution1.cpp
#include <stdio.h>
template <class T> class X
{
public:
void f(typename T::myType* mt) {}
};
class Yarg
{
public:
struct myType { };
};
int main()
{
X<Yarg> x;
x.f(new Yarg::myType());
printf("Name resolved by using typename keyword.");
}
Output
Name lookup for dependent names examines names from both the context of the
template definition—in the following example, this context would find myFunction(char)
—and the context of the template instantiation.In the following example, the template is
instantiated in main; therefore, the MyNamespace::myFunction is visible from the point of
instantiation and is picked as the better match. If MyNamespace::myFunction were
renamed, myFunction(char) would be called instead.
All names are resolved as if they were dependent names. Nevertheless, we recommend
that you use fully qualified names if there is any possible conflict.
C++
// template_name_resolution2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void myFunction(char)
{
cout << "Char myFunction" << endl;
}
namespace MyNamespace
{
void myFunction(int)
{
cout << "Int MyNamespace::myFunction" << endl;
}
};
int main()
{
Class1<int>* c1 = new Class1<int>(100);
}
Output
Output
Int MyNamespace::myFunction
Template Disambiguation
Visual Studio 2012 enforces the C++98/03/11 standard rules for disambiguation with
the "template" keyword. In the following example, Visual Studio 2010 would accept both
the nonconforming lines and the conforming lines. Visual Studio 2012 accepts only the
conforming lines.
C++
#include <iostream>
#include <ostream>
#include <typeinfo>
using namespace std;
int main() {
cout << typeid(Container<int, Allocator<float>>::AX).name() << endl;
}
See also
Name Resolution
Name Resolution for Locally Declared
Names
Article • 09/28/2022 • 3 minutes to read
The template's name itself can be referred to with or without the template arguments. In
the scope of a class template, the name itself refers to the template. In the scope of a
template specialization or partial specialization, the name alone refers to the
specialization or partial specialization. Other specializations or partial specializations of
the template can also be referenced, with the appropriate template arguments.
C++
// template_name_resolution3.cpp
// compile with: /c
template <class T> class A {
A* a1; // A refers to A<T>
A<int>* a2; // A<int> refers to a specialization of A.
A<T*>* a3; // A<T*> refers to the partial specialization A<T*>.
};
C++
// template_name_resolution4.cpp
// compile with: /EHsc
template <class T>
class Base1 {};
int main() {
// Derived1<int> d;
}
C++
// template_name_resolution5.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main() {
C<int> c;
c.f();
}
Output
Z::Z()
C++
// template_name_resolution6.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
namespace NS {
void g() { cout << "NS::g" << endl; }
int main() {
NS::C<int> c;
c.f();
}
Output
C<T>::g
C++
// template_name_resolution7.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
struct B {
int i;
void print() { cout << "Base" << endl; }
};
int main() {
C<int, 1> c;
c.f();
cout << c.i << endl;
}
Output
Base
1
See also
Name resolution
Overload resolution of function
template calls
Article • 09/28/2022 • 2 minutes to read
A function template can overload non-template functions of the same name. In this
scenario, the compiler first attempts to resolve a function call by using template
argument deduction to instantiate the function template with a unique specialization. If
template argument deduction fails, then the compiler considers both instantiated
function template overloads and non-template function overloads to resolve the call.
These other overloads are known as the candidate set. If template argument deduction
succeeds, then the generated function is compared with the other functions in the
candidate set to determine the best match, following the rules for overload resolution.
For more information, see Function overloading.
C++
// template_name_resolution9.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
f(1, 1); // Equally good match; choose the non-template function.
f('a', 1); // Chooses the function template.
f<int, int>(2, 2); // Template arguments explicitly specified.
}
Output
f(int, int)
void f(T1, T2)
void f(T1, T2)
C++
// template_name_resolution10.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
long l = 0;
int i = 0;
// Call the function template f(long, int) because f(int, int)
// would require a conversion from long to int.
f(l, i);
}
Output
See also
Name resolution
typename
Source code organization (C++
Templates)
Article • 07/01/2022 • 3 minutes to read
When defining a class template, you must organize the source code in such a way that
the member definitions are visible to the compiler when it needs them. You have the
choice of using the inclusion model or the explicit instantiation model. In the inclusion
model, you include the member definitions in every file that uses a template. This
approach is simplest and provides maximum flexibility in terms of what concrete types
can be used with your template. Its disadvantage is that it can increase compilation
times. The times can be significant if a project or the included files themselves are large.
With the explicit instantiation approach, the template itself instantiates concrete classes
or class members for specific types. This approach can speed up compilation times, but
it limits usage to only those classes that the template implementer has enabled ahead of
time. In general, we recommend that you use the inclusion model unless the
compilation times become a problem.
Background
Templates aren't like ordinary classes in the sense that the compiler doesn't generate
object code for a template or any of its members. There's nothing to generate until the
template is instantiated with concrete types. When the compiler encounters a template
instantiation such as MyClass<int> mc; and no class with that signature exists yet, it
generates a new class. It also attempts to generate code for any member functions that
are used. If those definitions are in a file that isn't #included, directly or indirectly, in the
.cpp file that is being compiled, the compiler can't see them. From the compiler's point
of view, it's not necessarily an error. The functions may be defined in another translation
unit where the linker will find them. If the linker doesn't find that code, it raises an
unresolved external error.
C++
#ifndef MYARRAY
#define MYARRAY
#include <iostream>
T& operator[](int i)
{
return arr[i];
}
};
#endif
With this approach, the compiler has access to the complete template definition and can
instantiate templates on-demand for any type. It's simple and relatively easy to
maintain. However, the inclusion model does have a cost in terms of compilation times.
This cost can be significant in large programs, especially if the template header itself
#includes other headers. Every .cpp file that #includes the header will get its own copy
of the function templates and all the definitions. The linker will generally be able to sort
things out so that you don't end up with multiple definitions for a function, but it takes
time to do this work. In smaller programs that extra compilation time is probably not
significant.
You create an explicit instantiation by using the keyword template followed by the
signature of the entity you want to instantiate. This entity can be a type or a member. If
you explicitly instantiate a type, all members are instantiated.
C++
//MyArray.h
#ifndef MYARRAY
#define MYARRAY
The source file MyArray.cpp explicitly instantiates template MyArray<double, 5> and
template MyArray<string, 5> :
C++
//MyArray.cpp
#include <iostream>
#include "MyArray.h"
In the previous example, the explicit instantiations are at the bottom of the .cpp file. A
MyArray may be used only for double or String types.
7 Note
Event handling is primarily supported for COM classes (C++ classes that implement
COM objects, typically using ATL classes or the coclass attribute). For more information,
see Event handling in COM.
Event handling is also supported for native C++ classes (C++ classes that don't
implement COM objects). Native C++ event handling support is deprecated and will be
removed in a future release. For more information, see Event handling in native C++.
7 Note
Event attributes in native C++ are incompatible with Standard C++. They don't
compile when you specify /permissive- conformance mode.
Event handling supports both single- and multithreaded usage. It protects data from
simultaneous multithread access. You can derive subclasses from event source or
receiver classes. These subclasses support extended event sourcing and receiving.
The Microsoft C++ compiler includes attributes and keywords for declaring events and
event handlers. The event attributes and keywords can be used in CLR programs and in
native C++ programs.
Article Description
See also
C++ language reference
Keywords
__event keyword
Article • 09/21/2021 • 3 minutes to read
Declares an event.
7 Note
Event attributes in native C++ are incompatible with Standard C++. They don't
compile when you specify /permissive- conformance mode.
Syntax
__event member-function-declarator ;
Remarks
The Microsoft-specific keyword __event can be applied to a member function
declaration, an interface declaration, or a data member declaration. However, you can't
use the __event keyword to qualify a member of a nested class.
Depending on whether your event source and receiver are native C++, COM, or
managed (.NET Framework), you can use the following constructs as events:
- interface -
- - data member
Use __hook in an event receiver to associate a handler member function with an event
member function. After you create an event with the __event keyword, all event
handlers hooked to that event afterward get called when the event is called.
Native events
Native events are member functions. The return type is typically HRESULT or void , but
can be any integral type, including an enum . When an event uses an integral return type,
an error condition is defined when an event handler returns a nonzero value. In this
case, the event that's raised calls the other delegates.
C++
COM events
COM events are interfaces. The parameters of a member function in an event source
interface should be in parameters, but it isn't rigorously enforced. It's because an out
parameter isn't useful when multicasting. A level 1 warning is issued if you use an out
parameter.
The return type is typically HRESULT or void , but can be any integral type, including
enum . When an event uses an integral return type and an event handler returns a
nonzero value, it's an error condition. The event being raised aborts the calls to the
other delegates. The compiler automatically marks an event source interface as a source
in the generated IDL.
The __interface keyword is always required after __event for a COM event source.
C++
Managed events are data members or member functions. When used with an event, the
return type of a delegate must conform to the Common Language Specification. The
return type of the event handler must match the return type of the delegate. For more
information on delegates, see Delegates and Events. If a managed event is a data
member, its type must be a pointer to a delegate.
In the .NET Framework, you can treat a data member as if it were a method itself (that is,
the Invoke method of its corresponding delegate). To do so, predefine the delegate
type for declaring a managed event data member. In contrast, a managed event method
implicitly defines the corresponding managed delegate if it isn't already defined. For
example, you can declare an event value such as OnClick as an event as follows:
C++
When implicitly declaring a managed event, you can specify add and remove accessors
that get called when event handlers are added or removed. You can also define the
member function that calls (raises) the event from outside the class.
// EventHandling_Native_Event.cpp
// compile with: /c
[event_source(native)]
class CSource {
public:
__event void MyEvent(int nValue);
};
[ dual, uuid("00000000-0000-0000-0000-000000000002") ]
__interface IEventSource {
[id(1)] HRESULT MyEvent();
};
[ coclass, uuid("00000000-0000-0000-0000-000000000003"), event_source(com)
]
class CSource : public IEventSource {
public:
__event __interface IEventSource;
HRESULT FireEvent() {
__raise MyEvent();
return S_OK;
}
};
See also
Keywords
Event handling
event_source
event_receiver
__hook
__unhook
__raise
__hook keyword
Article • 08/03/2021 • 2 minutes to read
7 Note
Event attributes in native C++ are incompatible with Standard C++. They don't
compile when you specify /permissive- conformance mode.
Syntax
C++
long __hook(
&SourceClass::EventMethod,
source,
&ReceiverClass::HandlerMethod
[, receiver = this]
);
long __hook(
interface,
source
);
Parameters
&SourceClass::EventMethod
A pointer to the event method to which you hook the event handler method:
Native C++ events: SourceClass is the event source class and EventMethod is the
event.
COM events: SourceClass is the event source interface and EventMethod is one of
its methods.
Managed events: SourceClass is the event source class and EventMethod is the
event.
interface
The interface name being hooked to receiver , only for COM event receivers in which
the layout_dependent parameter of the event_receiver attribute is true .
source
A pointer to an instance of the event source. Depending on the code type specified in
event_receiver , source can be one of these types:
&ReceiverClass::HandlerMethod
Native C++ events: ReceiverClass is the event receiver class and HandlerMethod is
the handler.
receiver
(Optional) A pointer to an instance of the event receiver class. If you don't specify a
receiver, the default is the receiver class or structure in which __hook is called.
Usage
Can be use in any function scope, including main, outside the event receiver class.
Remarks
Use the intrinsic function __hook in an event receiver to associate or hook a handler
method with an event method. The specified handler is then called when the source
raises the specified event. You can hook several handlers to a single event or hook
several events to a single handler.
There are two forms of __hook . You can use the first (four-argument) form in most cases,
specifically, for COM event receivers in which the layout_dependent parameter of the
event_receiver attribute is false .
In these cases, you don't need to hook all methods in an interface before firing an event
on one of the methods. You only need to hook the method handling the event. You can
use the second (two-argument) form of __hook only for a COM event receiver in which
layout_dependent = true .
__hook returns a long value. A nonzero return value indicates that an error has occurred
The compiler checks for the existence of an event and that the event signature agrees
with the delegate signature.
You can call __hook and __unhook outside the event receiver, except for COM events.
For information on coding managed events in the new syntax, see event.
7 Note
Example
See Event handling in native C++ and Event handling in COM for samples.
See also
Keywords
Event handling
event_source
event_receiver
__event
__unhook
__raise
__raise keyword
Article • 08/03/2021 • 2 minutes to read
7 Note
Event attributes in native C++ are incompatible with Standard C++. They don't
compile when you specify /permissive- conformance mode.
Syntax
__raise method-declarator ;
Remarks
From managed code, an event can only be raised from within the class where it's
defined. For more information, see event.
7 Note
Example
C++
// EventHandlingRef_raise.cpp
struct E {
__event void func1();
void func1(int) {}
void func2() {}
void b() {
__raise func1();
__raise func1(1); // C3745: 'int Event::bar(int)':
// only an event can be 'raised'
__raise func2(); // C3745
}
};
int main() {
E e;
__raise e.func1();
__raise e.func1(1); // C3745
__raise e.func2(); // C3745
}
See also
Keywords
Event handling
__event
__hook
__unhook
Component extensions for .NET and UWP
__unhook keyword
Article • 08/03/2021 • 2 minutes to read
7 Note
Event attributes in native C++ are incompatible with Standard C++. They don't
compile when you specify /permissive- conformance mode.
Syntax
C++
long __unhook(
&SourceClass::EventMethod,
source,
&ReceiverClass::HandlerMethod
[, receiver = this]
);
long __unhook(
interface,
source
);
long __unhook(
source
);
Parameters
&SourceClass::EventMethod
A pointer to the event method from which you unhook the event handler method:
Native C++ events: SourceClass is the event source class and EventMethod is the
event.
COM events: SourceClass is the event source interface and EventMethod is one of
its methods.
Managed events: SourceClass is the event source class and EventMethod is the
event.
interface
The interface name being unhooked from receiver, only for COM event receivers in
which the layout_dependent parameter of the event_receiver attribute is true .
source
A pointer to an instance of the event source. Depending on the code type specified in
event_receiver , source can be one of these types:
Native C++ events: ReceiverClass is the event receiver class and HandlerMethod is
the handler.
receiver (optional) A pointer to an instance of the event receiver class. If you don't
specify a receiver, the default is the receiver class or structure in which __unhook is
called.
Usage
Can be use in any function scope, including main , outside the event receiver class.
Remarks
Use the intrinsic function __unhook in an event receiver to disassociate or "unhook" a
handler method from an event method.
There are three forms of __unhook . You can use the first (four-argument) form in most
cases. You can use the second (two-argument) form of __unhook only for a COM event
receiver; it unhooks the entire event interface. You can use the third (one-argument)
form to unhook all delegates from the specified source.
A nonzero return value indicates that an error has occurred (managed events will throw
an exception).
If you call __unhook on an event and event handler that aren't already hooked, it will
have no effect.
At compile time, the compiler verifies that the event exists and does parameter type
checking with the specified handler.
You can call __hook and __unhook outside the event receiver, except for COM events.
For information on coding managed events in the new syntax, see event.
7 Note
Example
See Event Handling in Native C++ and Event Handling in COM for samples.
See also
Keywords
event_source
event_receiver
__event
__hook
__raise
Event handling in native C++
Article • 08/03/2021 • 2 minutes to read
In native C++ event handling, you set up an event source and event receiver using the
event_source and event_receiver attributes, respectively, specifying type = native . These
attributes allow the classes they're applied on to fire events and handle events in a
native, non-COM context.
7 Note
Event attributes in native C++ are incompatible with Standard C++. They don't
compile when you specify /permissive- conformance mode.
Declaring events
In an event source class, use the __event keyword on a method declaration to declare
the method as an event. Make sure to declare the method, but don't define it. If you do,
it generates a compiler error, because the compiler defines the method implicitly when
it's made into an event. Native events can be methods with zero or more parameters.
The return type can be void or any integral type.
Firing events
To fire an event, call the method declared as an event in the event source class. If
handlers have been hooked to the event, the handlers will be called.
Native C++ event code
The following example shows how to fire an event in native C++. To compile and run the
example, refer to the comments in the code. To build the code in the Visual Studio IDE,
verify that the /permissive- option is turned off.
Example
Code
C++
// evh_native.cpp
// compile by using: cl /EHsc /W3 evh_native.cpp
#include <stdio.h>
[event_source(native)]
class CSource {
public:
__event void MyEvent(int nValue);
};
[event_receiver(native)]
class CReceiver {
public:
void MyHandler1(int nValue) {
printf_s("MyHandler1 was called with value %d.\n", nValue);
}
int main() {
CSource source;
CReceiver receiver;
receiver.hookEvent(&source);
__raise source.MyEvent(123);
receiver.unhookEvent(&source);
}
Output
Output
See also
Event handling
Event handling in COM
Article • 08/03/2021 • 4 minutes to read
In COM event handling, you set up an event source and event receiver using the
event_source and event_receiver attributes, respectively, specifying type = com . These
attributes inject appropriate code for custom, dispatch, and dual interfaces. The injected
code allows the attributed classes to fire events and handle events through COM
connection points.
7 Note
Event attributes in native C++ are incompatible with Standard C++. They don't
compile when you specify /permissive- conformance mode.
Declaring events
In an event source class, use the __event keyword on an interface declaration to declare
that interface's methods as events. The events of that interface are fired when you call
them as interface methods. Methods on event interfaces can have zero or more
parameters (which should all be in parameters). The return type can be void or any
integral type.
7 Note
Typically, there are two techniques to allow a COM event receiver to access event
source interface definitions. The first, as shown below, is to share a common header
file. The second is to use #import with the embedded_idl import qualifier, so that
the event source type library is written to the .tlh file with the attribute-generated
code preserved.
Firing events
To fire an event, call a method in the interface declared with the __event keyword in the
event source class. If handlers have been hooked to the event, the handlers will be
called.
C++
// evh_server.h
#pragma once
[ dual, uuid("00000000-0000-0000-0000-000000000001") ]
__interface IEvents {
[id(1)] HRESULT MyEvent([in] int value);
};
[ dual, uuid("00000000-0000-0000-0000-000000000002") ]
__interface IEventSource {
[id(1)] HRESULT FireEvent();
};
C++
// evh_server.cpp
// compile with: /LD
// post-build command: Regsvr32.exe /s evh_server.dll
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
#include "evh_server.h"
[ module(dll, name="EventSource", uuid="6E46B59E-89C3-4c15-A6D8-
B8A1CEC98830") ];
HRESULT FireEvent() {
__raise MyEvent(123);
return S_OK;
}
};
C++
// evh_client.cpp
// compile with: /link /OPT:NOREF
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
#include <stdio.h>
#include "evh_server.h"
[ module(name="EventReceiver") ];
[ event_receiver(com) ]
class CReceiver {
public:
HRESULT MyHandler1(int nValue) {
printf_s("MyHandler1 was called with value %d.\n", nValue);
return S_OK;
}
int main() {
// Create COM object
CoInitialize(NULL);
{
IEventSource* pSource = 0;
HRESULT hr = CoCreateInstance(__uuidof(CSource), NULL,
CLSCTX_ALL, __uuidof(IEventSource), (void **) &pSource);
if (FAILED(hr)) {
return -1;
}
Output
Output
However, in COM event handling, when you set the layout_dependent parameter of
event_receiver to true , the name and signature matching is enforced. The names and
signatures of the handlers in the event receiver and in the hooked events must exactly
match.
When layout_dependent is set to false , the calling convention and storage class (virtual,
static, and so on) can be mixed and matched between the firing event method and the
hooking methods (its delegates). It's slightly more efficient to have
layout_dependent = true .
C++
[coclass, event_source(com)]
class CSource : public IEventSource {
public:
__event __interface IEvents;
HRESULT FireEvent() {
MyEvent1(123);
MyEvent2(123);
return S_OK;
}
};
Then, in the event receiver, any handler hooked to a method in IEventSource must
match its name and signature, as follows:
C++
See also
Event handling
Microsoft-specific modifiers
Article • 08/03/2021 • 2 minutes to read
Based addressing, the practice of using a pointer as a base from which other
pointers can be offset
Microsoft-specific keywords
Many of the Microsoft-specific keywords can be used to modify declarators to form
derived types. For more information about declarators, see Declarators.
__based The name that follows declares a 32-bit offset to the 32-bit base Yes
contained in the declaration.
__cdecl The name that follows uses the C naming and calling conventions. Yes
__fastcall The name that follows declares a function that uses registers, when Yes
available, instead of the stack for argument passing.
__stdcall The name that follows specifies a function that observes the Yes
standard calling convention.
__vectorcall The name that follows declares a function that uses registers, Yes
including SSE registers, when available, instead of the stack for
argument passing.
See also
C++ Language Reference
Based Addressing
Article • 08/03/2021 • 2 minutes to read
__based Grammar
Based Pointers
See also
Microsoft-Specific Modifiers
__based Grammar
Article • 01/25/2023 • 2 minutes to read
Microsoft Specific
Based addressing is useful when you need precise control over the segment in which
objects are allocated (static and dynamic based data).
The only form of based addressing acceptable in 32-bit and 64-bit compilations is
"based on a pointer" that defines a type that contains a 32-bit or 64-bit displacement to
a 32-bit or 64-bit base or based on void .
Grammar
based-range-modifier :
__based( base-expression )
base-expression :
based-variable :
identifier
based-abstract-declarator :
abstract-declarator
base-type :
type-name
See also
Based Pointers
Based Pointers (C++)
Article • 08/03/2021 • 2 minutes to read
The __based keyword allows you to declare pointers based on pointers (pointers that
are offsets from existing pointers). The __based keyword is Microsoft-specific.
Syntax
Remarks
Pointers based on pointer addresses are the only form of the __based keyword valid in
32-bit or 64-bit compilations. For the Microsoft 32-bit C/C++ compiler, a based pointer
is a 32-bit offset from a 32-bit pointer base. A similar restriction holds for 64-bit
environments, where a based pointer is a 64-bit offset from the 64-bit base.
One use for pointers based on pointers is for persistent identifiers that contain pointers.
A linked list that consists of pointers based on a pointer can be saved to disk, then
reloaded to another place in memory, with the pointers remaining valid. For example:
C++
// based_pointers1.cpp
// compile with: /c
void *vpBuffer;
struct llist_t {
void __based( vpBuffer ) *vpData;
struct llist_t __based( vpBuffer ) *llNext;
};
The pointer vpBuffer is assigned the address of memory allocated at some later point in
the program. The linked list is relocated relative to the value of vpBuffer .
7 Note
For compatibility with previous versions, _based is a synonym for __based unless
compiler option /Za (Disable language extensions) is specified.
Example
The following code demonstrates changing a based pointer by changing its base.
C++
// based_pointers2.cpp
// compile with: /EHsc
#include <iostream>
pBased = &a2[0];
Output
1
2
10
11
See also
Keywords
alloc_text
Calling Conventions
Article • 08/03/2021 • 2 minutes to read
The Visual C/C++ compiler provides several different conventions for calling internal
and external functions. Understanding these different approaches can help you debug
your program and link your code with assembly-language routines.
The topics on this subject explain the differences between the calling conventions, how
arguments are passed, and how values are returned by functions. They also discuss
naked function calls, an advanced feature that enables you to write your own prolog and
epilog code.
For information on calling conventions for x64 processors, see Calling Convention.
See also
Microsoft-Specific Modifiers
Argument Passing and Naming
Conventions
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The Microsoft C++ compilers allow you to specify conventions for passing arguments
and return values between functions and callers. Not all conventions are available on all
supported platforms, and some conventions use platform-specific implementations. In
most cases, keywords or compiler switches that specify an unsupported convention on a
particular platform are ignored, and the platform default convention is used.
On x86 platforms, all arguments are widened to 32 bits when they are passed. Return
values are also widened to 32 bits and returned in the EAX register, except for 8-byte
structures, which are returned in the EDX:EAX register pair. Larger structures are
returned in the EAX register as pointers to hidden return structures. Parameters are
pushed onto the stack from right to left. Structures that are not PODs will not be
returned in registers.
The compiler generates prolog and epilog code to save and restore the ESI, EDI, EBX,
and EBP registers, if they are used in the function.
7 Note
When a struct, union, or class is returned from a function by value, all definitions of
the type need to be the same, else the program may fail at runtime.
For information on how to define your own function prolog and epilog code, see Naked
Function Calls.
For information about the default calling conventions in code that targets x64 platforms,
see x64 Calling Convention. For information about calling convention issues in code that
targets ARM platforms, see Common Visual C++ ARM Migration Issues.
The following calling conventions are supported by the Visual C/C++ compiler.
__cdecl Caller Pushes parameters on the stack, in reverse order (right to left)
__clrcall n/a Load parameters onto CLR expression stack in order (left to right).
Keyword Stack Parameter passing
cleanup
__stdcall Callee Pushes parameters on the stack, in reverse order (right to left)
__vectorcall Callee Stored in registers, then pushed on stack in reverse order (right to
left)
See also
Calling Conventions
__cdecl
Article • 08/03/2021 • 2 minutes to read
__cdecl is the default calling convention for C and C++ programs. Because the stack is
cleaned up by the caller, it can do vararg functions. The __cdecl calling convention
creates larger executables than __stdcall, because it requires each function call to include
stack cleanup code. The following list shows the implementation of this calling
convention. The __cdecl modifier is Microsoft-specific.
Element Implementation
7 Note
Place the __cdecl modifier before a variable or a function name. Because the C naming
and calling conventions are the default, the only time you must use __cdecl in x86 code
is when you have specified the /Gv (vectorcall), /Gz (stdcall), or /Gr (fastcall) compiler
option. The /Gd compiler option forces the __cdecl calling convention.
On ARM and x64 processors, __cdecl is accepted but typically ignored by the compiler.
By convention on ARM and x64, arguments are passed in registers when possible, and
subsequent arguments are passed on the stack. In x64 code, use __cdecl to override the
/Gv compiler option and use the default x64 calling convention.
For non-static class functions, if the function is defined out-of-line, the calling
convention modifier does not have to be specified on the out-of-line definition. That is,
for class non-static member methods, the calling convention specified during
declaration is assumed at the point of definition. Given this class definition:
C++
struct CMyClass {
void __cdecl mymethod();
};
this:
C++
is equivalent to this:
C++
For compatibility with previous versions, cdecl and _cdecl are a synonym for __cdecl
unless compiler option /Za (Disable language extensions) is specified.
Example
In the following example, the compiler is instructed to use C naming and calling
conventions for the system function.
C++
See also
Argument Passing and Naming Conventions
Keywords
__clrcall
Article • 08/03/2021 • 3 minutes to read
Specifies that a function can only be called from managed code. Use __clrcall for all
virtual functions that will only be called from managed code. However this calling
convention cannot be used for functions that will be called from native code. The
__clrcall modifier is Microsoft-specific.
Use __clrcall to improve performance when calling from a managed function to a virtual
managed function or from managed function to managed function through pointer.
Entry points are separate, compiler-generated functions. If a function has both native
and managed entry points, one of them will be the actual function with the function
implementation. The other function will be a separate function (a thunk) that calls into
the actual function and lets the common language runtime perform PInvoke. When
marking a function as __clrcall, you indicate the function implementation must be MSIL
and that the native entry point function will not be generated.
When taking the address of a native function if __clrcall is not specified, the compiler
uses the native entry point. __clrcall indicates that the function is managed and there is
no need to go through the transition from managed to native. In that case the compiler
uses the managed entry point.
When /clr (not /clr:pure or /clr:safe ) is used and __clrcall is not used, taking the
address of a function always returns the address of the native entry point function.
When __clrcall is used, the native entry point function is not created, so you get the
address of the managed function, not an entry point thunk function. For more
information, see Double Thunking. The /clr:pure and /clr:safe compiler options are
deprecated in Visual Studio 2015 and unsupported in Visual Studio 2017.
/clr (Common Language Runtime Compilation) implies that all functions and function
pointers are __clrcall and the compiler will not permit a function inside the compiland to
be marked anything other than __clrcall. When /clr:pure is used, __clrcall can only be
specified on function pointers and external declarations.
You can directly call __clrcall functions from existing C++ code that was compiled by
using /clr as long as that function has an MSIL implementation. __clrcall functions
cannot be called directly from functions that have inline asm and call CPU-specific
intrinisics, for example, even if those functions are compiled with /clr .
__clrcall function pointers are only meant to be used in the application domain in which
they were created. Instead of passing __clrcall function pointers across application
domains, use CrossAppDomainDelegate. For more information, see Application
Domains and Visual C++.
Examples
Note that when a function is declared with __clrcall, code will be generated when
needed; for example, when function is called.
C++
// clrcall2.cpp
// compile with: /clr
using namespace System;
int __clrcall Func1() {
Console::WriteLine("in Func1");
return 0;
}
// Func1 hasn't been used at this point (code has not been generated),
// so runtime returns the adddress of a stub to the function
int (__clrcall *pf)() = &Func1;
int main() {
if (&Func1 == pf)
Console::WriteLine("&Func1 == pf, comparison succeeds");
else
Console::WriteLine("&Func1 != pf, comparison fails");
// even though comparison fails, stub and function call are correct
pf();
Func1();
}
Output
in Func1
&Func1 != pf, comparison fails
in Func1
in Func1
The following sample shows that you can define a function pointer, such that, you
declare that the function pointer will only be invoked from managed code. This allows
the compiler to directly call the managed function and avoid the native entry point
(double thunk issue).
C++
// clrcall3.cpp
// compile with: /clr
void Test() {
System::Console::WriteLine("in Test");
}
int main() {
void (*pTest)() = &Test;
(*pTest)();
See also
Argument Passing and Naming Conventions
Keywords
__stdcall
Article • 08/03/2021 • 2 minutes to read
The __stdcall calling convention is used to call Win32 API functions. The callee cleans
the stack, so the compiler makes vararg functions __cdecl . Functions that use this
calling convention require a function prototype. The __stdcall modifier is Microsoft-
specific.
Syntax
return-type __stdcall function-name[ ( argument-list ) ]
Remarks
The following list shows the implementation of this calling convention.
Element Implementation
Stack- Called function pops its own arguments from the stack.
maintenance
responsibility
Name- An underscore ( _ ) is prefixed to the name. The name is followed by the at sign
decoration ( @ ) followed by the number of bytes (in decimal) in the argument list. Therefore,
convention the function declared as int func( int a, double b ) is decorated as follows:
_func@12
Case- None
translation
convention
The /Gz compiler option specifies __stdcall for all functions not explicitly declared with
a different calling convention.
For compatibility with previous versions, _stdcall is a synonym for __stdcall unless
compiler option /Za (Disable language extensions) is specified.
Functions declared using the __stdcall modifier return values the same way as
functions declared using __cdecl.
On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; on
ARM and x64 architectures, by convention, arguments are passed in registers when
possible, and subsequent arguments are passed on the stack.
For non-static class functions, if the function is defined out-of-line, the calling
convention modifier does not have to be specified on the out-of-line definition. That is,
for class non-static member methods, the calling convention specified during
declaration is assumed at the point of definition. Given this class definition,
C++
struct CMyClass {
void __stdcall mymethod();
};
this
C++
is equivalent to this
C++
Example
In the following example, use of __stdcall results in all WINAPI function types being
handled as a standard call:
C++
See also
Argument Passing and Naming Conventions
Keywords
__fastcall
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Element Implementation
Argument- The first two DWORD or smaller arguments that are found in the argument list
passing from left to right are passed in ECX and EDX registers; all other arguments are
order passed on the stack from right to left.
Name- At sign (@) is prefixed to names; an at sign followed by the number of bytes (in
decoration decimal) in the parameter list is suffixed to names.
convention
7 Note
Using the /Gr compiler option causes each function in the module to compile as
__fastcall unless the function is declared by using a conflicting attribute, or the name
of the function is main .
The __fastcall keyword is accepted and ignored by the compilers that target ARM and
x64 architectures; on an x64 chip, by convention, the first four arguments are passed in
registers when possible, and additional arguments are passed on the stack. For more
information, see x64 Calling Convention. On an ARM chip, up to four integer arguments
and eight floating-point arguments may be passed in registers, and additional
arguments are passed on the stack.
For non-static class functions, if the function is defined out-of-line, the calling
convention modifier does not have to be specified on the out-of-line definition. That is,
for class non-static member methods, the calling convention specified during
declaration is assumed at the point of definition. Given this class definition:
C++
struct CMyClass {
void __fastcall mymethod();
};
this:
C++
is equivalent to this:
C++
For compatibility with previous versions, _fastcall is a synonym for __fastcall unless
compiler option /Za (Disable language extensions) is specified.
Example
In the following example, the function DeleteAggrWrapper is passed arguments in
registers:
C++
Under __thiscall , the callee cleans the stack, which is impossible for vararg functions.
Arguments are pushed on the stack from right to left. The this pointer is passed via
register ECX, and not on the stack.
On ARM, ARM64, and x64 machines, __thiscall is accepted and ignored by the
compiler. That's because they use a register-based calling convention by default.
One reason to use __thiscall is in classes whose member functions use __clrcall by
default. In that case, you can use __thiscall to make individual member functions
callable from native code.
When compiling with /clr:pure, all functions and function pointers are __clrcall unless
specified otherwise. The /clr:pure and /clr:safe compiler options are deprecated in
Visual Studio 2015 and unsupported in Visual Studio 2017.
vararg member functions use the __cdecl calling convention. All function arguments
are pushed on the stack, with the this pointer placed on the stack last.
Because this calling convention applies only to C++, it doesn't have a C name
decoration scheme.
When you define a non-static class member function out-of-line, specify the calling
convention modifier only in the declaration. You don't have to specify it again on the
out-of-line definition. The compiler uses the calling convention specified during
declaration at the point of definition.
See also
Argument passing and naming conventions
__vectorcall
Article • 10/17/2022 • 12 minutes to read
Microsoft Specific
Element Implementation
C name- Function names are suffixed with two "at" signs (@@) followed by the
decoration number of bytes (in decimal) in the parameter list.
convention
Using the /Gv compiler option causes each function in the module to compile as
__vectorcall unless the function is a member function, is declared with a conflicting
calling convention attribute, uses a vararg variable argument list, or has the name main .
You can pass three kinds of arguments by register in __vectorcall functions: integer
type values, vector type values, and homogeneous vector aggregate (HVA) values.
An integer type satisfies two requirements: it fits in the native register size of the
processor—for example, 4 bytes on an x86 machine or 8 bytes on an x64 machine—and
it's convertible to an integer of register length and back again without changing its bit
representation. For example, any type that can be promoted to int on x86 ( long long
on x64)—for example, a char or short —or that can be cast to int ( long long on x64)
and back to its original type without change is an integer type. Integer types include
pointer, reference, and struct or union types of 4 bytes (8 bytes on x64) or less. On x64
platforms, larger struct and union types are passed by reference to memory allocated
by the caller; on x86 platforms, they are passed by value on the stack.
A vector type is either a floating-point type—for example, a float or double —or an
SIMD vector type—for example, __m128 or __m256 .
An HVA type is a composite type of up to four data members that have identical vector
types. An HVA type has the same alignment requirement as the vector type of its
members. This is an example of an HVA struct definition that contains three identical
vector types and has 32-byte alignment:
C++
typedef struct {
__m256 x;
__m256 y;
__m256 z;
} hva3; // 3 element HVA type on __m256
Declare your functions explicitly with the __vectorcall keyword in header files to allow
separately compiled code to link without errors. Functions must be prototyped to use
__vectorcall , and can't use a vararg variable length argument list.
A member function may be declared by using the __vectorcall specifier. The hidden
this pointer is passed by register as the first integer type argument.
For non-static class member functions, if the function is defined out-of-line, the calling
convention modifier does not have to be specified on the out-of-line definition. That is,
for class non-static members, the calling convention specified during declaration is
assumed at the point of definition. Given this class definition:
C++
struct MyClass {
void __vectorcall mymethod();
};
this:
C++
is equivalent to this:
C++
C++
When any of the first four arguments in order from left to right are integer type
arguments, they are passed in the register that corresponds to that position—RCX, RDX,
R8, or R9. A hidden this pointer is treated as the first integer type argument. When an
HVA argument in one of the first four arguments can't be passed in the available
registers, a reference to caller-allocated memory is passed in the corresponding integer
type register instead. Integer type arguments after the fourth parameter position are
passed on the stack.
When any of the first six arguments in order from left to right are vector type
arguments, they are passed by value in SSE vector registers 0 to 5 according to
argument position. Floating-point and __m128 types are passed in XMM registers, and
__m256 types are passed in YMM registers. This differs from the standard x64 calling
convention, because the vector types are passed by value instead of by reference, and
additional registers are used. The shadow stack space allocated for vector type
arguments is fixed at 8 bytes, and the /homeparams option does not apply. Vector type
arguments in the seventh and later parameter positions are passed on the stack by
reference to memory allocated by the caller.
After registers are allocated for vector arguments, the data members of HVA arguments
are allocated, in ascending order, to unused vector registers XMM0 to XMM5 (or YMM0
to YMM5, for __m256 types), as long as there are enough registers available for the
entire HVA. If not enough registers are available, the HVA argument is passed by
reference to memory allocated by the caller. The stack shadow space for an HVA
argument is fixed at 8 bytes with undefined content. HVA arguments are assigned to
registers in order from left to right in the parameter list, and may be in any position.
HVA arguments in one of the first four argument positions that are not assigned to
vector registers are passed by reference in the integer register that corresponds to that
position. HVA arguments passed by reference after the fourth parameter position are
pushed on the stack.
The stack is maintained by the caller in the x64 implementation of __vectorcall . The
caller prolog and epilog code allocates and clears the stack for the called function.
Arguments are pushed on the stack from right to left, and shadow stack space is
allocated for arguments passed in registers.
Examples:
C++
// crt_vc64.c
// Build for amd64 with: cl /arch:AVX /W3 /FAs crt_vc64.c
// This example creates an annotated assembly listing in
// crt_vc64.asm.
#include <intrin.h>
#include <xmmintrin.h>
typedef struct {
__m128 array[2];
} hva2; // 2 element HVA type on __m128
typedef struct {
__m256 array[4];
} hva4; // 4 element HVA type on __m256
a = b = d = _mm_set1_ps(3.0f);
c = e = _mm256_set1_ps(5.0f);
h2.array[0] = _mm_set1_ps(6.0f);
h4.array[0] = _mm256_set1_ps(7.0f);
b = example1(a, b, c, d, e);
e = example2(1, b, 3, d, e, 6.0f, 7);
d = example3(1, h2, 3, 4, 5);
f = example4(1, 2.0f, h4, d, 5);
i = example5(1, h2, 3, h4, 5);
h4 = example6(h2, h4, c, h2);
}
The first two integer type arguments found in the parameter list from left to right are
placed in ECX and EDX, respectively. A hidden this pointer is treated as the first integer
type argument, and is passed in ECX. The first six vector type arguments are passed by
value through SSE vector registers 0 to 5, in the XMM or YMM registers, depending on
argument size.
The first six vector type arguments in order from left to right are passed by value in SSE
vector registers 0 to 5. Floating-point and __m128 types are passed in XMM registers,
and __m256 types are passed in YMM registers. No shadow stack space is allocated for
vector type arguments passed by register. The seventh and subsequent vector type
arguments are passed on the stack by reference to memory allocated by the caller. The
limitation of compiler error C2719 does not apply to these arguments.
After registers are allocated for vector arguments, the data members of HVA arguments
are allocated in ascending order to unused vector registers XMM0 to XMM5 (or YMM0
to YMM5, for __m256 types), as long as there are enough registers available for the
entire HVA. If not enough registers are available, the HVA argument is passed on the
stack by reference to memory allocated by the caller. No stack shadow space for an HVA
argument is allocated. HVA arguments are assigned to registers in order from left to
right in the parameter list, and may be in any position.
Results of __vectorcall functions are returned by value in registers when possible.
Results of integer type, including structs or unions of 4 bytes or less, are returned by
value in EAX. Integer type structs or unions of 8 bytes or less are returned by value in
EDX:EAX. Vector type results are returned by value in XMM0 or YMM0, depending on
size. HVA results have each data element returned by value in registers XMM0:XMM3 or
YMM0:YMM3, depending on element size. Other result types are returned by reference
to memory allocated by the caller.
Examples:
C++
// crt_vc86.c
// Build for x86 with: cl /arch:AVX /W3 /FAs crt_vc86.c
// This example creates an annotated assembly listing in
// crt_vc86.asm.
#include <intrin.h>
#include <xmmintrin.h>
typedef struct {
__m128 array[2];
} hva2; // 2 element HVA type on __m128
typedef struct {
__m256 array[4];
} hva4; // 4 element HVA type on __m256
a = b = d = _mm_set1_ps(3.0f);
c = e = _mm256_set1_ps(5.0f);
h2.array[0] = _mm_set1_ps(6.0f);
h4.array[0] = _mm256_set1_ps(7.0f);
b = example1(a, b, c, d, e);
e = example2(1, b, 3, d, e, 6.0f, 7);
d = example3(1, h2, 3, 4, 5);
f = example4(1, 2.0f, h4, d, 5);
i = example5(1, h2, 3, h4, 5);
h4 = example6(h2, h4, c, h2);
}
End Microsoft Specific
See also
Argument Passing and Naming Conventions
Keywords
Calling Example: Function Prototype
and Call
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The following example shows the results of making a function call using various calling
conventions.
This example is based on the following function skeleton. Replace calltype with the
appropriate calling convention.
C++
See also
Calling Conventions
Results of Calling Example
Article • 11/12/2021 • 2 minutes to read
Microsoft Specific
__cdecl
The C decorated function name is _MyFunc .
__fastcall
The C decorated name ( __fastcall ) is @MyFunc@20 . The C++ decorated name is
implementation-specific.
See also
Calling Example: Function Prototype and Call
Naked Function Calls
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Functions declared with the naked attribute are emitted without prolog or epilog code,
enabling you to write your own custom prolog/epilog sequences using the inline
assembler. Naked functions are provided as an advanced feature. They enable you to
declare a function that is being called from a context other than C/C++, and thus make
different assumptions about where parameters are, or which registers are preserved.
Examples include routines such as interrupt handlers. This feature is particularly useful
for writers of virtual device drivers (VxDs).
See also
Calling Conventions
Rules and Limitations for Naked
Functions
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Structured Exception Handling and C++ Exception Handling constructs are not
permitted because they must unwind across the stack frame.
To ensure that no initialization code for local variables appears before the prolog
sequence, initialized local variables are not permitted at function scope. In
particular, the declaration of C++ objects is not permitted at function scope. There
may, however, be initialized data in a nested scope.
Frame pointer optimization (the /Oy compiler option) is not recommended, but it
is automatically suppressed for a naked function.
You cannot declare C++ class objects at the function lexical scope. You can,
however, declare objects in a nested block.
For __fastcall naked functions, whenever there is a reference in C/C++ code to one
of the register arguments, the prolog code should store the values of that register
into the stack location for that variable. For example:
C++
// nkdfastcl.cpp
// compile with: /c
// processor: x86
__declspec(naked) int __fastcall power(int i, int j) {
// calculates i^j, assumes that j >= 0
// prolog
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
// store ECX and EDX into stack locations allocated for i and j
mov i, ecx
mov j, edx
}
{
int k = 1; // return value
while (j-- > 0)
k *= i;
__asm {
mov eax, k
};
}
// epilog
__asm {
mov esp, ebp
pop ebp
ret
}
}
See also
Naked Function Calls
Considerations for Writing
Prolog/Epilog Code
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Before writing your own prolog and epilog code sequences, it is important to
understand how the stack frame is laid out. It is also useful to know how to use the
__LOCAL_SIZE symbol.
The localbytes variable represents the number of bytes needed on the stack for local
variables, and the <registers> variable is a placeholder that represents the list of
registers to be saved on the stack. After pushing the registers, you can place any other
appropriate data on the stack. The following is the corresponding epilog code:
The stack always grows down (from high to low memory addresses). The base pointer
( ebp ) points to the pushed value of ebp . The locals area begins at ebp-4 . To access local
variables, calculate an offset from ebp by subtracting the appropriate value from ebp .
__LOCAL_SIZE
The compiler provides a symbol, __LOCAL_SIZE , for use in the inline assembler block of
function prolog code. This symbol is used to allocate space for local variables on the
stack frame in custom prolog code.
The compiler determines the value of __LOCAL_SIZE . Its value is the total number of
bytes of all user-defined local variables and compiler-generated temporary variables.
__LOCAL_SIZE can be used only as an immediate operand; it cannot be used in an
expression. You must not change or redefine the value of this symbol. For example:
The following example of a naked function containing custom prolog and epilog
sequences uses the __LOCAL_SIZE symbol in the prolog sequence:
C++
// the__local_size_symbol.cpp
// processor: x86
__declspec ( naked ) int main() {
int i;
int j;
__asm { /* prolog */
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
/* Function body */
__asm { /* epilog */
mov esp, ebp
pop ebp
ret
}
}
See also
Naked Function Calls
Floating Point Coprocessor and Calling
Conventions
Article • 08/03/2021 • 2 minutes to read
If you are writing assembly routines for the floating point coprocessor, you must
preserve the floating point control word and clean the coprocessor stack unless you are
returning a float or double value (which your function should return in ST(0)).
See also
Calling Conventions
Obsolete Calling Conventions
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The __pascal, __fortran, and __syscall calling conventions are no longer supported. You
can emulate their functionality by using one of the supported calling conventions and
appropriate linker options.
<windows.h> now supports the WINAPI macro, which translates to the appropriate
calling convention for the target. Use WINAPI where you previously used PASCAL or
__far __pascal.
See also
Argument Passing and Naming Conventions
restrict (C++ AMP)
Article • 08/03/2021 • 2 minutes to read
The restriction specifier can be applied to function and lambda declarations. It enforces
restrictions on the code in the function and on the behavior of the function in
applications that use the C++ Accelerated Massive Parallelism (C++ AMP) runtime.
7 Note
For information about the restrict keyword that is part of the __declspec
storage-class attributes, see restrict.
Clause Description
restrict(cpu) The function can use the full C++ language. Only other functions that are
declared by using restrict(cpu) functions can call the function.
restrict(amp) The function can only use the subset of the C++ language that C++ AMP can
accelerate.
A sequence of The function must adhere to the limitations of both restrict(cpu) and
restrict(cpu) restrict(amp) . The function can be called by functions that are declared by
and using restrict(cpu) , restrict(amp) , restrict(cpu, amp) , or restrict(amp,
restrict(amp) . cpu) .
Remarks
The restrict keyword is a contextual keyword. The restriction specifiers, cpu and amp
are not reserved words. The list of specifiers is not extensible. A function that does not
have a restrict clause is the same as a function that has the restrict(cpu) clause.
A function that has the restrict(amp) clause has the following limitations:
The function can call only functions that have the restrict(amp) clause.
Recursion.
Virtual functions.
Pointers to functions.
Pointers in structures.
Pointers to pointers.
goto statements.
Labeled statements.
Global variables.
dynamic_cast casts.
asm declarations.
Varargs.
Example
The following example shows how to use the restrict(amp) clause.
C++
See also
C++ AMP (C++ Accelerated Massive Parallelism)
tile_static Keyword
Article • 08/03/2021 • 3 minutes to read
The tile_static keyword is used to declare a variable that can be accessed by all threads
in a tile of threads. The lifetime of the variable starts when execution reaches the point
of declaration and ends when the kernel function returns. For more information on
using tiles, see Using Tiles.
It can be used only on variables that are in a function that has the restrict(amp)
modifier.
Example
The following example shows how a tile_static variable can be used to accumulate data
across several threads in a tile.
C++
// Sample data:
int sampledata[] = {
2, 2, 9, 7, 1, 4,
4, 4, 8, 8, 3, 4,
1, 5, 1, 2, 5, 2,
6, 8, 3, 2, 7, 2};
// The tiles:
// 2 2 9 7 1 4
// 4 4 8 8 3 4
//
// 1 5 1 2 5 2
// 6 8 3 2 7 2
// Averages:
int averagedata[] = {
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
};
parallel_for_each(
// Create threads for sample.extent and divide the extent into 2 x 2
tiles.
sample.extent.tile<2,2>(),
[=](tiled_index<2,2> idx) restrict(amp)
{
// Create a 2 x 2 array to hold the values in this tile.
tile_static int nums[2][2];
// Copy the values for the tile into the 2 x 2 array.
nums[idx.local[1]][idx.local[0]] = sample[idx.global];
// When all the threads have executed and the 2 x 2 array is
complete, find the average.
idx.barrier.wait();
int sum = nums[0][0] + nums[0][1] + nums[1][0] + nums[1][1];
// Copy the average into the array_view.
average[idx.global] = sum / 4;
}
);
// Output:
// 3 3 8 8 3 3
// 3 3 8 8 3 3
// 5 5 2 2 4 4
// 5 5 2 2 4 4
// Sample data.
int sampledata[] = {
2, 2, 9, 7, 1, 4,
4, 4, 8, 8, 3, 4,
1, 5, 1, 2, 5, 2,
6, 8, 3, 2, 7, 2};
parallel_for_each(
// Create threads for sample.grid and divide the grid into 2 x 2 tiles.
sample.extent.tile<2,2>(),
[=](tiled_index<2,2> idx) restrict(amp)
{
// Create a 2 x 2 array to hold the values in this tile.
tile_static int nums[2][2];
// Copy the values for the tile into the 2 x 2 array.
nums[idx.local[1]][idx.local[0]] = sample[idx.global];
// When all the threads have executed and the 2 x 2 array is
complete, find the average.
idx.barrier.wait();
int sum = nums[0][0] + nums[0][1] + nums[1][0] + nums[1][1];
// Copy the average into the array_view.
average[idx.global] = sum / 4;
}
);
// Output.
// 3 3 8 8 3 3
// 3 3 8 8 3 3
// 5 5 2 2 4 4
// 5 5 2 2 4 4
See also
Microsoft-Specific Modifiers
C++ AMP Overview
parallel_for_each Function (C++ AMP)
Walkthrough: Matrix Multiplication
__declspec
Article • 03/02/2022 • 2 minutes to read
Microsoft Specific
The extended attribute syntax for specifying storage-class information uses the
__declspec keyword, which specifies that an instance of a given type is to be stored with
Grammar
decl-specifier :
__declspec ( extended-decl-modifier-seq )
extended-decl-modifier-seq :
extended-decl-modifier opt
extended-decl-modifier extended-decl-modifier-seq
extended-decl-modifier :
align( number )
allocate(" segname ")
allocator
appdomain
code_seg(" segname ")
deprecated
dllimport
dllexport
empty_bases
jitintrinsic
naked
noalias
noinline
noreturn
nothrow
novtable
no_sanitize_address
process
safebuffers
selectany
spectre(nomitigation)
thread
uuid(" ComObjectGUID ")
White space separates the declaration modifier sequence. Examples appear in later
sections.
functions, data, and objects. The property , selectany , and uuid attributes affect COM
objects.
For compatibility with previous versions, _declspec is a synonym for __declspec unless
compiler option /Za (Disable language extensions) is specified.
C++
C++
The general guideline for using the __declspec attribute for simple declarations is as
follows:
decl-specifier-seq init-declarator-list ;
The decl-specifier-seq should contain, among other things, a base type (for example,
int , float , a typedef , or a class name), a storage class (for example, static , extern ),
C++
The following code declares an integer thread local variable and initializes it with a
value:
C++
See also
Keywords
C extended storage-class attributes
align (C++)
Article • 04/22/2022 • 7 minutes to read
In Visual Studio 2015 and later, use the C++11 standard alignas specifier to control
alignment. For more information, see Alignment.
Microsoft Specific
Syntax
__declspec( align( # ) ) declarator
Remarks
Writing applications that use the latest processor instructions introduces some new
constraints and issues. Many new instructions require data that's aligned to 16-byte
boundaries. Aligning frequently used data to the processor's cache line size improves
cache performance. For example, if you define a structure whose size is less than 32
bytes, you may want 32-byte alignment to make sure that objects of that structure type
are efficiently cached.
# is the alignment value. Valid entries are integer powers of two from 1 to 8192 (bytes),
such as 2, 4, 8, 16, 32, or 64. declarator is the data that you're declaring as aligned.
For information about how to return a value of type size_t that is the alignment
requirement of the type, see alignof. For information about how to declare unaligned
pointers when targeting 64-bit processors, see __unaligned.
You can use __declspec(align(#)) when you define a struct , union , or class , or when
you declare a variable.
The compiler doesn't guarantee or attempt to preserve the alignment attribute of data
during a copy or data transform operation. For example, memcpy can copy a struct
declared with __declspec(align(#)) to any location. Ordinary allocators (for example,
malloc, C++ operator new, and the Win32 allocators) typically return memory that isn't
sufficiently aligned for __declspec(align(#)) structures or arrays of structures. To
guarantee that the destination of a copy or data transformation operation is correctly
aligned, use _aligned_malloc. Or, write your own allocator.
You can't specify alignment for function parameters. When you pass data that has an
alignment attribute by value on the stack, its alignment is controlled by the calling
convention. If data alignment is important in the called function, copy the parameter
into correctly aligned memory before use.
C++
This type now has a 32-byte alignment attribute. It means that all static and automatic
instances start on a 32-byte boundary. Other structure types declared with this type as a
member preserve this type's alignment attribute. That is, any structure with Str1 as an
element has an alignment attribute of at least 32.
Here, sizeof(struct Str1) is equal to 32. It implies that if an array of Str1 objects is
created, and the base of the array is 32-byte aligned, each member of the array is also
32-byte aligned. To create an array whose base is correctly aligned in dynamic memory,
use _aligned_malloc. Or, write your own allocator.
The sizeof value for any structure is the offset of the final member, plus that member's
size, rounded up to the nearest multiple of the largest member alignment value or the
whole structure alignment value, whichever is larger.
The size of a structure is the smallest multiple of its alignment greater than or
equal to the offset of the end of its last member.
align Examples
Defining New Types with __declspec(align(#))
Aligning Data in Thread Local Storage
How align Works with Data Packing
x64 structure alignment examples
align Examples
The following examples show how __declspec(align(#)) affects the size and alignment
of data structures. The examples assume the following definitions:
C++
#define CACHE_LINE 32
#define CACHE_ALIGN __declspec(align(CACHE_LINE))
required to hold the four integers. Each int member requires 4-byte alignment, but the
alignment of the structure itself is declared to be 32. Then the overall alignment is 32.
C++
In this example, sizeof(struct S2) returns 16, which is exactly the sum of the member
sizes, because that is a multiple of the largest alignment requirement (a multiple of 8).
C++
__declspec(align(8)) struct S2 {
int a, b, c, d;
};
C++
struct S3 {
struct S1 s1; // S3 inherits cache alignment requirement
// from S1 declaration
int a; // a is now cache aligned because of s1
// 28 bytes of trailing padding
};
In this example, notice that a has the alignment of its natural type, in this case, 4 bytes.
However, S1 must be 32-byte aligned. 28 bytes of padding follow a , so that s1 starts at
offset 32. S4 then inherits the alignment requirement of S1 , because it's the largest
alignment requirement in the structure. sizeof(struct S4) returns 64.
C++
struct S4 {
int a;
// 28 bytes padding
struct S1 s1; // S4 inherits cache alignment requirement of S1
};
The following three variable declarations also use __declspec(align(#)) . In each case,
the variable must be 32-byte aligned. In the array, the base address of the array, not
each array member, is 32-byte aligned. The sizeof value for each array member is
unaffected when you use __declspec(align(#)) .
C++
CACHE_ALIGN int i;
CACHE_ALIGN int array[128];
CACHE_ALIGN struct s2 s;
C++
typedef CACHE_ALIGN struct { int a; } S5;
S5 array[10];
In this example, notice that aligning the structure itself and aligning the first element
have the same effect:
C++
CACHE_ALIGN struct S6 {
int a;
int b;
};
struct S7 {
CACHE_ALIGN int a;
int b;
};
C++
void fn() {
int a;
char b;
long c;
char d[10]
}
The alignment when memory is allocated on the heap depends on which allocation
function is called. For example, if you use malloc , the result depends on the operand
size. If arg >= 8, the memory returned is 8-byte aligned. If arg < 8, the alignment of the
memory returned is the first power of 2 less than arg. For example, if you use malloc(7) ,
the alignment is 4 bytes.
For example, you can define a struct with an alignment value this way:
C++
Now, aType and bType are the same size (8 bytes) but variables of type bType are 32-
byte aligned.
This example shows various ways to place aligned data into thread local storage.
C++
C++
struct S {
char a;
short b;
double c;
CACHE_ALIGN double d;
char e;
double f;
};
The following table lists the offset of each member under different /Zp (or #pragma
pack ) values, showing how the two interact.
a 0 0 0 0
b 1 2 2 2
c 3 4 4 8
d 32 32 32 32
e 40 40 40 40
f 41 42 44 48
sizeof(S) 64 64 64 64
The offset of an object is based on the offset of the previous object and the current
packing setting, unless the object has a __declspec(align(#)) attribute, in which case
the alignment is based on the offset of the previous object and the
__declspec(align(#)) value for the object.
See also
__declspec
Overview of ARM ABI Conventions
x64 software conventions
allocate
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The allocate declaration specifier names a data segment in which the data item will be
allocated.
Syntax
__declspec(allocate(" segname )) declarator
Remarks
The name segname must be declared using one of the following pragmas:
code_seg
const_seg
data_seg
init_seg
section
Example
C++
// allocate.cpp
#pragma section("mycode", read)
__declspec(allocate("mycode")) int i = 0;
int main() {
}
See also
__declspec
Keywords
allocator
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
__declspec(allocator)
Remarks
The native memory profiler in Visual Studio works by collecting allocation ETW event
data emitted by during runtime. Allocators in the CRT and Windows SDK have been
annotated at the source level so that their allocation data can be captured. If you are
writing your own allocators, then any functions that return a pointer to newly allocated
heap memory can be decorated with __declspec(allocator) , as seen in this example for
myMalloc:
C++
For more information, see Measure memory usage in Visual Studio and Custom native
ETW heap events.
Specifies that each application domain of your managed application should have its
own copy of a particular global variable or static member variable. See Application
Domains and Visual C++ for more information.
Every application domain has its own copy of a per-appdomain variable. A constructor
of an appdomain variable is executed when an assembly is loaded into an application
domain, and the destructor is executed when the application domain is unloaded.
If you want all application domains within a process in the common language runtime to
share a global variable, use the __declspec(process) modifier. __declspec(process) is in
effect by default under /clr. The /clr:pure and /clr:safe compiler options are deprecated
in Visual Studio 2015 and unsupported in Visual Studio 2017.
__declspec(appdomain) is only valid when one of the /clr compiler options is used. Only
a global variable, static member variable, or a static local variable can be marked with
__declspec(appdomain) . It is an error to apply __declspec(appdomain) to static members
of managed types because they always have this behavior.
There are limitations to mixing the use of per process and per appdomain variables; see
process for more information.
For example, at program start up, all per-process variables are initialized, then all per-
appdomain variables are initialized. Therefore when a per-process variable is being
initialized, it cannot depend on the value of any per-application domain variable. It is
bad practice to mix the use (assignment) of per appdomain and per process variables.
Example
C++
// declspec_appdomain.cpp
// compile with: /clr
#include <stdio.h>
using namespace System;
class CGlobal {
public:
CGlobal(bool bProcess) {
Counter = 10;
m_bProcess = bProcess;
Console::WriteLine("__declspec({0}) CGlobal::CGlobal constructor",
m_bProcess ? (String^)"process" : (String^)"appdomain");
}
~CGlobal() {
Console::WriteLine("__declspec({0}) CGlobal::~CGlobal destructor",
m_bProcess ? (String^)"process" : (String^)"appdomain");
}
int Counter;
private:
bool m_bProcess;
};
int main() {
AppDomain^ defaultDomain = AppDomain::CurrentDomain;
AppDomain^ domain = AppDomain::CreateDomain("Domain 1");
AppDomain^ domain2 = AppDomain::CreateDomain("Domain 2");
CrossAppDomainDelegate^ changeDelegate = gcnew
CrossAppDomainDelegate(&Functions::change);
CrossAppDomainDelegate^ displayDelegate = gcnew
CrossAppDomainDelegate(&Functions::display);
// Print the initial values of appdomain_global in all appdomains.
Console::WriteLine("Initial value");
defaultDomain->DoCallBack(displayDelegate);
domain->DoCallBack(displayDelegate);
domain2->DoCallBack(displayDelegate);
AppDomain::Unload(domain);
AppDomain::Unload(domain2);
}
Output
See also
__declspec
Keywords
__declspec(code_seg)
Article • 10/17/2022 • 3 minutes to read
Microsoft Specific
The code_seg declaration attribute names an executable text segment in the .obj file in
which the object code for the function or class member functions is stored.
Syntax
__declspec(code_seg(" segname ")) declarator
Remarks
The __declspec(code_seg(...)) attribute enables the placement of code into separate
named segments that can be paged or locked in memory individually. You can use this
attribute to control the placement of instantiated templates and compiler-generated
code.
A segment is a named block of data in an .obj file that is loaded into memory as a unit.
A text segment is a segment that contains executable code. The term section is often
used interchangeably with segment.
Object code that's generated when declarator is defined is put in the text segment
specified by segname , which is a narrow-string literal. The name segname doesn't have to
be specified in a section pragma before it can be used in a declaration. By default, when
no code_seg is specified, object code is put in a segment named .text . A code_seg
attribute overrides any existing #pragma code_seg directive. A code_seg attribute
applied to a member function overrides any code_seg attribute applied to the enclosing
class.
If an entity has a code_seg attribute, all declarations and definitions of the same entity
must have identical code_seg attributes. If a base-class has a code_seg attribute, derived
classes must have the same attribute.
Lambdas inherit code_seg attributes from their enclosing scope. To specify a segment
for a lambda, apply a code_seg attribute after the parameter-declaration clause and
before any mutable or exception specification, any trailing return-type specification, and
the lambda body. For more information, see Lambda Expression Syntax. This example
defines a lambda in a segment named PagedMem:
C++
Example
This example shows how a code_seg attribute controls segment placement when
implicit and explicit template specialization is used:
C++
// code_seg.cpp
// Compile: cl /EHsc /W4 code_seg.cpp
int main()
{
// implicit double specialization uses base template's
// __declspec(code_seg("Segment_1")) to place object code
Example<double> doubleExample{};
doubleExample.VirtualMemberFunction(3.14L);
See also
__declspec
Keywords
deprecated (C++)
Article • 08/03/2021 • 2 minutes to read
With the exceptions noted below, the deprecated declaration offers the same
functionality as the deprecated pragma:
The deprecated declaration lets you specify particular forms of function overloads
as deprecated, whereas the pragma form applies to all overloaded forms of a
function name.
The deprecated declaration lets you specify a message that will display at compile
time. The text of the message can be from a macro.
Examples
The following sample shows how to mark functions as deprecated, and how to specify a
message that will be displayed at compile time, when the deprecated function is used.
C++
// deprecated.cpp
// compile with: /W3
#define MY_TEXT "function is deprecated"
void func1(void) {}
__declspec(deprecated) void func1(int) {}
__declspec(deprecated("** this is a deprecated function **")) void
func2(int) {}
__declspec(deprecated(MY_TEXT)) void func3(int) {}
int main() {
func1();
func1(1); // C4996
func2(1); // C4996
func3(1); // C4996
}
The following sample shows how to mark classes as deprecated, and how to specify a
message that will be displayed at compile time, when the deprecated class is used.
C++
// deprecate_class.cpp
// compile with: /W3
struct __declspec(deprecated) X {
void f(){}
};
int main() {
X x; // C4996
X2 x2; // C4996
}
See also
__declspec
Keywords
dllexport , dllimport
Article • 05/25/2022 • 2 minutes to read
Microsoft Specific
Syntax
__declspec( dllimport ) declarator
Remarks
These attributes explicitly define the DLL's interface to its client, which can be the
executable file or another DLL. Declaring functions as dllexport eliminates the need for
a module-definition ( .def ) file, at least with respect to the specification of exported
functions. The dllexport attribute replaces the __export keyword.
dllexport of a function exposes the function with its decorated name, sometimes
known as "name mangling". For C++ functions, the decorated name includes extra
characters that encode type and parameter information. C functions or functions that
are declared as extern "C" include platform-specific decoration that's based on the
calling convention. No name decoration is applied to exported C functions or C++
extern "C" functions that use the __cdecl calling convention. For more information on
To export an undecorated name, you can link by using a Module Definition ( .def ) file
that defines the undecorated name in an EXPORTS section. For more information, see
EXPORTS. Another way to export an undecorated name is to use a #pragma
comment(linker, "/export:alias=decorated_name") directive in the source code.
When you declare dllexport or dllimport , you must use extended attribute syntax and
the __declspec keyword.
Example
C++
Alternatively, to make your code more readable, you can use macro definitions:
C++
See also
__declspec
Keywords
Definitions and Declarations (C++)
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The DLL interface refers to all items (functions and data) that are known to be exported
by some program in the system; that is, all items that are declared as dllimport or
dllexport . All declarations included in the DLL interface must specify either the
dllimport or dllexport attribute. However, the definition must specify only the
dllexport attribute. For example, the following function definition generates a compiler
error:
The use of dllexport implies a definition, while dllimport implies a declaration. You
must use the extern keyword with dllexport to force a declaration; otherwise, a
definition is implied. Thus, the following examples are correct:
void func() {
static __declspec( dllimport ) int s; // Error; not declared
// extern.
__declspec( dllimport ) int m; // Okay; this is a
// declaration.
__declspec( dllexport ) int n; // Error; implies external
// definition in local scope.
extern __declspec( dllimport ) int i; // Okay; this is a
// declaration.
extern __declspec( dllexport ) int k; // Okay; extern implies
// declaration.
__declspec( dllexport ) int x = 5; // Error; implies external
// definition in local scope.
}
See also
dllexport, dllimport
Defining Inline C++ Functions with
dllexport and dllimport
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
You can define as inline a function with the dllexport attribute. In this case, the function
is always instantiated and exported, whether or not any module in the program
references the function. The function is presumed to be imported by another program.
You can also define as inline a function declared with the dllimport attribute. In this
case, the function can be expanded (subject to /Ob specifications), but never
instantiated. In particular, if the address of an inline imported function is taken, the
address of the function residing in the DLL is returned. This behavior is the same as
taking the address of a non-inline imported function.
These rules apply to inline functions whose definitions appear within a class definition.
In addition, static local data and strings in inline functions maintain the same identities
between the DLL and client as they would in a single program (that is, an executable file
without a DLL interface).
Exercise care when providing imported inline functions. For example, if you update the
DLL, don't assume that the client will use the changed version of the DLL. To ensure that
you are loading the proper version of the DLL, rebuild the DLL's client as well.
See also
dllexport, dllimport
General Rules and Limitations
Article • 08/03/2021 • 3 minutes to read
Microsoft Specific
If you declare a function or object with the dllexport attribute, its definition must
appear in some module of the same program. Otherwise, a linker error is
generated.
C++
In C++, you can initialize a globally declared or static local data pointer or with the
address of a data object declared with the dllimport attribute, which generates an
error in C. In addition, you can initialize a static local function pointer with the
address of a function declared with the dllimport attribute. In C, such an
assignment sets the pointer to the address of the DLL import thunk (a code stub
that transfers control to the function) rather than the address of the function. In
C++, it sets the pointer to the address of the function. For example:
C++
C++
void func2()
{
static int *pi = &i; // Okay
static void ( *pf )( void ) = &func1; // Okay
}
If you apply dllexport to a regular class that has a base class that is not marked as
dllexport , the compiler will generate C4275.
The compiler generates the same warning if the base class is a specialization of a
class template. To work around this, mark the base-class with dllexport . The
problem with a specialization of a class template is where to place the
__declspec(dllexport) ; you are not allowed to mark the class template. Instead,
explicitly instantiate the class template and mark this explicit instantiation with
dllexport . For example:
C++
This workaround fails if the template argument is the deriving class. For example:
C++
Because this is common pattern with templates, the compiler changed the
semantics of dllexport when it is applied to a class that has one or more base-
classes and when one or more of the base classes is a specialization of a class
template. In this case, the compiler implicitly applies dllexport to the
specializations of class templates. You can do the following and not get a warning:
C++
See also
dllexport, dllimport
Using dllimport and dllexport in C++
Classes
Article • 08/03/2021 • 3 minutes to read
Microsoft Specific
You can declare C++ classes with the dllimport or dllexport attribute. These forms
imply that the entire class is imported or exported. Classes exported this way are called
exportable classes.
The following example defines an exportable class. All its member functions and static
data are exported:
C++
class DllExport C {
int i;
virtual int func( void ) { return 1; }
};
Note that explicit use of the dllimport and dllexport attributes on members of an
exportable class is prohibited.
dllexport Classes
When you declare a class dllexport , all its member functions and static data members
are exported. You must provide the definitions of all such members in the same
program. Otherwise, a linker error is generated. The one exception to this rule applies to
pure virtual functions, for which you need not provide explicit definitions. However,
because a destructor for an abstract class is always called by the destructor for the base
class, pure virtual destructors must always provide a definition. Note that these rules are
the same for nonexportable classes.
If you export data of class type or functions that return classes, be sure to export the
class.
dllimport Classes
When you declare a class dllimport , all its member functions and static data members
are imported. Unlike the behavior of dllimport and dllexport on nonclass types, static
data members cannot specify a definition in the same program in which a dllimport
class is defined.
Similarly, you can declare member functions with the dllimport or dllexport attributes.
In this case, you must provide a dllexport definition somewhere within the same
program.
It is worthwhile to note several important points regarding selective member import and
export:
If you export one virtual function in a class, you must export all of them, or at least
provide versions that the client can use directly.
If you have a class in which you are using selective member import/export with
virtual functions, the functions must be in the exportable interface or defined inline
(visible to the client).
If you define a member as dllexport but do not include it in the class definition, a
compiler error is generated. You must define the member in the class header.
If you define a member function in a place other than the body of the class
definition in which you declared it, a warning is generated if the function is defined
as dllexport or dllimport (if this definition differs from that specified in the class
declaration).
See also
dllexport, dllimport
empty_bases
Article • 03/02/2022 • 5 minutes to read
Microsoft Specific
The C++ Standard requires that a most-derived object must have a non-zero size and
must occupy one or more bytes of storage. Because the requirement only extends to
most-derived objects, base class subobjects aren't subject to this constraint. The Empty
Base Class Optimization (EBCO) takes advantage of this liberty. It results in reduced
memory consumption, which can improve performance. The Microsoft Visual C++
compiler has historically had limited support for EBCO. In Visual Studio 2015 Update 3
and later versions, we've added a new __declspec(empty_bases) attribute for class types
that takes full advantage of this optimization.
) Important
Syntax
__declspec( empty_bases )
Remarks
In Visual Studio, absent any __declspec(align()) or alignas() specifications, an empty
class is 1 byte in size:
C++
A class with a single non-static data member of type char is also 1 byte in size:
C++
struct Struct1
{
char c;
};
static_assert(sizeof(Struct1) == 1, "Struct1 should be 1 byte");
Combining these classes in a class hierarchy also results in a class that's 1 byte in size:
C++
This result is the Empty Base Class Optimization at work, as without it Derived1 would
be 2 bytes in size: 1 byte for Empty1 and 1 byte for Derived1::c . The class layout is also
optimal when there's a chain of empty classes:
C++
However, the default class layout in Visual Studio doesn't take advantage of EBCO in
multiple inheritance scenarios:
C++
Although Derived3 could be 1 byte in size, the default class layout results in it being 2
bytes in size. The class layout algorithm is adding 1 byte of padding between any two
consecutive empty base classes, effectively resulting in Empty2 consuming an extra byte
within Derived3 :
class Derived3 size(2):
+---
0 | +--- (base class Empty2)
0 | | +--- (base class Empty1)
| | +---
| +---
1 | +--- (base class Empty3)
| +---
1 | c
+---
The effects of this suboptimal layout are compounded when the alignment
requirements of a later base class or member subobject force extra padding:
C++
The natural alignment for an object of type int is 4 bytes, so 3 bytes of extra padding
must be added after Empty3 to correctly align Derived4::i :
Another issue with the default class layout is that an empty base class may be laid out at
an offset past the end of the class:
C++
Although Struct2 is the optimal size, Empty1 is laid out at offset 1 within Struct2 but
the size of Struct2 isn't increased to account for it. As a result, for an array A of
Struct2 objects, the address of the Empty1 subobject of A[0] will be the same as the
address of A[1] , which shouldn't be the case. This issue wouldn't occur if Empty1 were
laid out at offset 0 within Struct2 , thereby overlapping the Struct1 subobject.
The default layout algorithm hasn't been modified to address these limitations and fully
take advantage of EBCO. Such a change would break binary compatibility. If the default
layout for a class changed as a result of EBCO, every object file and library that contains
the class definition would need to be recompiled so they all agree on the class layout.
This requirement would also extend to libraries obtained from external sources. The
developers of such libraries would have to provide independent versions compiled both
with and without the EBCO layout to support customers who use different versions of
the compiler. Although we can't change the default layout, we can provide a means to
change the layout on a per-class basis with the addition of the __declspec(empty_bases)
class attribute. A class defined with this attribute can make full use of EBCO.
C++
All of the subobjects of Derived3 are laid out at offset 0, and its size is the optimal 1
byte. One important point to remember is that __declspec(empty_bases) only affects the
layout of the class to which it's applied. It isn't applied recursively to base classes:
C++
C++
Because of the requirement that all object files and libraries agree on the class layout,
__declspec(empty_bases) can only be applied to classes that you control. It can't be
applied to classes in the standard library, or to classes included in libraries that aren't
also recompiled with the EBCO layout.
See also
__declspec
Keywords
jitintrinsic
Article • 08/03/2021 • 2 minutes to read
Marks the function as significant to the 64-bit common language runtime. This is used
on certain functions in Microsoft-provided libraries.
Syntax
__declspec(jitintrinsic)
Remarks
jitintrinsic adds a MODOPT (IsJitIntrinsic) to a function signature.
Users are discouraged from using this __declspec modifier, as unexpected results can
occur.
See also
__declspec
Keywords
naked (C++)
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
For functions declared with the naked attribute, the compiler generates code without
prolog and epilog code. You can use this feature to write your own prolog/epilog code
sequences using inline assembler code. Naked functions are particularly useful in writing
virtual device drivers. Note that the naked attribute is only valid on x86 and ARM, and is
not available on x64.
Syntax
__declspec(naked) declarator
Remarks
Because the naked attribute is only relevant to the definition of a function and is not a
type modifier, naked functions must use extended attribute syntax and the __declspec
keyword.
The compiler cannot generate an inline function for a function marked with the naked
attribute, even if the function is also marked with the __forceinline keyword.
The compiler issues an error if the naked attribute is applied to anything other than the
definition of a non-member method.
Examples
This code defines a function with the naked attribute:
Or, alternately:
#define Naked __declspec( naked )
Naked int func( formal_parameters ) {}
The naked attribute affects only the nature of the compiler's code generation for the
function's prolog and epilog sequences. It does not affect the code that is generated for
calling such functions. Thus, the naked attribute is not considered part of the function's
type, and function pointers cannot have the naked attribute. Furthermore, the naked
attribute cannot be applied to a data definition. For example, this code sample
generates an error:
The naked attribute is relevant only to the definition of the function and cannot be
specified in the function's prototype. For example, this declaration generates a compiler
error:
See also
__declspec
Keywords
Naked Function Calls
noalias
Article • 08/03/2021 • 2 minutes to read
Microsoft-specific
noalias means that a function call doesn't modify or reference visible global state and
only modifies the memory pointed to directly by pointer parameters (first-level
indirections).
If a function is annotated as noalias , the optimizer can assume that only the parameters
themselves, and only first-level indirections of pointer parameters, are referenced or
modified inside the function.
The noalias annotation only applies within the body of the annotated function.
Marking a function as __declspec(noalias) doesn't affect the aliasing of pointers
returned by the function.
Example
The following sample demonstrates the use of __declspec(noalias) .
// declspec_noalias.c
#include <stdio.h>
#include <stdlib.h>
#define M 800
#define N 600
#define P 700
a = ma(m * n);
if (!a) exit(1);
for (i=0; i<m; i++)
for (j=0; j<n; j++)
a[i*n+j] = 0.1/k++;
return a;
}
int main()
{
float * a, * b, * c;
if (!mempool)
{
puts("ERROR: Malloc returned null");
exit(1);
}
memptr = mempool;
a = init(M, N);
b = init(N, P);
c = init(M, P);
multiply(a, b, c);
}
See also
__declspec
Keywords
__declspec(restrict)
noinline
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
(function in a class).
It may be worthwhile to not inline a function if it is small and not critical to the
performance of your code. That is, if the function is small and not likely to be called
often, such as a function that handles an error condition.
Keep in mind that if a function is marked noinline , the calling function will be smaller
and thus, itself a candidate for compiler inlining.
C++
class X {
__declspec(noinline) int mbrfunc() {
return 0;
} // will not inline
};
See also
__declspec
Keywords
inline, __inline, __forceinline
noreturn
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
This __declspec attribute tells the compiler that a function does not return. As a
consequence, the compiler knows that the code following a call to a
__declspec(noreturn) function is unreachable.
If the compiler finds a function with a control path that does not return a value, it
generates a warning (C4715) or error message (C2202). If the control path cannot be
reached due to a function that never returns, you can use __declspec(noreturn) to
prevent this warning or error.
7 Note
Example
In the following sample,the else clause does not contain a return statement. Declaring
fatal as __declspec(noreturn) avoids an error or warning message.
C++
// noreturn2.cpp
__declspec(noreturn) extern void fatal () {}
int main() {
if(1)
return 1;
else if(0)
return 0;
else
fatal();
}
See also
__declspec
Keywords
no_sanitize_address
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
7 Note
Example
See the AddressSanitizer build reference for examples.
See also
__declspec
Keywords
AddressSanitizer
nothrow (C++)
Article • 08/17/2021 • 2 minutes to read
Microsoft Specific
Syntax
return-type __declspec(nothrow) [call-convention] function-name ([argument-list])
Remarks
We recommend that all new code use the noexcept operator rather than
__declspec(nothrow) .
This attribute tells the compiler that the declared function and the functions it calls
never throw an exception. However, it does not enforce the directive. In other words, it
never causes std::terminate to be invoked, unlike noexcept , or in std:c++17 mode
(Visual Studio 2017 version 15.5 and later), throw() .
With the synchronous exception handling model, now the default, the compiler can
eliminate the mechanics of tracking the lifetime of certain unwindable objects in such a
function, and significantly reduce the code size. Given the following preprocessor
directive, the three function declarations below are equivalent in /std:c++14 mode:
C++
The void __stdcall f3() throw(); declaration uses the syntax defined by the C++
standard. In C++17 the throw() keyword was deprecated.
END Microsoft Specific
See also
__declspec
noexcept
Keywords
novtable
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
This form of __declspec can be applied to any class declaration, but should only be
applied to pure interface classes, that is, classes that will never be instantiated on their
own. The __declspec stops the compiler from generating code to initialize the vfptr in
the constructor(s) and destructor of the class. In many cases, this removes the only
references to the vtable that are associated with the class and, thus, the linker will
remove it. Using this form of __declspec can result in a significant reduction in code
size.
If you attempt to instantiate a class marked with novtable and then access a class
member, you will receive an access violation (AV).
Example
C++
// novtable.cpp
#include <stdio.h>
struct __declspec(novtable) X {
virtual void mf();
};
struct Y : public X {
void mf() {
printf_s("In Y\n");
}
};
int main() {
// X *pX = new X();
// pX->mf(); // Causes a runtime access violation.
Output
In Y
See also
__declspec
Keywords
process
Article • 08/03/2021 • 2 minutes to read
Specifies that your managed application process should have a single copy of a
particular global variable, static member variable, or static local variable shared across all
application domains in the process. This was primarily intended to be used when
compiling with /clr:pure , which is deprecated in Visual Studio 2015 and unsupported
in Visual Studio 2017. When compiling with /clr , global and static variables are per-
process by default and do not need to use __declspec(process) .
Only a global variable, a static member variable, or a static local variable of native type
can be marked with __declspec(process) .
If you want each application domain to have its own copy of a global variable, use
appdomain.
See also
__declspec
Keywords
property (C++)
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
This attribute can be applied to non-static "virtual data members" in a class or structure
definition. The compiler treats these "virtual data members" as data members by
changing their references into function calls.
Syntax
Remarks
When the compiler sees a data member declared with this attribute on the right of a
member-selection operator ("." or "->"), it converts the operation to a get or put
function, depending on whether such an expression is an l-value or an r-value. In more
complicated contexts, such as " += ", a rewrite is performed by doing both get and put .
This attribute can also be used in the declaration of an empty array in a class or
structure definition. For example:
C++
The above statement indicates that x[] can be used with one or more array indices. In
this case, i=p->x[a][b] will be turned into i=p->GetX(a, b) , and p->x[a][b] = i will be
turned into p->PutX(a, b, i);
Example
C++
// declspec_property.cpp
struct S {
int i;
void putprop(int j) {
i = j;
}
int getprop() {
return i;
}
int main() {
S s;
s.the_prop = 5;
return s.the_prop;
}
See also
__declspec
Keywords
restrict
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
__declspec(restrict) pointer_return_type function();
Remarks
The compiler propagates __declspec(restrict) . For example, the CRT malloc function
has a __declspec(restrict) decoration, and therefore, the compiler assumes that
pointers initialized to memory locations by malloc are also not aliased by previously
existing pointers.
The compiler does not check that the returned pointer is not actually aliased. It is the
developer's responsibility to ensure the program does not alias a pointer marked with
the restrict __declspec modifier.
For another annotation that applies to aliasing within a function, see __declspec(noalias).
For information about the restrict keyword that is part of C++ AMP, see restrict (C++
AMP).
Example
The following sample demonstrates the use of __declspec(restrict) .
When __declspec(restrict) is applied to a function that returns a pointer, this tells the
compiler that the memory pointed to by the return value is not aliased. In this example,
the pointers mempool and memptr are global, so the compiler can't be sure that the
memory they refer to is not aliased. However, they are used within ma and its caller
init in a way that returns memory that isn't otherwise referenced by the program, so
__decslpec(restrict) is used to help the optimizer. This is similar to how the CRT headers
decorate allocation functions such as malloc by using __declspec(restrict) to indicate
that they always return memory that cannot be aliased by existing pointers.
// declspec_restrict.c
// Compile with: cl /W4 declspec_restrict.c
#include <stdio.h>
#include <stdlib.h>
#define M 800
#define N 600
#define P 700
a = ma(m * n);
if (!a) exit(1);
for (i=0; i<m; i++)
for (j=0; j<n; j++)
a[i*n+j] = 0.1f/k++;
return a;
}
int main()
{
float * a, * b, * c;
if (!mempool)
{
puts("ERROR: Malloc returned null");
exit(1);
}
memptr = mempool;
a = init(M, N);
b = init(N, P);
c = init(M, P);
multiply(a, b, c);
}
See also
Keywords
__declspec
__declspec(noalias)
safebuffers
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Tells the compiler not to insert buffer overrun security checks for a function.
Syntax
__declspec( safebuffers )
Remarks
The /GS compiler option causes the compiler to test for buffer overruns by inserting
security checks on the stack. The types of data structures that are eligible for security
checks are described in /GS (Buffer Security Check). For more information about buffer
overrun detection, see Security Features in MSVC .
An expert manual code review or external analysis might determine that a function is
safe from a buffer overrun. In that case, you can suppress security checks for a function
by applying the __declspec(safebuffers) keyword to the function declaration.
U Caution
Buffer security checks provide important security protection and have a negligible
affect on performance. Therefore, we recommend that you do not suppress them,
except in the rare case where the performance of a function is a critical concern and
the function is known to be safe.
Inline Functions
A primary function can use an inlining keyword to insert a copy of a secondary function.
If the __declspec(safebuffers) keyword is applied to a function, buffer overrun
detection is suppressed for that function. However, inlining affects the
__declspec(safebuffers) keyword in the following ways.
Suppose the /GS compiler option is specified for both functions, but the primary
function specifies the __declspec(safebuffers) keyword. The data structures in the
secondary function make it eligible for security checks, and the function does not
suppress those checks. In this case:
Specify the __forceinline keyword on the secondary function to force the compiler
to inline that function regardless of compiler optimizations.
Because the secondary function is eligible for security checks, security checks are
also applied to the primary function even though it specifies the
__declspec(safebuffers) keyword.
Example
The following code shows how to use the __declspec(safebuffers) keyword.
C++
See also
__declspec
Keywords
inline, __inline, __forceinline
strict_gs_check
selectany
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Tells the compiler that the declared global data item (variable or object) is a pick-any
COMDAT (a packaged function).
Syntax
__declspec( selectany ) declarator
Remarks
At link time, if multiple definitions of a COMDAT are seen, the linker picks one and
discards the rest. If the linker option /OPT:REF (Optimizations) is selected, then COMDAT
elimination will occur to remove all the unreferenced data items in the linker output.
A global data item can normally be initialized only once in an EXE or DLL project.
selectany can be used in initializing global data defined by headers, when the same
header appears in more than one source file. selectany is available in both the C and
C++ compilers.
7 Note
selectany can only be applied to the actual initialization of global data items that
__declspec(selectany) X x(1);
C++
// selectany2.cpp
// in the following lines, const marks the variables as read only
__declspec(selectany) extern const int ix = 5;
__declspec(selectany) extern const int jx = 5;
int main() {
int ij;
ij = ix + jx;
}
END Microsoft Specific
See also
__declspec
Keywords
spectre
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Tells the compiler not to insert Spectre variant 1 speculative execution barrier
instructions for a function.
Syntax
__declspec( spectre(nomitigation) )
Remarks
The /Qspectre compiler option causes the compiler to insert speculative execution
barrier instructions. They're inserted where analysis indicates that a Spectre variant 1
security vulnerability exists. The specific instructions emitted depend on the processor.
While these instructions should have a minimal impact on code size or performance,
there may be cases where your code is not affected by the vulnerability, and requires
maximum performance.
Expert analysis might determine that a function is safe from a Spectre variant 1 bounds
check bypass defect. In that case, you can suppress the generation of mitigation code
within a function by applying __declspec(spectre(nomitigation)) to the function
declaration.
U Caution
Example
The following code shows how to use __declspec(spectre(nomitigation)) .
C++
// compile with: /c /Qspectre
static __declspec(spectre(nomitigation))
int noSpectreIssues() {
// No Spectre variant 1 vulnerability here
// ...
return 0;
}
int main() {
noSpectreIssues();
return 0;
}
See also
__declspec
Keywords
/Qspectre
thread
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The thread extended storage-class modifier is used to declare a thread local variable.
For the portable equivalent in C++11 and later, use the thread_local storage class
specifier for portable code. On Windows thread_local is implemented with
__declspec(thread) .
Syntax
__declspec(thread) declarator
Remarks
Thread Local Storage (TLS) is the mechanism by which each thread in a multithreaded
process allocates storage for thread-specific data. In standard multithreaded programs,
data is shared among all threads of a given process, whereas thread local storage is the
mechanism for allocating per-thread data. For a complete discussion of threads, see
Multithreading.
Declarations of thread local variables must use extended attribute syntax and the
__declspec keyword with the thread keyword. For example, the following code declares
an integer thread local variable and initializes it with a value:
C++
1. If the variable is initialized with a function call (including constructors), this function
will only be called for the thread that caused the binary/DLL to load into the
process, and for those threads that started after the binary/DLL was loaded. The
initialization functions are not called for any other thread that was already running
when the DLL was loaded. Dynamic initialization occurs on the DllMain call for
DLL_THREAD_ATTACH, but the DLL never gets that message if the DLL isn't in the
process when the thread starts.
2. Thread-local variables that are initialized statically with constant values are
generally initialized properly on all threads. However, as of December 2017 there is
a known conformance issue in the Microsoft C++ compiler whereby constexpr
variables receive dynamic rather than static initialization.
Note: Both of these issues are expected to be fixed in future updates of the
compiler.
Additionally, you must observe these guidelines when declaring thread local objects and
variables:
You can apply the thread attribute only to class and data declarations and
definitions; thread can't be used on function declarations or definitions.
You can specify the thread attribute only on data items with static storage
duration. This includes global data objects (both static and extern ), local static
objects, and static data members of classes. You can't declare automatic data
objects with the thread attribute.
You must use the thread attribute for the declaration and the definition of a
thread local object, whether the declaration and definition occur in the same file or
separate files.
Because the declaration of objects that use the thread attribute is permitted, these
two examples are semantically equivalent:
C++
// declspec_thread_2.cpp
// compile with: /LD
__declspec( thread ) class B {
public:
int data;
} BObject; // BObject declared thread local.
class B2 {
public:
int data;
};
__declspec( thread ) B2 BObject2; // BObject2 declared thread local.
C++
// declspec_thread_3.cpp
// compile with: /LD
#define Thread __declspec( thread )
int j = j; // Okay in C++; C error
Thread int tls_i = sizeof( tls_i ); // Okay in C and C++
A sizeof expression that includes the object being initialized does not constitute a
reference to itself and is allowed in C and C++.
See also
__declspec
Keywords
Thread Local Storage (TLS)
uuid (C++)
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The compiler attaches a GUID to a class or structure declared or defined (full COM
object definitions only) with the uuid attribute.
Syntax
Remarks
The uuid attribute takes a string as its argument. This string names a GUID in normal
registry format with or without the { } delimiters. For example:
C++
This attribute can be applied in a redeclaration. This allows the system headers to supply
the definitions of interfaces such as IUnknown , and the redeclaration in some other
header (such as <comdef.h>) to supply the GUID.
The keyword __uuidof can be applied to retrieve the constant GUID attached to a user-
defined type.
See also
__declspec
Keywords
__restrict
Article • 08/03/2021 • 2 minutes to read
Like the __declspec ( restrict ) modifier, the __restrict keyword (two leading
underscores '_') indicates that a symbol isn't aliased in the current scope. The
__restrict keyword differs from the __declspec (restrict) modifier in the following
ways:
When __restrict is used, the compiler won't propagate the no-alias property of a
variable. That is, if you assign a __restrict variable to a non- __restrict variable,
the compiler will still allow the non-__restrict variable to be aliased. This is different
from the behavior of the C99 C language restrict keyword.
Generally, if you want to affect the behavior of an entire function, use __declspec
(restrict) instead of the keyword.
For compatibility with previous versions, _restrict is a synonym for __restrict unless
compiler option /Za (Disable language extensions) is specified.
In Visual Studio 2015 and later, __restrict can be used on C++ references.
7 Note
When used on a variable that also has the volatile keyword, volatile will take
precedence.
Example
C++
// __restrict_keyword.c
// compile with: /LD
// In the following function, declare a and b as disjoint arrays
// but do not have same assurance for c and d.
void sum2(int n, int * __restrict a, int * __restrict b,
int * c, int * d) {
int i;
for (i = 0; i < n; i++) {
a[i] = b[i] + c[i];
c[i] = b[i] + d[i];
}
}
See also
Keywords
__sptr, __uptr
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Use the __sptr or __uptr modifier on a 32-bit pointer declaration to specify how the
compiler converts a 32-bit pointer to a 64-bit pointer. A 32-bit pointer is converted, for
example, when it is assigned to a 64-bit pointer variable or is dereferenced on a 64-bit
platform.
Microsoft documentation for support of 64-bit platforms sometimes refers to the most
significant bit of a 32-bit pointer as the sign bit. By default, the compiler uses sign
extension to convert a 32-bit pointer to a 64-bit pointer. That is, the least significant 32
bits of the 64-bit pointer are set to the value of the 32-bit pointer and the most
significant 32 bits are set to the value of the sign bit of the 32-bit pointer. This
conversion yields correct results if the sign bit is 0, but not if the sign bit is 1. For
example, the 32-bit address 0x7FFFFFFF yields the equivalent 64-bit address
0x000000007FFFFFFF, but the 32-bit address 0x80000000 is incorrectly changed to
0xFFFFFFFF80000000.
The __sptr , or signed pointer, modifier specifies that a pointer conversion set the most
significant bits of a 64-bit pointer to the sign bit of the 32-bit pointer. The __uptr , or
unsigned pointer, modifier specifies that a conversion set the most significant bits to
zero. The following declarations show the __sptr and __uptr modifiers used with two
unqualified pointers, two pointers qualified with the __ptr32 type, and a function
parameter.
C++
Use the __sptr and __uptr modifiers with pointer declarations. Use the modifiers in the
position of a pointer type qualifier, which means the modifier must follow the asterisk.
You cannot use the modifiers with pointers to members. The modifiers do not affect
non-pointer declarations.
For compatibility with previous versions, _sptr and _uptr are synonyms for __sptr and
__uptr unless compiler option /Za (Disable language extensions) is specified.
Example
The following example declares 32-bit pointers that use the __sptr and __uptr
modifiers, assigns each 32-bit pointer to a 64-bit pointer variable, and then displays the
hexadecimal value of each 64-bit pointer. The example is compiled with the native 64-
bit compiler and is executed on a 64-bit platform.
C++
// sptr_uptr.cpp
// processor: x64
#include "stdio.h"
int main()
{
void * __ptr64 p64;
void * __ptr32 p32d; //default signed pointer
void * __sptr __ptr32 p32s; //explicit signed pointer
void * __uptr __ptr32 p32u; //explicit unsigned pointer
// The printf() function automatically displays leading zeroes with each 32-
bit pointer. These are unrelated
// to the __sptr and __uptr modifiers.
printf("Display each 32-bit pointer (as an unsigned 64-bit
pointer):\n");
printf("p32d: %p\n", p32d);
printf("p32s: %p\n", p32s);
printf("p32u: %p\n", p32u);
Output
See also
Microsoft-Specific Modifiers
__unaligned
Article • 04/22/2022 • 2 minutes to read
Microsoft-specific. When you declare a pointer with the __unaligned modifier, the
compiler assumes that the pointer addresses data that isn't aligned. So, platform-
appropriate code is generated to handle unaligned reads and writes through the
pointer.
Remarks
This modifier describes the alignment of the data addressed by the pointer. It is
assumed that the pointer itself is aligned.
The necessity for the __unaligned keyword varies by platform and environment. Failure
to mark data appropriately can result in issues ranging from performance penalties to
hardware faults. The __unaligned modifier isn't valid for the x86 platform.
align
alignof Operator
pack
/Zp (Struct Member Alignment)
x64 structure alignment examples
See also
Keywords
__w64
Article • 08/03/2021 • 2 minutes to read
Syntax
type __w64 identifier
Parameters
type
One of the three types that could cause problems in code being ported from a 32-bit to
a 64-bit compiler: int , long , or a pointer.
identifier
The identifier for the variable you are creating.
Remarks
) Important
The /Wp64 compiler option and __w64 keyword are deprecated in Visual Studio
2010 and Visual Studio 2013 and removed starting in Visual Studio 2013. If you use
the /Wp64 compiler option on the command line, the compiler issues Command-
Line Warning D9002. The __w64 keyword is silently ignored. Instead of using this
option and keyword to detect 64-bit portability issues, use a Microsoft C++
compiler that targets a 64-bit platform. For more information, see Configure Visual
C++ for 64-bit, x64 targets.
Any typedef that has __w64 on it must be 32 bits on x86 and 64 bits on x64.
To detect portability issues by using versions of the Microsoft C++ compiler earlier than
Visual Studio 2010, the __w64 keyword should be specified on any typedefs that change
size between 32 bit and 64 bit platforms. For any such type, __w64 must appear only on
the 32-bit definition of the typedef.
For compatibility with previous versions, _w64 is a synonym for __w64 unless compiler
option /Za (Disable language extensions) is specified.
The __w64 keyword is ignored if the compilation does not use /Wp64 .
For more information about porting to 64-bit, see the following topics:
Example
C++
// __w64.cpp
// compile with: /W3 /Wp64
typedef int Int_32;
#ifdef _WIN64
typedef __int64 Int_Native;
#else
typedef int __w64 Int_Native;
#endif
int main() {
Int_32 i0 = 5;
Int_Native i1 = 10;
i0 = i1; // C4244 64-bit int assigned to 32-bit int
See also
Keywords
__func__
Article • 11/12/2021 • 2 minutes to read
(C++11) The predefined identifier __func__ is implicitly defined as a string that contains
the unqualified and unadorned name of the enclosing function. __func__ is mandated
by the C++ standard and is not a Microsoft extension.
Syntax
C++
__func__
Return Value
Returns a null-terminated const char array of characters that contains the function
name.
Example
C++
#include <string>
#include <iostream>
namespace Test
{
struct Foo
{
static void DoSomething(int i, std::string s)
{
std::cout << __func__ << std::endl; // Output: DoSomething
}
};
}
int main()
{
Test::Foo::DoSomething(42, "Hello");
return 0;
}
Requirements
C++11
Compiler COM Support
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
The Microsoft C++ compiler can directly read component object model (COM) type
libraries and translate the contents into C++ source code that can be included in the
compilation. Language extensions are available to facilitate COM programming on the
client side for desktop apps.
By using the #import preprocessor directive, the compiler can read a type library and
convert it into a C++ header file that describes the COM interfaces as classes. A set of
#import attributes is available for user control of the content for the resulting type
library header files.
You can use the __declspec extended attribute uuid to assign a globally unique identifier
(GUID) to a COM object. The keyword __uuidof can be used to extract the GUID
associated with a COM object. Another __declspec attribute, property, can be used to
specify the get and set methods for a data member of a COM object.
A set of COM support global functions and classes is provided to support the VARIANT
and BSTR types, implement smart pointers, and encapsulate the error object thrown by
_com_raise_error :
_bstr_t
_com_error
_com_ptr_t
_variant_t
See also
Compiler COM Support Classes
Compiler COM Global Functions
Compiler COM Global Functions
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Function Description
_set_com_error_handler Replaces the default function that is used for COM error-handling.
See also
Compiler COM Support Classes
Compiler COM Support
_com_raise_error
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
Parameters
hr
HRESULT information.
perrinfo
IErrorInfo object.
Remarks
_com_raise_error, which is defined in <comdef.h>, can be replaced by a user-written
version of the same name and prototype. This could be done if you want to use #import
but do not want to use C++ exception handling. In that case, a user version of
_com_raise_error might decide to do a longjmp or display a message box and halt. The
user version should not return, though, because the compiler COM support code does
not expect it to return.
You can also use _set_com_error_handler to replace the default error-handling function.
C++
Requirements
Header: <comdef.h>
Lib: If the wchar_t is Native Type compiler option is on, use comsuppw.lib or
comsuppwd.lib. If wchar_t is Native Type is off, use comsupp.lib. For more information,
see /Zc:wchar_t (wchar_t Is Native Type).
See also
Compiler COM Global Functions
_set_com_error_handler
ConvertStringToBSTR
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
Parameters
pSrc
A char * variable.
Example
C++
// ConvertStringToBSTR.cpp
#include <comutil.h>
#include <stdio.h>
int main() {
char* lpszText = "Test";
printf_s("char * text: %s\n", lpszText);
SysFreeString(bstrText);
}
Output
Requirements
Header: <comutil.h>
Lib: comsuppw.lib or comsuppwd.lib (see /Zc:wchar_t (wchar_t Is Native Type) for more
information)
See also
Compiler COM Global Functions
ConvertBSTRToString
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
Parameters
pSrc
A BSTR variable.
Remarks
ConvertBSTRToString allocates a string you must delete.
Example
C++
// ConvertBSTRToString.cpp
#include <comutil.h>
#include <stdio.h>
int main() {
BSTR bstrText = ::SysAllocString(L"Test");
wprintf_s(L"BSTR text: %s\n", bstrText);
SysFreeString(bstrText);
delete[] lpszText2;
}
Output
Requirements
Header: <comutil.h>
Lib: comsuppw.lib or comsuppwd.lib (see /Zc:wchar_t (wchar_t Is Native Type) for more
information)
See also
Compiler COM Global Functions
_set_com_error_handler
Article • 08/03/2021 • 2 minutes to read
Syntax
C++
Parameters
pHandler
Pointer to the replacement function.
hr
HRESULT information.
perrinfo
IErrorInfo object.
Remarks
By default, _com_raise_error handles all COM errors. You can change this behavior by
using _set_com_error_handler to call your own error-handling function.
Example
C++
// _set_com_error_handler.cpp
// compile with /EHsc
#include <stdio.h>
#include <comdef.h>
#include <comutil.h>
int main()
{
_set_com_error_handler(_My_com_raise_error);
_bstr_t bstrEmpty(L"");
_ConnectionPtr Connection = NULL;
try
{
Connection.CreateInstance(__uuidof(Connection));
Connection->Open(bstrEmpty, bstrEmpty, bstrEmpty, 0);
}
catch(char* errorMessage)
{
printf("Exception raised: %s\n", errorMessage);
}
return 0;
}
Output
Requirements
Header: <comdef.h>
Lib: If the /Zc:wchar_t compiler option is specified (the default), use comsuppw.lib or
comsuppwd.lib. If the /Zc:wchar_t- compiler option is specified, use comsupp.lib. For
more information, including how to set this option in the IDE, see /Zc:wchar_t (wchar_t Is
Native Type).
See also
Compiler COM Global Functions
Compiler COM Support Classes
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Standard classes are used to support some of the COM types. The classes are defined in
<comdef.h> and the header files generated from the type library.
Class Purpose
_bstr_t Wraps the BSTR type to provide useful operators and methods.
_com_ptr_t Encapsulates COM interface pointers, and automates the required calls to AddRef ,
Release , and QueryInterface .
_variant_t Wraps the VARIANT type to provide useful operators and methods.
See also
Compiler COM Support
Compiler COM Global Functions
C++ Language Reference
_bstr_t class
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
A _bstr_t object encapsulates the BSTR data type. The class manages resource
allocation and deallocation through function calls to SysAllocString and SysFreeString
and other BSTR APIs when appropriate. The _bstr_t class uses reference counting to
avoid excessive overhead.
Members
Construction
Constructor Description
Operations
Function Description
Detach Returns the BSTR wrapped by a _bstr_t and detaches the BSTR from the _bstr_t .
Operators
Operator Description
operator wchar_t* Extract the pointers to the encapsulated Unicode or multibyte BSTR object.
operator char*
Requirements
Header: <comutil.h>
See also
Compiler COM support classes
_bstr_t::_bstr_t
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
_bstr_t( ) throw( );
_bstr_t(
const _bstr_t& s1
) throw( );
_bstr_t(
const char* s2
);
_bstr_t(
const wchar_t* s3
);
_bstr_t(
const _variant_t& var
);
_bstr_t(
BSTR bstr,
bool fCopy
);
Parameters
s1
s2
A multibyte string.
s3
A Unicode string
var
A _variant_t object.
bstr
fCopy
If false , the bstr argument is attached to the new object without making a copy by
calling SysAllocString .
Remarks
The _bstr_t class supplies several constructors:
_bstr_t( )
_bstr_t( _bstr_t& s1 )
_bstr_t( char* s2 )
Constructs a _bstr_t object by calling SysAllocString to create a new BSTR object and
then encapsulates it. This constructor first performs a multibyte to Unicode conversion.
_bstr_t( wchar_t* s3 )
Constructs a _bstr_t object by calling SysAllocString to create a new BSTR object and
then encapsulates it.
Constructs a _bstr_t object from a _variant_t object by first retrieving a BSTR object
from the encapsulated VARIANT object.
Constructs a _bstr_t object from an existing BSTR (as opposed to a wchar_t* string). If
fCopy is false , the supplied BSTR is attached to the new object without making a new
copy by using SysAllocString . This constructor is used by wrapper functions in the type
library headers to encapsulate and take ownership of a BSTR that's returned by an
interface method.
See also
_bstr_t class
_variant_t class
_ bstr_t::Assign
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
void Assign(
BSTR s
);
Parameters
s
A BSTR to be copied into the BSTR wrapped by a _bstr_t .
Remarks
Assign does a binary copy of the entire length of the BSTR , whatever the content.
Example
C++
// _bstr_t_Assign.cpp
#include <comdef.h>
#include <stdio.h>
int main()
{
// creates a _bstr_t wrapper
_bstr_t bstrWrapper;
bstrWrapper.Attach(SysAllocString(OLESTR("SysAllocedString")));
wprintf_s(L"bstrWrapper = %s\n",
static_cast<wchar_t*>(bstrWrapper));
// resuse bstr
bstr= SysAllocString(OLESTR("Yet another string"));
// two wrappers, one BSTR
_bstr_t bstrWrapper2 = bstrWrapper;
*bstrWrapper.GetAddress() = bstr;
Output
See also
_bstr_t class
_bstr_t::Attach
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
void Attach(
BSTR s
);
Parameters
s
A BSTR to be associated with, or assigned to, the _bstr_t variable.
Remarks
If the _bstr_t was previously attached to another BSTR , the _bstr_t will clean up the
BSTR resource, if no other _bstr_t variables are using the BSTR .
Example
See _bstr_t::Assign for an example using Attach .
See also
_bstr_t Class
_bstr_t::copy
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
Parameters
fCopy
If true , copy returns a copy of the contained BSTR , otherwise copy returns the actual
BSTR .
Remarks
Returns a newly allocated copy of the encapsulated BSTR object, or the encapsulated
object itself, depending on the parameter.
Example
C++
See also
_bstr_t class
_bstr_t::Detach
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Returns the BSTR wrapped by a _bstr_t and detaches the BSTR from the _bstr_t .
Syntax
C++
Return Value
Returns the BSTR encapsulated by the _bstr_t .
Example
See _bstr_t::Assign for an example that uses Detach .
See also
_bstr_t class
_bstr_t::GetAddress
Article • 08/06/2021 • 2 minutes to read
Microsoft Specific
Frees any existing string and returns the address of a newly allocated string.
Syntax
C++
BSTR* GetAddress( );
Return Value
A pointer to the BSTR wrapped by the _bstr_t .
Remarks
GetAddress affects all _bstr_t objects that share a BSTR . More than one _bstr_t can
share a BSTR through the use of the copy constructor and operator= .
Example
See _bstr_t::Assign for an example that uses GetAddress .
See also
_bstr_t class
_bstr_t::GetBSTR
Article • 08/06/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
BSTR& GetBSTR( );
Return Value
The beginning of the BSTR wrapped by the _bstr_t .
Remarks
GetBSTR affects all _bstr_t objects that share a BSTR . More than one _bstr_t can share
Example
See _bstr_t::Assign for an example that uses GetBSTR .
See also
_bstr_t class
_bstr_t::length
Article • 08/06/2021 • 2 minutes to read
Microsoft Specific
Returns the number of characters in the _bstr_t , not including the terminating null, of
the encapsulated BSTR .
Syntax
C++
Remarks
END Microsoft Specific
See also
_bstr_t class
_bstr_t::operator =
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
Parameters
s1
A _bstr_t object to be assigned to an existing _bstr_t object.
s2
A multibyte string to be assigned to an existing _bstr_t object.
s3
var
Example
See _bstr_t::Assign for an example that uses operator= .
See also
_bstr_t class
_bstr_t::operator += , _bstr_t::operator
+
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Appends characters to the end of the _bstr_t object, or concatenates two strings.
Syntax
C++
Parameters
s1
A _bstr_t object.
s2
A multibyte string.
s3
A Unicode string.
Remarks
These operators perform string concatenation:
See also
_bstr_t class
_bstr_t::operator !
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
Return Value
It returns true if the encapsulated BSTR is a NULL string, false if not.
See also
_bstr_t class
_bstr_t relational operators
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
Remarks
These operators compare two _bstr_t objects lexicographically. The operators return
true if the comparisons hold, otherwise return false .
See also
_bstr_t class
_bstr_t::wchar_t* , _bstr_t::char*
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
Remarks
These operators can be used to extract the character data that's encapsulated by the
BSTR object. Assigning a new value to the returned pointer does not modify the original
BSTR data.
See also
_bstr_t class
_com_error class
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Construction
Name Description
Operators
Name Description
Extractor functions
Name Description
WCode Retrieves the 16-bit error code mapped into the encapsulated HRESULT .
IErrorInfo functions
Name Description
Name Description
ErrorMessage Retrieves the string message for HRESULT stored in the _com_error object.
Name Description
Requirements
Header: <comdef.h>
See also
Compiler COM support classes
IErrorInfo interface
_com_error member functions
Article • 11/18/2022 • 2 minutes to read
For information about the _com_error member functions, see _com_error class.
See also
_com_error class
_com_error::_com_error
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
_com_error(
HRESULT hr,
IErrorInfo* perrinfo = NULL,
bool fAddRef = false) throw();
Parameters
hr
HRESULT information.
perrinfo
IErrorInfo object.
fAddRef
The default causes the constructor to not call AddRef on a non-null IErrorInfo
interface. This behavior provides for correct reference counting in the common case
where ownership of the interface is passed into the _com_error object, such as:
C++
If you don't want your code to transfer ownership to the _com_error object, and the
AddRef is required to offset the Release in the _com_error destructor, construct the
object as follows:
C++
_com_error err(hr, perrinfo, true);
that
Remarks
The first constructor creates a new object given an HRESULT and optional IErrorInfo
object. The second creates a copy of an existing _com_error object.
See also
_com_error class
_com_error::Description
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
Return value
Returns the result of IErrorInfo::GetDescription for the IErrorInfo object recorded
within the _com_error object. The resulting BSTR is encapsulated in a _bstr_t object. If
no IErrorInfo is recorded, it returns an empty _bstr_t .
Remarks
Calls the IErrorInfo::GetDescription function and retrieves IErrorInfo recorded within
the _com_error object. Any failure while calling the IErrorInfo::GetDescription method
is ignored.
See also
_com_error class
_com_error::Error
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
Return value
Raw HRESULT item passed into the constructor.
Remarks
Retrieves the encapsulated HRESULT item in a _com_error object.
See also
_com_error class
_com_error::ErrorInfo
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
Return value
Raw IErrorInfo item passed into the constructor.
Remarks
Retrieves the encapsulated IErrorInfo item in a _com_error object, or NULL if no
IErrorInfo item is recorded. The caller must call Release on the returned object when
finished using it.
See also
_com_error class
_com_error::ErrorMessage
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Retrieves the string message for HRESULT stored in the _com_error object.
Syntax
C++
Return value
Returns the string message for the HRESULT recorded within the _com_error object. If
the HRESULT is a mapped 16-bit wCode, then a generic message " IDispatch error #
<wCode> " is returned. If no message is found, then a generic message " Unknown error #
<hresult> " is returned. The returned string is either a Unicode or multibyte string,
Remarks
Retrieves the appropriate system message text for HRESULT recorded within the
_com_error object. The system message text is obtained by calling the Win32
FormatMessage function. The string returned is allocated by the FormatMessage API, and
it's released when the _com_error object is destroyed.
See also
_com_error class
_com_error::GUID
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
Return value
Returns the result of IErrorInfo::GetGUID for the IErrorInfo object recorded within the
_com_error object. If no IErrorInfo object is recorded, it returns GUID_NULL .
Remarks
Any failure while calling the IErrorInfo::GetGUID method is ignored.
See also
_com_error class
_com_error::HelpContext
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
Return value
Returns the result of IErrorInfo::GetHelpContext for the IErrorInfo object recorded
within the _com_error object. If no IErrorInfo object is recorded, it returns a zero.
Remarks
Any failure while calling the IErrorInfo::GetHelpContext method is ignored.
See also
_com_error class
_com_error::HelpFile
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
Return value
Returns the result of IErrorInfo::GetHelpFile for the IErrorInfo object recorded
within the _com_error object. The resulting BSTR is encapsulated in a _bstr_t object. If
no IErrorInfo is recorded, it returns an empty _bstr_t .
Remarks
Any failure while calling the IErrorInfo::GetHelpFile method is ignored.
See also
_com_error class
_com_error::HRESULTToWCode
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
Parameters
hr
The 32-bit HRESULT to be mapped to 16-bit wCode .
Return value
16-bit wCode mapped from the 32-bit HRESULT .
Remarks
For more information, see _com_error::WCode.
See also
_com_error::WCode
_com_error::WCodeToHRESULT
_com_error class
_com_error::Source
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
Return value
Returns the result of IErrorInfo::GetSource for the IErrorInfo object recorded within
the _com_error object. The resulting BSTR is encapsulated in a _bstr_t object. If no
IErrorInfo is recorded, it returns an empty _bstr_t .
Remarks
Any failure while calling the IErrorInfo::GetSource method is ignored.
See also
_com_error class
_com_error::WCode
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Retrieves the 16-bit error code mapped into the encapsulated HRESULT .
Syntax
C++
Return value
If the HRESULT is within the range 0x80040200 to 0x8004FFFF, the WCode method returns
the HRESULT minus 0x80040200; otherwise, it returns zero.
Remarks
The WCode method is used to undo a mapping that happens in the COM support code.
The wrapper for a dispinterface property or method calls a support routine that
packages the arguments and calls IDispatch::Invoke . Upon return, if a failure HRESULT
of DISP_E_EXCEPTION is returned, the error information is retrieved from the EXCEPINFO
structure passed to IDispatch::Invoke . The error code can either be a 16-bit value
stored in the wCode member of the EXCEPINFO structure or a full 32-bit value in the
scode member of the EXCEPINFO structure. If a 16-bit wCode is returned, it must first be
See also
_com_error::HRESULTToWCode
_com_error::WCodeToHRESULT
_com_error class
_com_error::WCodeToHRESULT
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
Parameters
wCode
The 16-bit wCode to be mapped to 32-bit HRESULT .
Return value
32-bit HRESULT mapped from the 16-bit wCode .
Remarks
See the WCode member function.
See also
_com_error::WCode
_com_error::HRESULTToWCode
_com_error class
_com_error operators
Article • 11/18/2022 • 2 minutes to read
See also
_com_error class
_com_error::operator=
Article • 11/18/2022 • 2 minutes to read
Microsoft Specific
Syntax
C++
_com_error& operator=(
const _com_error& that
) throw ();
Parameters
that
A _com_error object.
See also
_com_error class
_com_ptr_t Class
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
C++
_COM_SMARTPTR_TYPEDEF(IMyInterface, __uuidof(IMyInterface));
A set of function templates, not members of this template class, support comparisons
with a smart pointer on the right side of the comparison operator.
Construction
Name Description
Low-Level Operations
Name Description
AddRef Calls the AddRef member function of IUnknown on the encapsulated interface
pointer.
Release Calls the Release member function of IUnknown on the encapsulated interface
pointer.
Operators
Name Description
operators ==, !=, <, >, Compare the smart pointer object to another smart pointer, raw
<=, >= interface pointer, or NULL.
Requirements
Header: <comip.h>
Lib: comsuppw.lib or comsuppwd.lib (see /Zc:wchar_t (wchar_t Is Native Type) for more
information)
See also
Compiler COM Support Classes
_com_ptr_t Member Functions
Article • 08/03/2021 • 2 minutes to read
For information about the _com_ptr_t member functions, see _com_ptr_t Class.
See also
_com_ptr_t Class
_com_ptr_t::_com_ptr_t
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
// Default constructor.
// Constructs a NULL smart pointer.
_com_ptr_t() throw();
Parameters
pInterface
A raw interface pointer.
fAddRef
If true , AddRef is called to increment the reference count of the encapsulated interface
pointer.
cp
A _com_ptr_t object.
p
A raw interface pointer, its type being different from the smart pointer type of this
_com_ptr_t object.
varSrc
A _variant_t object.
clsid
The CLSID of a coclass.
dwClsContext
Context for running executable code.
lpcStr
A multibyte string that holds either a CLSID (starting with "{") or a ProgID .
pOuter
The outer unknown for aggregation.
END Microsoft Specific
See also
_com_ptr_t Class
_com_ptr_t::AddRef
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Calls the AddRef member function of IUnknown on the encapsulated interface pointer.
Syntax
C++
void AddRef( );
Remarks
Calls IUnknown::AddRef on the encapsulated interface pointer, raising an E_POINTER error
if the pointer is NULL.
See also
_com_ptr_t Class
_com_ptr_t::Attach
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
Parameters
pInterface
A raw interface pointer.
fAddRef
If it is true , then AddRef is called. If it is false , the _com_ptr_t object takes ownership
of the raw interface pointer without calling AddRef .
Remarks
Attach( pInterface ) AddRef is not called. The ownership of the interface is passed to
this _com_ptr_t object. Release is called to decrement the reference count for the
previously encapsulated pointer.
AddRef . Release is called to decrement the reference count for the previously
encapsulated pointer.
See also
_com_ptr_t Class
_com_ptr_t::CreateInstance
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
HRESULT CreateInstance(
const CLSID& rclsid,
IUnknown* pOuter=NULL,
DWORD dwClsContext = CLSCTX_ALL
) throw( );
HRESULT CreateInstance(
LPCWSTR clsidString,
IUnknown* pOuter=NULL,
DWORD dwClsContext = CLSCTX_ALL
) throw( );
HRESULT CreateInstance(
LPCSTR clsidStringA,
IUnknown* pOuter=NULL,
DWORD dwClsContext = CLSCTX_ALL
) throw( );
Parameters
rclsid
The CLSID of an object.
clsidString
A Unicode string that holds either a CLSID (starting with "{") or a ProgID .
clsidStringA
A multibyte string, using the ANSI code page, that holds either a CLSID (starting with "
{") or a ProgID .
dwClsContext
Context for running executable code.
pOuter
The outer unknown for aggregation.
Remarks
These member functions call CoCreateInstance to create a new COM object and then
queries for this smart pointer's interface type. The resulting pointer is then encapsulated
within this _com_ptr_t object. Release is called to decrement the reference count for
the previously encapsulated pointer. This routine returns the HRESULT to indicate
success or failure.
See also
_com_ptr_t Class
_com_ptr_t::Detach
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
Remarks
Extracts and returns the encapsulated interface pointer, and then clears the
encapsulated pointer storage to NULL. This removes the interface pointer from
encapsulation. It is up to you to call Release on the returned interface pointer.
See also
_com_ptr_t Class
_com_ptr_t::GetActiveObject
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
HRESULT GetActiveObject(
const CLSID& rclsid
) throw( );
HRESULT GetActiveObject(
LPCWSTR clsidString
) throw( );
HRESULT GetActiveObject(
LPCSTR clsidStringA
) throw( );
Parameters
rclsid
The CLSID of an object.
clsidString
A Unicode string that holds either a CLSID (starting with "{") or a ProgID .
clsidStringA
A multibyte string, using the ANSI code page, that holds either a CLSID (starting with "
{") or a ProgID .
Remarks
These member functions call GetActiveObject to retrieve a pointer to a running object
that has been registered with OLE and then queries for this smart pointer's interface
type. The resulting pointer is then encapsulated within this _com_ptr_t object. Release
is called to decrement the reference count for the previously encapsulated pointer. This
routine returns the HRESULT to indicate success or failure.
GetActiveObject( rclsid ) Attaches to an existing instance of an object given a
CLSID .
See also
_com_ptr_t Class
_com_ptr_t::GetInterfacePtr
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
Remarks
Returns the encapsulated interface pointer, which may be NULL.
See also
_com_ptr_t Class
_com_ptr_t::QueryInterface
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
Parameters
iid
IID of an interface pointer.
p
Raw interface pointer.
Remarks
Calls IUnknown::QueryInterface on the encapsulated interface pointer with the specified
IID and returns the resulting raw interface pointer in p. This routine returns the
HRESULT to indicate success or failure.
See also
_com_ptr_t Class
_com_ptr_t::Release
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Calls the Release member function of IUnknown on the encapsulated interface pointer.
Syntax
C++
void Release( );
Remarks
Calls IUnknown::Release on the encapsulated interface pointer, raising an E_POINTER
error if this interface pointer is NULL.
See also
_com_ptr_t Class
_com_ptr_t Operators
Article • 08/03/2021 • 2 minutes to read
See also
_com_ptr_t Class
_com_ptr_t::operator =
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
template<typename _OtherIID>
_com_ptr_t& operator=( const _com_ptr_t<_OtherIID>& p );
Remarks
Assigns an interface pointer to this _com_ptr_t object.
See also
_com_ptr_t Class
_com_ptr_t Relational Operators
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Compare the smart pointer object to another smart pointer, raw interface pointer, or
NULL.
Syntax
template<typename _OtherIID>
bool operator==( const _com_ptr_t<_OtherIID>& p );
template<typename _OtherIID>
bool operator==( _com_ptr_t<_OtherIID>& p );
template<typename _InterfaceType>
bool operator==( _InterfaceType* p );
template<>
bool operator==( Interface* p );
template<>
bool operator==( const _com_ptr_t& p ) throw();
template<>
bool operator==( _com_ptr_t& p ) throw();
template<typename _OtherIID>
bool operator!=( const _com_ptr_t<_OtherIID>& p );
template<typename _OtherIID>
bool operator!=( _com_ptr_t<_OtherIID>& p );
template<typename _InterfaceType>
bool operator!=( _InterfaceType* p );
template<typename _OtherIID>
bool operator<( const _com_ptr_t<_OtherIID>& p );
template<typename _OtherIID>
bool operator<( _com_ptr_t<_OtherIID>& p );
template<typename _InterfaceType>
bool operator<( _InterfaceType* p );
template<typename _OtherIID>
bool operator>( const _com_ptr_t<_OtherIID>& p );
template<typename _OtherIID>
bool operator>(_com_ptr_t< _OtherIID>& p );
template<typename _InterfaceType>
bool operator>( _InterfaceType* p );
template<typename _OtherIID>
bool operator<=( const _com_ptr_t<_OtherIID>& p );
template<typename _OtherIID>
bool operator<=( _com_ptr_t<_OtherIID>& p );
template<typename _InterfaceType>
bool operator<=( _InterfaceType* p );
template<typename _OtherIID>
bool operator>=( const _com_ptr_t<_OtherIID>& p );
template<typename _OtherIID>
bool operator>=( _com_ptr_t<_OtherIID>& p );
template<typename _InterfaceType>
bool operator>=( _InterfaceType* p );
Remarks
Compares a smart pointer object to another smart pointer, raw interface pointer, or
NULL. Except for the NULL pointer tests, these operators first query both pointers for
IUnknown , and compare the results.
See also
_com_ptr_t Class
_com_ptr_t Extractors
Article • 08/03/2021 • 2 minutes to read
Microsoft-specific
Syntax
c++
Remarks
operator Interface* Returns the encapsulated interface pointer, which may be
NULL.
operator* Allows a smart pointer object to act as though it were the actual
encapsulated interface when dereferenced.
operator-> Allows a smart pointer object to act as though it were the actual
encapsulated interface when dereferenced.
operator& Releases any encapsulated interface pointer, replacing it with NULL, and
returns the address of the encapsulated pointer. This operator allows you to pass
the smart pointer by address to a function that has an out parameter through
which it returns an interface pointer.
7 Note
Because operator bool is not declared as explicit , _com_ptr_t is implicitly
convertible to bool , which is convertible to any scalar type. This can have
unexpected consequences in your code. Enable Compiler Warning (level 4)
C4800 to prevent unintentional use of this conversion.
See also
_com_ptr_t class
Relational Function Templates
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
Parameters
i
A raw interface pointer.
p
A smart pointer.
Remarks
These function templates allow comparison with a smart pointer on the right side of the
comparison operator. These are not member functions of _com_ptr_t .
See also
_com_ptr_t Class
_variant_t Class
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
A _variant_t object encapsulates the VARIANT data type. The class manages resource
allocation and deallocation and makes function calls to VariantInit and VariantClear
as appropriate.
Construction
Name Description
Operations
Name Description
ChangeType Changes the type of the _variant_t object to the indicated VARTYPE .
Detach Detaches the encapsulated VARIANT object from this _variant_t object.
Operators
Name Description
Requirements
Header: <comutil.h>
Lib: comsuppw.lib or comsuppwd.lib (see /Zc:wchar_t (wchar_t Is Native Type) for more
information)
See also
Compiler COM Support Classes
_variant_t Member Functions
Article • 08/03/2021 • 2 minutes to read
For information about the _variant_t member functions, see _variant_t Class.
See also
_variant_t Class
_variant_t::_variant_t
Article • 12/09/2021 • 4 minutes to read
Microsoft Specific
Syntax
C++
_variant_t( ) throw( );
_variant_t(
const VARIANT& varSrc
);
_variant_t(
const VARIANT* pVarSrc
);
_variant_t(
const _variant_t& var_t_Src
);
_variant_t(
VARIANT& varSrc,
bool fCopy
);
_variant_t(
short sSrc,
VARTYPE vtSrc = VT_I2
);
_variant_t(
long lSrc,
VARTYPE vtSrc = VT_I4
);
_variant_t(
float fltSrc
) throw( );
_variant_t(
double dblSrc,
VARTYPE vtSrc = VT_R8
);
_variant_t(
const CY& cySrc
) throw( );
_variant_t(
const _bstr_t& bstrSrc
);
_variant_t(
const wchar_t *wstrSrc
);
_variant_t(
const char* strSrc
);
_variant_t(
IDispatch* pDispSrc,
bool fAddRef = true
) throw( );
_variant_t(
bool bSrc
) throw( );
_variant_t(
IUnknown* pIUknownSrc,
bool fAddRef = true
) throw( );
_variant_t(
const DECIMAL& decSrc
) throw( );
_variant_t(
BYTE bSrc
) throw( );
variant_t(
char cSrc
) throw();
_variant_t(
unsigned short usSrc
) throw();
_variant_t(
unsigned long ulSrc
) throw();
_variant_t(
int iSrc
) throw();
_variant_t(
unsigned int uiSrc
) throw();
_variant_t(
__int64 i8Src
) throw();
_variant_t(
unsigned __int64 ui8Src
) throw();
Parameters
varSrc
A VARIANT object to be copied into the new _variant_t object.
pVarSrc
var_t_Src
fCopy
If false , the supplied VARIANT object is attached to the new _variant_t object without
making a new copy by VariantCopy .
ISrc , sSrc
vtSrc
fltSrc , dblSrc
cySrc
A CY object to be copied into the new _variant_t object.
bstrSrc
A _bstr_t object to be copied into the new _variant_t object.
strSrc , wstrSrc
pIUknownSrc
pDispSrc
decSrc
A DECIMAL value to be copied into the new _variant_t object.
bSrc
cSrc
usSrc
ulSrc
A unsigned long value to be copied into the new _variant_t object.
iSrc
An int value to be copied into the new _variant_t object.
uiSrc
An unsigned int value to be copied into the new _variant_t object.
i8Src
ui8Src
Remarks
_variant_t() Constructs an empty _variant_t object, VT_EMPTY .
_variant_t( VARIANT& varSrc ) Constructs a _variant_t object from a copy of the
of type VT_I2 or VT_BOOL from a short integer value. Any other VARTYPE results in
an E_INVALIDARG error.
of type VT_I4 , VT_BOOL , or VT_ERROR from a long integer value. Any other VARTYPE
results in an E_INVALIDARG error.
object of type VT_R8 or VT_DATE from a double numerical value. Any other
VARTYPE results in an E_INVALIDARG error.
Release that will occur when the _variant_t object is destroyed. It is up to you to
call Release on the supplied interface pointer. If fAddRef is false , this constructor
takes ownership of the supplied interface pointer; don't call Release on the
supplied interface pointer.
object of type VT_DISPATCH from a COM interface pointer. If fAddRef is true , then
AddRef is called on the supplied interface pointer to match the call to Release that
will occur when the _variant_t object is destroyed. It's up to you to call Release
on the supplied interface pointer. If fAddRef is false , this constructor takes
ownership of the supplied interface pointer; don't call Release on the supplied
interface pointer.
See also
_variant_t Class
_variant_t::Attach
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
Parameters
varSrc
A VARIANT object to be attached to this _variant_t object.
Remarks
Takes ownership of the VARIANT by encapsulating it. This member function releases any
existing encapsulated VARIANT , then copies the supplied VARIANT , and sets its VARTYPE
to VT_EMPTY to make sure its resources can only be released by the _variant_t
destructor.
See also
_variant_t Class
_variant_t::Clear
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
void Clear( );
Remarks
Calls VariantClear on the encapsulated VARIANT object.
See also
_variant_t Class
_variant_t::ChangeType
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
void ChangeType(
VARTYPE vartype,
const _variant_t* pSrc = NULL
);
Parameters
vartype
The VARTYPE for this _variant_t object.
pSrc
A pointer to the _variant_t object to be converted. If this value is NULL, conversion is
done in place.
Remarks
This member function converts a _variant_t object into the indicated VARTYPE . If pSrc is
NULL, the conversion is done in place, otherwise this _variant_t object is copied from
pSrc and then converted.
See also
_variant_t Class
_variant_t::Detach
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
VARIANT Detach( );
Return Value
The encapsulated VARIANT .
Remarks
Extracts and returns the encapsulated VARIANT , then clears this _variant_t object
without destroying it. This member function removes the VARIANT from encapsulation
and sets the VARTYPE of this _variant_t object to VT_EMPTY. It is up to you to release
the returned VARIANT by calling the VariantClear function.
See also
_variant_t Class
_variant_t::SetString
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
C++
Parameters
pSrc
Pointer to the character string.
Remarks
Converts an ANSI character string to a Unicode BSTR string and assigns it to this
_variant_t object.
See also
_variant_t Class
_variant_t Operators
Article • 08/03/2021 • 2 minutes to read
See also
_variant_t Class
_variant_t::operator=
Article • 08/03/2021 • 2 minutes to read
Syntax
C++
Parameters
varSrc
A reference to a VARIANT from which to copy the content and VT_* type.
pVarSrc
A pointer to a VARIANT from which to copy the content and VT_* type.
var_t_Src
A reference to a _variant_t from which to copy the content and VT_* type.
sSrc
A short integer value to copy. Given type VT_BOOL if *this is of type VT_BOOL .
Otherwise, it's given type VT_I2 .
lSrc
A long integer value to copy. Given type VT_BOOL if *this is of type VT_BOOL . Given type
VT_ERROR if *this is of type VT_ERROR . Otherwise, given type VT_I4 .
fltSrc
A float numerical value to copy. Given type VT_R4 .
dblSrc
A double numerical value to copy. Given type VT_DATE if this is of type VT_DATE .
Otherwise, given type VT_R8 .
cySrc
A CY object to copy. Given type VT_CY .
bstrSrc
A BSTR object to copy. Given type VT_BSTR .
wstrSrc
strSrc
pDispSrc
bSrc
pSrc
An IUnknown pointer to copy with a call to AddRef . Given type VT_UNKNOWN .
decSrc
A DECIMAL object to copy. Given type VT_DECIMAL .
byteSrc
usSrc
ulSrc
iSrc
An int value to copy. Given type VT_INT .
uiSrc
An unsigned int value to copy. Given type VT_UINT .
i8Src
ui8Src
An unsigned __int64 or unsigned long long value to copy. Given type VT_UI8 .
Remarks
The operator= assignment operator clears any existing value, which deletes object
types, or calls Release for IDispatch* and IUnknown* types. Then, it copies a new value
into the _variant_t object. It changes the _variant_t type to match the assigned value,
except as noted for short , long , and double arguments. Value types are copied directly.
A VARIANT or _variant_t pointer or reference argument copies the assigned object's
contents and type. Other pointer or reference type arguments create a copy of the
assigned object. The assignment operator calls AddRef for IDispatch* and IUnknown*
arguments.
See also
_variant_t class
_variant_t Relational Operators
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
bool operator==(
const VARIANT& varSrc) const;
bool operator==(
const VARIANT* pSrc) const;
bool operator!=(
const VARIANT& varSrc) const;
bool operator!=(
const VARIANT* pSrc) const;
Parameters
varSrc
A VARIANT to be compared with the _variant_t object.
pSrc
Pointer to the VARIANT to be compared with the _variant_t object.
Return Value
Returns true if comparison holds, false if not.
Remarks
Compares a _variant_t object with a VARIANT , testing for equality or inequality.
See also
_variant_t Class
_variant_t Extractors
Article • 08/03/2021 • 2 minutes to read
Microsoft Specific
Syntax
Remarks
Extracts raw data from an encapsulated VARIANT . If the VARIANT is not already the proper
type, VariantChangeType is used to attempt a conversion, and an error is generated
upon failure:
to free it.
See also
_variant_t Class
Microsoft Extensions
Article • 01/25/2023 • 2 minutes to read
asm-statement :
__asm assembly-instruction ; opt
assembly-instruction-list :
assembly-instruction ; opt
ms-modifier-list :
ms-modifier :
__cdecl
__fastcall
__stdcall
based-modifier
based-modifier :
__based ( based-type )
based-type :
name
Nonstandard Behavior
Article • 09/21/2021 • 2 minutes to read
The following sections list some of the places where the Microsoft implementation of
C++ doesn't conform to the C++ standard. The section numbers given below refer to
the section numbers in the C++ 11 standard (ISO/IEC 14882:2011(E)).
The list of compiler limits that differ from those defined in the C++ standard is given in
Compiler Limits.
C++
// CovariantReturn.cpp
class A
{
virtual A* f(int c, ...); // remove ...
};
class B : virtual A
{
B* f(int c, ...); // C2688 remove ...
};
C++
#include <iostream>
using namespace std;
namespace N {
void f(int) { cout << "f(int)" << endl;}
}
namespace N {
void f(char) { cout << "f(char)" << endl;}
}
int main() {
g('c');
}
// Output: f(char)
C++
char_traits::eof()
The C++ standard states that char_traits::eof must not correspond to a valid char_type
value. The Microsoft C++ compiler enforces this constraint for type char , but not for
type wchar_t . This doesn't conform to the requirement in Table 62 in section 12.1.1 of
the C++ 11 ISO specification. The example below demonstrates this behavior.
C++
#include <iostream>
int main()
{
using namespace std;
The C++ standard recommends limits for various language constructs. The following is a
list of cases where the Microsoft C++ compiler does not implement the recommended
limits. The first number is the limit that is established in the ISO C++ 11 standard
(INCITS/ISO/IEC 14882-2011[2012], Annex B) and the second number is the limit
implemented by the Microsoft C++ compiler:
Parameters in one macro definition - C++ standard: 256, Microsoft C++ compiler:
127.
Arguments in one macro invocation - C++ standard: 256, Microsoft C++ compiler
127.
Scope qualifications of one identifier - C++ standard: 256, Microsoft C++ compiler:
127.
See also
Nonstandard Behavior
C/C++ preprocessor reference
Article • 08/03/2021
In Visual Studio 2019 the /Zc:preprocessor compiler option provides a fully conformant
C11 and C17 preprocessor. This is the default when you use the compiler flag /std:c11
or /std:c17 .
In this section
Preprocessor
Provides an overview of the traditional and new conforming preprocessors.
Preprocessor directives
Describes directives, typically used to make source programs easy to change and easy to
compile in different execution environments.
Preprocessor operators
Discusses the four preprocessor-specific operators used in the context of the #define
directive.
Predefined macros
Discusses predefined macros as specified by the C and C++ standards and by Microsoft
C++.
Pragmas
Discusses pragmas, which offer a way for each compiler to offer machine- and operating
system-specific features while retaining overall compatibility with the C and C++
languages.
Related sections
C++ language reference
Provides reference material for the Microsoft implementation of the C++ language.
C language reference
Provides reference material for the Microsoft implementation of the C language.
A C++ program can call on a large number of functions from this conforming
implementation of the C++ Standard Library. These functions perform services such as
input and output and provide efficient implementations of frequently used operations.
For more information about linking with the appropriate Visual C++ runtime .lib file,
see C runtime (CRT) and C++ Standard Library (STL) .lib files.
7 Note
From a historical perspective, "STL" originally referred to the Standard Template Library
written by Alexander Stepanov. Parts of that library were standardized in the C++
Standard Library, along with the ISO C runtime library, parts of the Boost library, and
other functionality. Sometimes "STL" is used to refer to the containers and algorithms
parts of the C++ Standard Library adapted from Stepanov's STL. In this documentation,
Standard Template Library (STL) refers to the C++ Standard Library as a whole.
In this section
C++ Standard Library overview Provides an overview of the Microsoft implementation of
the C++ Standard Library.
Header files reference Provides links to reference topics about the C++ Standard Library
header files, with code examples.