Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading the nothrow Version of new and delete

Tags:

c++

See the following code:

#include<iostream>
#include<stdlib.h>
#include<new>

using namespace std;


class ex
{
     int x;
public:
     ex():ex(0){}
     ex(int x):x(x)
     {
     //cout<<"\nConstructor";
     }


 void *operator new(size_t siz)
 {
     void *p;
     cout<<"\nOverloaded new operator normal version";
     p=malloc(siz);
     if(p==NULL)
     {
         bad_alloc ba;
         throw ba;
     }
     else
        return p;
 }
 void operator delete(void *p,size_t sz)
 {
     cout<<"\nOverloaded delete normal version:"<<sz;
     free(p);
 }


 void *operator new(size_t siz,const nothrow_t &tag)
 {
     void *p;
     cout<<"\nOverloaded new operator nothrow version";
     p=malloc(siz);
     if(p==NULL)
     {
        return 0;
     }
     else
        return p;
 }
 void operator delete(void *p,const nothrow_t &tag)
 {
     cout<<"\nOverloaded delete nothrow version";
     free(p);
 }


 void *operator new[](size_t siz)
 {
     void *p;
     cout<<"\nOverloaded new operator normal version in array";
     p=malloc(siz);
     if(p==NULL)
     {
         bad_alloc ba;
         throw ba;
     }
     else
        return p;
 }
 void operator delete[](void *p,size_t sz)
 {
     cout<<"\nOverloaded delete normal version in array:"<<sz;
     free(p);
 }


 void *operator new[](size_t siz,const nothrow_t &tag)
 {
     void *p;
     cout<<"\nOverloaded new operator nothrow version in array";
     p=malloc(siz);
     if(p==NULL)
     {
         return 0;
     }
     else
        return p;
 }
 void operator delete[](void *p,const nothrow_t &tag)
 {
     cout<<"\nOverloaded delete nothrow version in array";
     free(p);
 }

};


int main()
{
ex *pt;

pt=new ex;
delete pt;

pt=new ex[10];
delete[] pt;

pt=new(nothrow) ex;
delete pt;

pt=new(nothrow) ex[10];
delete[] pt;
}

output for above code:

  Overloaded new operator normal version
  Overloaded delete normal version:4
  Overloaded new operator normal version in array
  Overloaded delete normal version in array:44
  Overloaded new operator nothrow version
  Overloaded delete normal version:4
  Overloaded new operator nothrow version in array
  Overloaded delete normal version in array:44
  Process returned 0 (0x0)   execution time : 0.724 s
  Press any key to continue.

My question is :

1)Why nothrow version of delete is not called.

2)can i use size parameter in nothrow version of delete. like

  void operator delete[](void *p,const nothrow_t &tag,size_t sz);

  or

  void operator delete(void *p,const nothrow_t &tag,size_t sz);

3)What is use of nothrow version of delete.

4)I used same code in both version new and new[] , delete and delete[] but one is normal variable and another one is array variable how this ?.

5)The compiler gives warning : 'operator new' must not return NULL unless it is declared 'throw()' (or -fcheck-new is in effect) How to over come that?

like image 840
srilakshmikanthanp Avatar asked Oct 27 '25 05:10

srilakshmikanthanp


2 Answers

The default behavoir of new

C++ throws bad_alloc exception on failing new unless you explicitly call new(std::nothrow).

This is not affected by the question of whether or not the user overloaded operator new.

Thus, when you call new without passing std::nothrow you will not reach the nothrow version. Even if you overloaded one.


new(nothrow)

Note that your nothrow version does throw, which is not the way to go. It is supposed to look like:

void* operator new(size_t size, const nothrow_t& tag) noexcept
{
     void* p = malloc(size);
     return p; // don't throw from the nothrow version of new
}

This however wouldn't change the behavior explained: to reach the nothrow version of new you must call it explicitly as you indeed see in your code.


Disabling exceptions

There are compilers which allow "disabling" exceptions, e.g. the flag --exceptions in gcc. This is compiler dependent but in most cases, if not all - putting aside old versions of MSVC - disabling exceptions do not cause exceptions not to be thrown but only make the compiler assume they wouldn't be thrown, and a call to new would still throw if it fails.

See: What exactly will happen if I disable C++ exceptions in a project?

gcc example: http://coliru.stacked-crooked.com/a/daa465731e56c681


Relevant SO questions:

  • Will new return NULL in any case?
  • Will new operator return NULL?
  • Why doesn't new in C++ return NULL on failure

Can also be a good read:

  • Herb Sutter on the new operator - part 1
  • Herb Sutter on the new operator - part 2

operator delete

The delete operator should never throw an exception. Both versions of it, the nothrow and the normal (non-nothrow).

So what is the usage of the nothrow version of operator delete?

If new was called to allocate an object, memory was successfully allocated but then the constructor of this object threw an exception, the new operation shall fail, propagating the exception thrown by the constructor. But before that there is a need to deallocate the memory obtained. This is done automatically by calling the delete operator. If the new which just failed was the nothrow version then the delete operator to be called would be the nothrow one, otherwise it would be the normal one. Note that both versions of the delete operator do not and should not throw. Also note that you cannot call the nothrow version of the delete operator on your own! But you can create a scenario in which it would be called.

Example:

struct A {
    A() {
        throw "bahh";
    }
};

void operator delete(void* ptr) noexcept {
    std::cout << "normal delete" << std::endl;
    free(ptr);
}

void operator delete(void* ptr, const std::nothrow_t&) noexcept {
    std::cout << "nothrow delete" << std::endl;
    free(ptr);
}

int main() {
    std::cout << "calling new A" << std::endl;    
    try {
        new A(); // prints: normal delete
    }
    catch(const char* s) {
        std::cout << s << std::endl; // bahh
    }

    std::cout << "calling new(std::nothrow) A" << std::endl;    
    try {
        new(std::nothrow) A(); // prints: nothrow delete
    }
    catch(const char* s) {
        std::cout << s << std::endl; // bahh
    }
}

Code: http://coliru.stacked-crooked.com/a/7be9ce12d251b033

See:

  • https://en.cppreference.com/w/cpp/memory/new/operator_delete
  • C++ can operator delete fails and if not why?
like image 66
Amir Kirsh Avatar answered Oct 29 '25 18:10

Amir Kirsh


If you haven't already, you should look at the cppreference page for operator delete, as already mentioned.

Notice that 'standard' sized delete operators are

  1. only available in C++14 and later and
  2. only for the 'usual operators' (that is, the ones at global scope).

For completeness, C++17 has added a set of overloads to new and delete for overaligned memory. I haven't yet looked at the C++20 destroying delete overloads.

It doesn't make much sense to have a class-specific sized delete overload as you can easily access the size of the object (with sizeof ex). Well, maybe for the array version there could be some use.

You can always explicitly call your overloads, e.g., something like

ex::operator delete(pt, foo);
like image 31
Paul Floyd Avatar answered Oct 29 '25 20:10

Paul Floyd