Can I change the value that returned from new operator???

oky
oky used Ask the Experts™
on
Assume that you have an OBJECT and its constructor allcoates a memory.
How can I let new operator return NULL, if the memory allcoation inside the constructor of OBJECT fails.

OBJECT::OBJECT(bufferSize)
{
  buffer = new double[bufferSize]; //This fails!
}

OBJECT * obj;
obj =new OBJECT( HUGE_NUMBER); // If constructor of OBJECT decides that there is an error this 'new' must return NULL.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
Try doing all your failure prone stuff in your custom written operator new.
EOL

Commented:
Whatever you do, writing an own new is almost all the time a bad idea.

If you want to introduce error handling on new, you'v to catch the bad_alloc exeption anyway. Because if you don't your programm will crash, whatsoever new returns.

You'v two choices. Either you can test for a bad allocation in your object, so the expection of new don get propagated to the outside world, or you catch the propagated new from the allocation of your OBJECT.

example 1:

class OBJECT
{
public:
     OBJECT( int size )
     try
     {
          int *i = new int[size];
          delete []i;
     }
     catch( bad_alloc xa )
     {
          cout << "The world is bad, therefore:" << xa.what() << endl;
     }
};

example 2:

class OBJECT
{
public:
     OBJECT( int size )
     {
          int *i = new int[size];
          delete []i;
     }
};

int main(int argc, char* argv[])
{
     try
     {
          Test* t = new Test(1000000000);
     }
     catch(bad_alloc xa)
     {
          cout << "The world is bad, therefore:" << xa.what() << endl;
     }
}

Whith that you'r on the save side.
EOL

Commented:
Altough, the first example has some caveats you might discover later ( as far as I remember behavior of new is not garanted if you have a throw inside of the constructor of an object ).

Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

Commented:
that's what exceptions are for.
Besides, if the allocation fails, you'll get a null pointer since double is a basic data type.
if the allocation fails, it is not guaranteed that u will get a null pointer, it is dependent on the implementation. though usually the case for basic data types, because they are initialized to zero... it is not safe...

if u want to get a null pointer if allocation fails, u have to do this...

#include <new>
T* p = new (nothrow()) T;
if (!p) return NULL;
oky

Author

Commented:
Although the allocation in constructor fails, the creation of OBJECT will still seem OK to the user who tries to create instance of OBJECT. The user can check this situation after the creation of OBJECT somehow. But I thought there might be an automatic way to tell the user that something went wrong in the constructor during creation of object by returning NULL from 'new'. Do I want so much???
EOL

Commented:
@CoolBreeze

#include <new>
T* p = new (nothrow()) T;
if (!p) return NULL;

Isn't this also unsave, because new isn't guaranteed to deliver zero in case of failure?

Don't you also assume that memory is initialzied with zero, which it isn't depending on optimization settings of the compiler?
ok i get ur point

consider this:

#include <iostream>
#include <new>
using namespace std;

class A {
  public:
    double* buffer;
    A() {  
      buffer = new(nothrow()) double[bufferSize]; //This fails    
    }
    void* operator new(unsigned int size) {
      if (buffer) {
        return ::new A;
      } else {
        return (void*)NULL;
      }
    }
};

int main() {
  A* a;
  a = new A();
  if (a) cout << "Ok" << endl; else cout << "Not Ok" << endl;
  return 1;
}
EOL, my above implementation guarantees a null when allocation fails. it is asking new to use a different implementation which instead of an exception returns NULL. it is not based on the compiler settings.
EOL

Commented:
@ oky

Yes, you'r asking for much since:
-C++ isn't a script language which takes most burdens of your shoulders.

-Allocation of memory directly triggers operations of the kernl and the memory mapper ( hardwareimplementation )

-The exception facilities handle the problem just nice.

-Using new and delete isn't supposed to be a task you trow in at random. If and when you do you must carefully consider it and whenever possible let it be.

-There are pefect facilities to handle dynamic amounts of data ( see STL ) where allocation is in the hands of a mighty library that knows what it does.
EOL

Commented:
CoolBreeze
I didn't know that this triggers a completely different new verions. Good to know tough, thx.

Commented:
If you are using Visual Studio, new will NEVER throw bad_alloc exception. Am I right? If new fails, it will return NULL.

You have to ask yourself how you wanna deal with memory allocation failure. Do you want to terminate your application? Do you wanna deallocate some objects you have allocated earlier? You either throw an exeption 'upwards' in your constructor and let some mechanism take care of the allocation failure or you can simply add a member function return the objects stat.

Before new fails, C++ can try to 'free' some memory first and this operation could be non-deterministic? I have a vague memory of reading that in Scott Meyer's More Effective C++?  

Commented:
hi @all,
if im not completely wrong,
the constructor of an object is called after new returned successfully.
the memory for the object is always allocated before the constructor is called, because you must have the possibility to access member variables in the constructor as well as the object was declared as a static variable.
thus, whatever you do in the constructor, it will never be possible to check if construction was successfully in the new operator.
to check this, employ the debugger with breakpoints in new and the constructor.

