Skip to content

Commit eed9ea9

Browse files
author
Colin Robertson
authored
Merge pull request #3936 from MicrosoftDocs/main637895289119512867
Repo sync for protected CLA branch
2 parents 8dd9068 + 1df2ccc commit eed9ea9

File tree

4 files changed

+256
-187
lines changed

4 files changed

+256
-187
lines changed
Lines changed: 90 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
description: "Learn more about: _set_new_handler"
33
title: "_set_new_handler"
4-
ms.date: "4/2/2020"
4+
ms.date: 05/21/2022
55
api_name: ["_set_new_handler", "_o__set_new_handler"]
66
api_location: ["msvcrt.dll", "msvcr80.dll", "msvcr90.dll", "msvcr100.dll", "msvcr100_clr0400.dll", "msvcr110.dll", "msvcr110_clr0400.dll", "msvcr120.dll", "msvcr120_clr0400.dll", "ucrtbase.dll", "api-ms-win-crt-runtime-l1-1-0.dll", "api-ms-win-crt-private-l1-1-0.dll"]
77
api_type: ["DLLExport"]
@@ -10,9 +10,9 @@ f1_keywords: ["_set_new_handler", "set_new_handler"]
1010
helpviewer_keywords: ["_set_new_handler function", "set_new_handler function", "error handling", "transferring control to error handler"]
1111
ms.assetid: 1d1781b6-5cf8-486a-b430-f365e0bb023f
1212
---
13-
# _set_new_handler
13+
# `_set_new_handler`
1414

