Back to TILs

C++ handling error on new

Date: 2023-02-15Last modified: 2024-02-26

Table of contents

How new works

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

References