#include 
#include 
#include 


namespace  {
    class Foo {};

    static const std::align_val_t MEMORY_ALIGNMENT_DEFAULT = std::align_val_t(alignof(std::max_align_t));
    static const size_t MEMORY_HEADER_SIZE = 8;
    
    void* alloc(size_t size, std::align_val_t align) {
        // This allocator allocates memory that has header region to deallocate only my dealloc function.
        void* memory = nullptr;
        size_t total_size = size + MEMORY_HEADER_SIZE;
        memory = malloc(total_size);
        if (!memory) {
            throw std::bad_alloc();
        }
        void* aligned_memory = static_cast(memory) + MEMORY_HEADER_SIZE;
        uintptr_t addr = reinterpret_cast(aligned_memory);
        uintptr_t aligned_addr = (addr + static_cast(align) - 1) &amp; ~(static_cast(align) - 1);
        *reinterpret_cast(memory) = size;
        printf(&#34;Allocated memory at: %p with size: %zu\n&#34;, reinterpret_cast(aligned_addr), size);
        return reinterpret_cast(aligned_addr);
    }

    void dealloc(void* p) {
        // This dealloc function assumes that the pointer was allocated with my alloc function.
        if (p) {
            size_t* header = reinterpret_cast(static_cast(p) - MEMORY_HEADER_SIZE);
            size_t size = *header;
            printf(&#34;Deallocating memory at: %p with size: %zu\n&#34;, p, size);
            free(header);
        }
    }
}

// ============================================================================
// overriding global new/delete in C++17
void* operator new(size_t size) { return alloc(size, MEMORY_ALIGNMENT_DEFAULT); }
void* operator new(size_t size, std::align_val_t alignment) { return alloc(size, alignment); }
void* operator new(size_t size, const std::nothrow_t&amp;) noexcept { return alloc(size, MEMORY_ALIGNMENT_DEFAULT); };
void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&amp;) noexcept { return alloc(size, alignment); }

void* operator new[](std::size_t size) { return alloc(size, MEMORY_ALIGNMENT_DEFAULT); }
void* operator new[](size_t size, std::align_val_t alignment) { return alloc(size, alignment); }
void* operator new[](size_t size, const std::nothrow_t&amp;) noexcept { return alloc(size, MEMORY_ALIGNMENT_DEFAULT); }
void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&amp;) noexcept { return alloc(size, alignment); }

void operator delete(void* ptr) noexcept { dealloc(ptr); }
void operator delete(void* ptr, std::size_t size) noexcept {
    if (size == 0) {
        return;
    }
    dealloc(ptr);
}
void operator delete(void* ptr, std::align_val_t alignment) noexcept { dealloc(ptr); }
void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept {
    if (size == 0) {
        return;
    }
    dealloc(ptr);
}
void operator delete(void* ptr, const std::nothrow_t&amp;) noexcept { dealloc(ptr); }
void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&amp;) noexcept { dealloc(ptr); }

void operator delete[](void* ptr) noexcept { dealloc(ptr); }
void operator delete[](void* ptr, std::size_t size) noexcept {
    if (size == 0) {
        return;
    }
    dealloc(ptr);
}
void operator delete[](void* ptr, std::align_val_t alignment) noexcept { dealloc(ptr); }
void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept {
    if (size == 0) {
        return;
    }
    dealloc(ptr);
}
void operator delete[](void* ptr, const std::nothrow_t&amp;) noexcept { dealloc(ptr); }
void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&amp;) noexcept { dealloc(ptr); }
// ============================================================================



int main(int argc, char * argv[]) {
    printf(&#34;==== Start Main Function ===\n&#34;);
    {
        printf(&#34;==== Start Memory Allocation ====\n&#34;);
        Foo* foo = new Foo();
        delete foo; // NO crash here.
        printf(&#34;==== End Memory Allocation ====\n&#34;);

        printf(&#34;==== Start String Allocation ====\n&#34;);
        ::std::string* str_ = new ::std::string(&#34;Hello, World!&#34;);
        delete str_; // No crash here.
        printf(&#34;==== End String Allocation ====\n&#34;);

        printf(&#34;==== Start Memory Stream ====\n&#34;);
        ::std::stringstream* ss_ = new ::std::stringstream();
        delete ss_; // CRASH here because default delete is called.
        printf(&#34;==== End Memory Stream ====\n&#34;);

    }
    printf(&#34;==== End Main Function ===\n&#34;);
    return 0;
}