15-
Transfers control to your error-handling mechanism if the **`new`** operator fails to allocate memory.
15+
Transfers control to your error-handling mechanism if the **`new`** operator fails to allocate memory. The Microsoft C++ compiler uses this function to implement [`std::set_new_handler`](../../standard-library/new-functions.md#set_new_handler) in the standard library.
1616

1717
## Syntax
1818

@@ -22,27 +22,25 @@ _PNH _set_new_handler( _PNH pNewHandler );
2222
2323
### Parameters
2424
25-
*pNewHandler*<br/>
26-
Pointer to the application-supplied memory handling function. An argument of 0 causes the new handler to be removed.
25+
*`pNewHandler`*\
26+
Pointer to the application-supplied memory handling function. An argument of 0 or `nullptr` causes the new handler to be removed.
2727
28-
## Return Value
28+
## Return value
2929
30-
Returns a pointer to the previous exception handling function registered by **_set_new_handler**, so that the previous function can be restored later. If no previous function has been set, the return value can be used to restore the default behavior; this value can be **NULL**.
30+
Returns a pointer to the previous exception handling function registered by **`_set_new_handler`**, so that the previous function can be restored later. If no previous function has been set, the return value can be used to restore the default behavior. This value can be `nullptr` or 0.
3131
3232
## Remarks
3333
34-
The C++ **_set_new_handler** function specifies an exception-handling function that gains control if the **`new`** operator fails to allocate memory. If **`new`** fails, the run-time system automatically calls the exception-handling function that was passed as an argument to **_set_new_handler**. **_PNH**, defined in New.h, is a pointer to a function that returns type **`int`** and takes an argument of type **size_t**. Use **size_t** to specify the amount of space to be allocated.
34+
The C++ **`_set_new_handler`** function specifies an exception-handling function that gains control if the **`new`** operator fails to allocate memory. If **`new`** fails, the run-time system automatically calls the exception-handling function that was passed as an argument to **`_set_new_handler`**. **`_PNH`**, defined in `<new.h>`, is a pointer to a function that returns type **`int`** and takes an argument of type **`size_t`**. Use **`size_t`** to specify the amount of space to be allocated.
3535
36-
There is no default handler.
36+
There's no default handler.
3737
38-
**_set_new_handler** is essentially a garbage-collection scheme. The run-time system retries allocation each time your function returns a nonzero value and fails if your function returns 0.
38+
**`_set_new_handler`** is essentially a garbage-collection scheme. The run-time system retries allocation each time your function returns a nonzero value and fails if your function returns 0.
3939
40-
An occurrence of the **_set_new_handler** function in a program registers the exception-handling function specified in the argument list with the run-time system:
40+
An occurrence of the **`_set_new_handler`** function in a program registers the exception-handling function specified in the argument list with the run-time system:
4141
4242
```cpp
43-
// set_new_handler1.cpp
44-
By default, this function's global state is scoped to the application. To change this, see [Global state in the CRT](../global-state.md).
45-
43+
// _set_new_handler1.cpp
4644
#include <new.h>
4745
4846
int handle_program_memory_depletion( size_t )
@@ -57,7 +55,9 @@ int main( void )
5755
}
5856
```
5957

60-
You can save the function address that was last passed to the **_set_new_handler** function and reinstate it later:
58+
By default, the **`_set_new_handler`** function's global state is scoped to the application. To change it, see [Global state in the CRT](../global-state.md).
59+
60+
You can save the function address that was last passed to the **`_set_new_handler`** function and reinstate it later:
6161

6262
```cpp
6363
_PNH old_handler = _set_new_handler( my_handler );
@@ -68,81 +68,109 @@ You can save the function address that was last passed to the **_set_new_handler
6868
// . . .
6969
```
7070
71-
The C++ [_set_new_mode](set-new-mode.md) function sets the new handler mode for [malloc](malloc.md). The new handler mode indicates whether, on failure, **malloc** is to call the new handler routine as set by **_set_new_handler**. By default, **malloc** does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when **malloc** fails to allocate memory, **malloc** calls the new handler routine in the same way that the **`new`** operator does when it fails for the same reason. To override the default, call:
71+
The C++ [`_set_new_mode`](set-new-mode.md) function sets the new handler mode for [`malloc`](malloc.md). The new handler mode indicates whether, on failure, **`malloc`** is to call the new handler routine as set by **`_set_new_handler`**. By default, **`malloc`** doesn't call the new handler routine on failure to allocate memory. You can override this default behavior so that, when **`malloc`** fails to allocate memory, **`malloc`** calls the new handler routine in the same way that the **`new`** operator does when it fails for the same reason. To override the default, call `_set_new_mode(1);` early in your program or link with *`newmode.obj`*.
7272
73-
```cpp
74-
_set_new_mode(1);
75-
```
73+
If a user-defined `operator new` is provided, the new handler functions aren't automatically called on failure.
7674
77-
early in your program or link with Newmode.obj.
75+
For more information, see [`new`](../../cpp/new-operator-cpp.md) and [`delete`](../../cpp/delete-operator-cpp.md) in the *C++ Language Reference*.
7876
79-
If a user-defined `operator new` is provided, the new handler functions are not automatically called on failure.
80-
81-
For more information, see [new](../../cpp/new-operator-cpp.md) and [delete](../../cpp/delete-operator-cpp.md) in the *C++ Language Reference*.
82-
83-
There is a single **_set_new_handler** handler for all dynamically linked DLLs or executables; even if you call **_set_new_handler** your handler might be replaced by another or that you are replacing a handler set by another DLL or executable.
77+
There's a single **`_set_new_handler`** handler for all dynamically linked DLLs or executables in a single process. Even if you call **`_set_new_handler`**, your handler might be replaced by another. Or, your new handler may replace a handler set by another DLL or executable in your process.
8478
8579
## Requirements
8680
87-
|Routine|Required header|
88-
|-------------|---------------------|
89-
|**_set_new_handler**|\<new.h>|
81+
| Function | Required header |
82+
|--|--|
83+
| **`_set_new_handler`** | `<new.h>` |
9084
9185
For more compatibility information, see [Compatibility](../../c-runtime-library/compatibility.md).
9286
9387
## Example
9488
95-
In this example, when the allocation fails, control is transferred to MyNewHandler. The argument passed to MyNewHandler is the number of bytes requested. The value returned from MyNewHandler is a flag indicating whether allocation should be retried: a nonzero value indicates that allocation should be retried, and a zero value indicates that allocation has failed.
89+
In this example, when the allocation fails, control is transferred to `MyNewHandler`. The argument passed to `MyNewHandler` is the number of bytes requested. The value returned from `MyNewHandler` is a flag indicating whether allocation should be retried: a nonzero value indicates that allocation should be retried, and a zero value indicates that allocation has failed.
9690
9791
```cpp
9892
// crt_set_new_handler.cpp
99-
// compile with: /c
100-
#include <stdio.h>
93+
// Build for x86.
94+
// WARNING: This code intentionally allocates memory until an allocation fails.
95+
// Running this code can cause your system to become non-responsive.
96+
#include <iostream>
97+
#include <new>
10198
#include <new.h>
102-
#define BIG_NUMBER 0x1fffffff
10399
104-
int coalesced = 0;
100+
static const int Big_number = 0x03FFFFFF;
101+
102+
struct MemoryHog {
103+
int pork[Big_number];
104+
};
105+
106+
class MemoryReserve {
107+
MemoryHog* reserved = nullptr;
108+
public:
109+
MemoryReserve() {
110+
reserved = new MemoryHog();
111+
}
112+
~MemoryReserve() noexcept {
113+
if (reserved != nullptr)
114+
delete reserved;
115+
}
116+
bool free_reserve() noexcept {
117+
if (reserved != nullptr) {
118+
delete reserved;
119+
reserved = nullptr;
120+
return true; // return true if memory freed
121+
}
122+
return false; // reserved memory exhausted.
123+
}
124+
};
125+
126+
// Global singleton for a MemoryReserve object
127+
static MemoryReserve reserve{};
105128
106-
int CoalesceHeap()
107-
{
108-
coalesced = 1; // Flag RecurseAlloc to stop
109-
// do some work to free memory
110-
return 0;
111-
}
112129
// Define a function to be called if new fails to allocate memory.
113-
int MyNewHandler( size_t size )
130+
int MyNewHandler(size_t /* unused */)
114131
{
115-
printf("Allocation failed. Coalescing heap.\n");
116-
117-
// Call a function to recover some heap space.
118-
return CoalesceHeap();
132+
// Call a function to recover some heap space. Return 1 on success.
133+
if (reserve.free_reserve()) {
134+
std::cerr << "MyNewHandler: Released reserved memory.\n";
135+
return 1;
136+
}
137+
std::cerr << "MyNewHandler: Reserved memory exhausted.\n";
138+
return 0;
119139
}
120140
121-
int RecurseAlloc() {
122-
int *pi = new int[BIG_NUMBER];
123-
if (!coalesced)
124-
RecurseAlloc();
125-
return 0;
141+
static const int max_depth = 16; // recursion depth limiter
142+
static int depth = 0;
143+
144+
void RecurseAlloc() {
145+
MemoryHog* piggy = new MemoryHog{};
146+
if (++depth < max_depth) // Recurse until memory exhausted or max_depth
147+
RecurseAlloc();
148+
depth--;
149+
delete piggy;
150+
return;
126151
}
127152
128153
int main()
129154
{
130-
// Set the failure handler for new to be MyNewHandler.
131-
_set_new_handler( MyNewHandler );
132-
RecurseAlloc();
155+
try {
156+
_set_new_handler(MyNewHandler); // Set handler for new.
157+
RecurseAlloc();
158+
}
159+
catch (std::bad_alloc& ex) {
160+
std::cerr << "bad_alloc caught: " << ex.what() << '\n';
161+
}
133162
}
134-
```
135-
136-
```Output
137-
Allocation failed. Coalescing heap.
138163
139-
This application has requested the Runtime to terminate it in an unusual way.
140-
Please contact the application's support team for more information.
164+
/* Output:
165+
MyNewHandler: Released reserved memory.
166+
MyNewHandler: Reserved memory exhausted.
167+
bad_alloc caught: bad allocation
168+
*/
141169
```
142170

143171
## See also
144172

145-
[Memory Allocation](../../c-runtime-library/memory-allocation.md)<br/>
146-
[calloc](calloc.md)<br/>
147-
[free](free.md)<br/>
148-
[realloc](realloc.md)<br/>
173+
[Memory allocation](../../c-runtime-library/memory-allocation.md)\
174+
[`calloc`](calloc.md)\
175+
[`free`](free.md)\
176+
[`realloc`](realloc.md)

docs/cpp/new-and-delete-operators.md

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
---
22
title: "new and delete operators"
33
description: "The C++ language new and delete operators allow control over allocation."
4-
ms.date: 07/07/2020
4+
ms.date: 05/21/2022
55
helpviewer_keywords: ["new keyword [C++]", "delete keyword [C++]"]
66
---
77
# `new` and `delete` operators
88

9-
C++ supports dynamic allocation and deallocation of objects using the [`new`](new-operator-cpp.md) and [`delete`](delete-operator-cpp.md) operators. These operators allocate memory for objects from a pool called the free store. The **`new`** operator calls the special function [`operator new`](new-operator-cpp.md), and the **`delete`** operator calls the special function [`operator delete`](delete-operator-cpp.md).
10-
11-
The **`new`** function in the C++ Standard Library supports the behavior specified in the C++ standard, which is to throw a `std::bad_alloc` exception if the memory allocation fails. If you still want the non-throwing version of **`new`**, link your program with *`nothrownew.obj`*. However, when you link with *`nothrownew.obj`*, the default **`operator new`** in the C++ Standard Library no longer functions.
9+
C++ supports dynamic allocation and deallocation of objects using the [`new`](new-operator-cpp.md) and [`delete`](delete-operator-cpp.md) 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`](new-operator-cpp.md), and the **`delete`** operator calls the special function [`operator delete`](delete-operator-cpp.md).
1210

1311
For a list of the library files in the C Runtime Library and the C++ Standard Library, see [CRT Library Features](../c-runtime-library/crt-library-features.md).
1412

@@ -20,9 +18,9 @@ The compiler translates a statement such as this one into a call to the function
2018
char *pch = new char[BUFFER_SIZE];
2119
```
2220

23-
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 linked in non-throwing **`operator new`** support.
21+
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.
2422

25-
You can write a routine that attempts to free memory and retry the allocation. For more information, see [`_set_new_handler`](../c-runtime-library/reference/set-new-handler.md). For details on the recovery scheme, see the [Handling insufficient memory](#handling-insufficient-memory) section.
23+
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 `new(std::nothrow)`, or if you've linked in non-throwing **`operator new`** support. For more information, see [Allocation failure behavior](#allocation-failure-behavior).
2624

2725
The two scopes for **`operator new`** functions are described in the following table.
2826

@@ -33,7 +31,7 @@ The two scopes for **`operator new`** functions are described in the following t
3331
| **`::operator new`** | Global |
3432
| *class-name* **`::operator new`** | Class |
3533

36-
The first argument to **`operator new`** must be of type `size_t`, defined in \<stddef.h>, and the return type is always **`void*`**.
34+
The first argument of **`operator new`** must be of type `size_t`, and the return type is always **`void*`**.
3735

3836
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.
3937

@@ -94,24 +92,67 @@ int main()
9492
}
9593
```
9694

95+
### Allocation failure behavior
96+
97+
The **`new`** function in the C++ Standard Library supports the behavior specified in the C++ standard since C++98. When there's insufficient memory for an allocation request, **`operator new`** throws a [`std::bad_alloc`](../standard-library/bad-alloc-class.md) exception.
98+
99+
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](../c-runtime-library/link-options.md).
100+
101+
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`](../build/reference/zc-throwingnew-assume-operator-new-throws.md).
102+
97103
### Handling insufficient memory
98104

