C++ 15 Lambda Expressions
C++ 15 Lambda Expressions
Article • 02/20/2023
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
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
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
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 • 03/25/2024
A reference, like a pointer, stores the address of an object that is located elsewhere in
memory. Unlike a pointer, a reference after it's initialized can't 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
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 and initialize 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
Feedback
Was this page helpful? Yes No
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
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
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
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
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
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
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
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
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
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
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 • 03/20/2024
The shared_ptr type is a smart pointer in the C++ standard library that is designed for
scenarios in which more than one owner needs to manage the lifetime of an object.
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
};
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 was 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 copies 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 uses 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.
C++
void test() {
auto sp = make_shared<int>(5);
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++)
Feedback
Was this page helpful? Yes No
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
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++)