at least, this is in ms vc++ 6.

doc nick

Commented:
The C++ way of notifying the user that something went wrong in a constructor is throwing an exception.

struct MyException { /*...*/ };

class MyClass {
public:
    MyClass() {
        // ...
        if (something_catastrophic_happened)
            throw MyException();
    }
};

int main() {
    try {
        MyClass obj;
        // ...
        return 0;
    }
    catch (MyException& ex) { // Your exceptions
        // ...
    }
    catch (std::exception& ex) { // Standard exceptions
        // ...
    }
    catch (...) { // Everything else
        // ...
    }
    return 1;
}

Unfortunately, as posted above, VC6 does not throw an exception on failure, so you need to check for it returning 0 if you want to be portable to that platform.
yes drnick, i must apologize, as i was in a rush, i overlooked this point in my code
ok, now is a tested version:

#include <iostream>
#include <new>
using namespace std;

class A {
 public:
   char* buffer;
   A() {      
   }
   void* operator new(unsigned int size) {
     char* p = NULL;
     p = new(nothrow) char[4096]; //This fails
     if (p) {
       A* q = ::new A;
       q->buffer = p;      
       return q;
     } else {
       return (void*)NULL;
     }
   }
};

int main() {
 A* a;
 a = new A();
 if (a) cout << "Ok" << endl; else cout << "Not Ok" << endl;
 a->buffer = "Test"; // try assigning to buffer, will raise an error if
                     // Not Ok
 cout << a->buffer << endl;
 return 1;
}

Commented:
wait.. what if A *q ::new A fails?

oh yeah, then let's do
A* q = ::new(nothrow) A;

then if it fails, it will also return NULL

Commented:
nooo, now you are doing it too easy for you CoolMan.

If p was allocated but not q, you have to delete p before return NULL and A *q = ::new (nothrow) A; wouldn't help in the aftercoming sentence q->buffer = p.  We want the complete code please.

oops, thought we not supposed to be so obvious? hmm... pple had always been teaching me to stimulate thinking on the questioner side
#include <iostream>
#include <new>
using namespace std;

class A {
 public:
   char* buffer;
   A() {      
   }
   void* operator new(unsigned int size) {
     char* p = NULL;
     p = ::new(nothrow) char[4096]; //This fails
     if (p) {
       A* q = NULL;
       q = ::new(nothrow) A;
       if (q) {
         q->buffer = p;
       } else {
         delete[] p;
       }
       return q;
     } else {
       return (void*)NULL;
     }
   }
};

int main() {
 A* a;
 a = new A();
 if (a) cout << "Ok" << endl; else cout << "Not Ok" << endl;
 a->buffer = "Test"; // try assigning to buffer, will raise an error if
                     // Not Ok
 cout << a->buffer << endl;
 return 1;
}


ok, the process:
we have a = new A(); which will call the operator new of A.
inside operator new, we create a char pointer p. then we try to allocate a memory to p. if the allocation is successful, p is given an address, if not, it will contain NULL.

if p contains NULL, we dun have to delete[] p. so far so good, we dun have any dangling variables. so we test that p is not NULL, and if it is not, we creates a pointer q and try to allocate memory for it. if allocation fails, q is NULL, and we dun have to delete[] q. if allocation succeed, we assign the address of buffer to p, else if it fails it means we won't have an A object. so we have to deallocate what we had allocated which is p. after that we return p which will tell the user whether the object is allocated or not

Commented:
I have no brain. :)

So what happens if you want to use A like this?

A a;

or

A a[10];

or suppose you have to initialize some member variables in your constructor:

A(int size)

that doesn't work either.

Since you cannot overload new operator, I think the solution is too specialized.  You can overload operator new as CoolBreeze has shown us. But operator new is only responsible for allocating memory. new operator uses operator new to allocate memory, but it calls the constructor as well. And if you declare your own new operator, you should declare own delete as well.

It is a nightmare


man, Kimpan, u are good and i like it. stimulates my mind :D

if u use A like this:

A a;

or

A a[10];

y it doesn't work? of course if u want to use it this way, u will have to add the following line in the constructor

if (!buffer) buffer = new(nothrow) char[4096];

but then again that defeats the purpose of his original question isn't it? by using A like this, there is a mutual understanding between the compiler and u that a must exist. and since a must exist, there's no way that a can be NULL too.

>or suppose you have to initialize some member variables >in your constructor:

>A(int size)

why not? just add the appropriate constructor and u will have it?

>Since you cannot overload new operator, I think the solution is too specialized

why can't we overload new operator? it is used too, why not? though i agree that it may be a little too specialized
oh well, i get ur point, sorry

Commented:
hmmm... don't be sorry. I don't want you to. Let us just discuss.