99-
Testing for failed memory allocation can be done as shown here:
105+
The way you test for a failed allocation from a **`new`** expression depends on whether you use the standard exception mechanism, or you use a **`nullptr`** return. Standard C++ expects an allocator to throw either `std::bad_alloc` or a class derived from `std::bad_alloc`. You can handle such an exception as shown in this sample:
106+
107+
```cpp
108+
#include <iostream>
109+
#include <new>
110+
using namespace std;
111+
#define BIG_NUMBER 10000000000LL
112+
int main() {
113+
try {
114+
int *pI = new int[BIG_NUMBER];
115+
}
116+
catch (bad_alloc& ex) {
117+
cout << "Caught bad_alloc: " << ex.what() << endl;
118+
return -1;
119+
}
120+
}
121+
```
122+
123+
When you use the `nothrow` form of **`new`**, you can test for an allocation failure as shown in this sample:
124+
125+
```cpp
126+
#include <iostream>
127+
#include <new>
128+
using namespace std;
129+
#define BIG_NUMBER 10000000000LL
130+
int main() {
131+
int *pI = new(nothrow) int[BIG_NUMBER];
132+
if ( pI == nullptr ) {
133+
cout << "Insufficient memory" << endl;
134+
return -1;
135+
}
136+
}
137+
```
138+
139+
You can test for a failed memory allocation when you've used *`nothrownew.obj`* file to replace global **`operator new`** as shown here:
100140
101141
```cpp
102142
#include <iostream>
143+
#include <new>
103144
using namespace std;
104-
#define BIG_NUMBER 100000000
145+
#define BIG_NUMBER 10000000000LL
105146
int main() {
106147
int *pI = new int[BIG_NUMBER];
107-
if( pI == 0x0 ) {
148+
if ( !pI ) {
108149
cout << "Insufficient memory" << endl;
109150
return -1;
110151
}
111152
}
112153
```
113154
114-
There's another way to handle failed memory allocation requests. Write a custom recovery routine to handle such a failure, then register your function by calling the [`_set_new_handler`](../c-runtime-library/reference/set-new-handler.md) run-time function.
155+
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`](../c-runtime-library/reference/set-new-handler.md).
115156

116157
## <a id="delete_operator"> </a> The `delete` operator
117158

0 commit comments

Comments
 (0)