C++ handling error on new
Date: 2023-02-15Last modified: 2024-02-26
Table of contents
How new works
- A new expression invokes operator new function
- operator new function will try to allocate memory
- On failure
- it throws an exception of type bad_alloc (default behavior)
- it calls a function set by set_new_handler function
- it returns NULL (if nothrow version of new is used)
- On success
- the constructor is invoked
- memory address is returned
constexpr int N = 10;
int *ptr[N]{};
// const size_t M1 = std::numeric_limits<std::size_t>::max() / 1'000'000'000;
const size_t M = 10'000'000'000;
void deleteAllNonNullPtr() {
for (int i = 0; i < N; ++i) {
if (ptr[i]) {
fmt::print("Deleting ptr[{}]\n", i);
delete[] ptr[i];
}
}
}
void testThrowException() {
try {
for (int i = 0; i < N; ++i) {
fmt::print("{}: #1 Allocating {} bytes...", i, M);
ptr[i] = new int[M];
if (ptr[i]) {
fmt::print(" OK\n");
ptr[i][0] = i; // use the allocated space
}
}
} catch (std::exception &e) {
fmt::print("\nException #1: {}", e.what());
}
deleteAllNonNullPtr();
}
void NewHandler() {
using namespace std::chrono_literals;
fmt::print("\n#2 Failure to allocate memory");
std::this_thread::sleep_for(1s);
throw std::runtime_error("NewHandler exception");
}
void testNewHandler() {
set_new_handler(NewHandler);
try {
for (int i = 0; i < N; ++i) {
fmt::print("{}: #2 Allocating {} bytes...", i, M);
ptr[i] = new int[M];
if (ptr[i]) {
fmt::print(" OK\n");
ptr[i][0] = i;
}
}
} catch (std::exception &e) {
fmt::print("\nException #2: {}", e.what());
}
deleteAllNonNullPtr();
}
void testNoThrow() {
// Equivalent to
// try { return operator new(size); } catch( ... ) { return nullptr; }
int *p = new (std::nothrow) int[M];
// You must check the value o p for nullptr
if (p == nullptr) {
fmt::print("\n#3 Failure to allocate memory");
} else {
delete[] p;
}
}
Placement new
Type *ptr = new (<memory_address>) Type{};
void testPlacementNew() {
char buf[4];
int *ptr = new (buf) int{3};
fmt::print("\nPlacement new");
fmt::print("\nValue of ptr = {}", *ptr);
fmt::print("\nAddress of ptr = {}", static_cast<void *>(ptr));
fmt::print("\nAddress of buf = {}", static_cast<void *>(buf));
}
class Reporter {
public:
Reporter() : data(0) { fmt::print("\nReporter Constructor: {}", 0); }
Reporter(size_t i) : data(i) { fmt::print("\nReporter Constructor: {}", i); }
~Reporter() { fmt::print("\nReporter Destructor {}", data); }
Reporter &operator=(const Reporter &other) {
data = other.data;
fmt::print("\nReporter assigment operator {}", data);
return *this;
}
private:
size_t data;
};
void testPlacementNew2() {
char buf[4];
const size_t SIZE = 5;
auto ptr = new (buf) Reporter{42};
// delete ptr; // Generate an error
ptr->~Reporter();
// ---
// Calls constructor one time
Reporter r1[SIZE]{11, 12, 13, 14, 15}; // RAII calls destructor
// ---
// Calls constructor (data=0)
Reporter *r2 = new Reporter[SIZE]{};
for (size_t i = 0; i < SIZE; ++i) {
// Calls constructor (data=i+20)
// Calls assigment/copy operator
// Calls destructor
r2[i] = Reporter{i + 20};
}
// No constructor called here
Reporter *ptr3 =
static_cast<Reporter *>(operator new(SIZE * sizeof(Reporter)));
for (size_t i = 0; i < SIZE; ++i) {
// Calls constructor on placement = ptr + i
new (ptr3 + i) Reporter(i + 30);
}
for (size_t i = 0; i < SIZE; ++i) {
ptr3[i].~Reporter();
}
}
```cpp
int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) {
testThrowException();
testNewHandler();
testNoThrow();
testPlacementNew();
testPlacementNew2();
return 0;
}
Possible output
0: #1 Allocating 10000000000 bytes...
Exception #1: std::bad_alloc0: #2 Allocating 10000000000 bytes...
#2 Failure to allocate memory
Exception #2: NewHandler exception
#2 Failure to allocate memory
#3 Failure to allocate memory
Placement new
Value of ptr = 3
Address of ptr = 0x7ffe142d8f4c
Address of buf = 0x7ffe142d8f4c
Reporter Constructor: 42
Reporter Destructor 42
Reporter Constructor: 11
Reporter Constructor: 12
Reporter Constructor: 13
Reporter Constructor: 14
Reporter Constructor: 15
Reporter Constructor: 0
Reporter Constructor: 0
Reporter Constructor: 0
Reporter Constructor: 0
Reporter Constructor: 0
Reporter Constructor: 20
Reporter assigment operator 20
Reporter Destructor 20
Reporter Constructor: 21
Reporter assigment operator 21
Reporter Destructor 21
Reporter Constructor: 22
Reporter assigment operator 22
Reporter Destructor 22
Reporter Constructor: 23
Reporter assigment operator 23
Reporter Destructor 23
Reporter Constructor: 24
Reporter assigment operator 24
Reporter Destructor 24
Reporter Constructor: 30
Reporter Constructor: 31
Reporter Constructor: 32
Reporter Constructor: 33
Reporter Constructor: 34
Reporter Destructor 30
Reporter Destructor 31
Reporter Destructor 32
Reporter Destructor 33
Reporter Destructor 34
Reporter Destructor 15
Reporter Destructor 14
Reporter Destructor 13
Reporter Destructor 12
Reporter Destructor 11