if you add buffer allocation in the constructor for the case A a or A a[10], you can't possibly know that allocation failed because constructors do not return any value?

About the A(int size) part:

if you have your allocation in operator new, would this compile?

A *a = new A(10)


new operator can't be overloaded. operator new can be. This I know with certainty.
where did u get the new operator thingy?

of course it will compile if u add the appropriate constructor, though it will not work the way i wanted. that's y i say sorry.
like i said, by using A a or A a[10], u are like using any other classes, u won't noe that allocation failed, and this point i agree with u.

Commented:
hmmm

Suppose you have two constructors then

A()
A(int number)

and you overload the operator new once more so you have:

void *operator new(unsigned int size)
void* operator new(unsigned int size, int number)


and you write

A *a, *b, *c, *d;

a = new A(10)
b = new A();
c = new(1) A();
d = new(1) A(10);


Which new operator and constructor will be invoked in each case and what value will number have in the constructor?


a = new A(10) should call A(int number) constructor right? Because that is what the built-in new operator does. But with your operator new overloading, new suddenly works differently and that make me worry.

about new operator thingy. In Scott Meyer's Effective C++ or More Effective C++, he explains the difference between 'new operator' and 'operator new'. As I wrote earlier. You can overload 'operator new' which is responsible for allocating memory. But you cannot overload 'new operator' which besides allocating memory using 'operator new' is responsible for calling the constructor. There was other things as well that 'operator new' does which you cannot do in your own code. I've forgot what. I will look into it if someone is interested. But eeh, let us just end this story. It takes too much effort!




would be happy if u could provide the difference between the two here :)
fyi, the definition of operator new is this

void* operator new(unsigned int size)

so even if u provide

void* operator new(unsigned int size, int number)

it wouldn't be used

Commented:
ok I will read that book tonight. Or even better, I will send you a copy of the book. Give me your name, address and VISA card number. VISA card number is only for security purposes since the book is X-rated. I promise.
heh heh, dunno y i make the above comments, i was wrong :(
found a quotation from the book:

Operator new is called by the new operator to allocate memory for the object being created
found a quotation from the book:

Operator new is called by the new operator to allocate memory for the object being created
u noe i found out that u can do something like this:

delete[] this;

in the constructor. do u noe if this is allowed? because if it is we can do this:

class A {
  public:
    char* buffer;
    A(int buffersize) {
      buffer = new(nothrow) char[buffersize];
      if (!buffer) delete[] this;
    }
    void delete(void* ptr) {
      ::delete[] ptr;
      void** temp = &ptr;
      *temp = NULL;
    }
};

Commented:
So we agree that 'new operator' and 'operator new' is not the same thing.

You evil man! delete[] this in the constructor?!

You are giving me headache!
Commented:
oky, why don't you want to use exceptions?  They were created exactly for this purpose!

See http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.2
one thing wanted to ask u, is Effective C++ good?

Commented:
>> delete[] this in the constructor?!

?! indeed.

delete[] is used for arrays of objects, this is never an array.

Commented:
They are really REALLY good.. read them
yes, indeed, alexo
and i noe that it is not safe to do this in the constructor or anywhere else, but i'm just curious that they actually allowed this.
EOL

Commented:
On a sidemark, VC7 does throw the bad_alloc exeption, M$ finaly managed to read the standard.

Commented:
oh great! I have installed VS7 on my machine but haven't worked with yet since I went a course using C# in .NET, so I have a question:

Your projects/code written in VS6 C++, will it easily be 'ported' to VS7 C++?

Commented:
>> and i noe that it is not safe to do this in the constructor or anywhere else

"delete this" is not safe in the ctor because the object has not been constructed yet.  Also not safe in the dtor (obviously).  It can be used in other places as long as the object is not accessed after it.
EOL

Commented:
@Kimpan

Yes it is relatively easy to migrate, unless of course you programmed VC6 specific bug workarounds that aren't in the standard. Such workarounds sadly include catching the right bad_alloc now, several issues with templates, and the "for" scooping bug is gone. I am sure that there nearly endless special cases, but those topics are the most frequent I think.

So there might quite well be some legacy code around.
VC7 is much closer to the standard then VC6.

Commented:
But not standard completly.. hmm maybe I should go over to C# instead. Cause standard there would be what Microsoft has dictated.. lol

Commented:
>> VC7 is much closer to the standard then VC6.
http://www.comeaucomputing.com/
oky

Author

Commented:
Hi guys,
Thanks for all your effort.
It seems like throwing an exception is simpler and safer rather than overloading operator new or other ways.

Commented:
yes, that is indeed. :)
EOL

Commented:
As I stated right from the start.

Commented:
You are so cool EOL you hardcore gameprogramming freak ;)
EOL

Commented:
I am too stupid to programm, that's why I hang around in a place where all the smart people are crowding, helps me feel better about my miserable life.

Commented:
I wish I had a miserable life even. I envy you. :)

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial