I have a C++ program where the new
operator is overloaded. The problem is that
if my allocation in the new
operator fails, I'm still calling the constructor.
I know I can avoid this by throwing std::bad_alloc
, but I don't want to do that.
How can I fail in my overloaded new
operator and still not call my constructor?
Essentially I want to implement something like new (std::nothrow)
.
Here's an example to illustrate what I mean. Note that the system I'm testing
on has no memory protection. So accessing NULL
doesn't do anything
Example 1 : Overloaded new operator
#include <stdio.h>
#include <stdlib.h>
#include <memory>
class Test {
public:
Test(void) {
printf("Test constructor\n");
}
void print(void) {
printf("this: %p\n", this);
}
void* operator new(size_t size, unsigned int extra) {
void* ptr = malloc(size + extra);
ptr = NULL; // For testing purposes
if (ptr == NULL) {
// ?
}
return ptr;
}
};
int main(void) {
Test* t = new (1) Test;
t->print();
printf("t: %p\n", t);
return 0;
}
The ouput for this is:
$ ./a.out
Test constructor
this: 00000000
t: 00000000
Clearly the constrcutor is getting called when the new
failed.
Example 2 : Huge class declaration with new (std::nothrow)
#include <stdio.h>
#include <stdlib.h>
#include <memory>
class Test {
int x0[0x0fffffff];
int x1[0x0fffffff];
int x2[0x0fffffff];
int x3[0x0fffffff];
int x4[0x0fffffff];
int x5[0x0fffffff];
int x6[0x0fffffff];
int x7[0x0fffffff];
int x8[0x0fffffff];
int x9[0x0fffffff];
int xa[0x0fffffff];
int xb[0x0fffffff];
int xc[0x0fffffff];
int xd[0x0fffffff];
int xe[0x0fffffff];
int xf[0x0fffffff];
public:
Test(void) {
printf("Test constructor\n");
}
void print(void) {
printf("this: %p\n", this);
}
};
int main(void) {
Test* t = new (std::nothrow) Test;
t->print();
printf("t: %p\n", t);
return 0;
}
The ouput for this is:
this: 00000000
t: 00000000
Clearly the constrcutor is not getting called when the new
failed.
So how do I implement new (std::nothrow)
kind of functionality in my
overloaded new
operator?
Whether the compiler checks for a null pointer after calling
operator new
or not, before calling the destructor, depends on
whether the allocator function has a non-throwing exception
specification or not. If not, the compiler assumes that
operator new
will throw if no memory is available. Otherwise,
it assumes that operator new
will return a null pointer. In
your case, your operator new
should be:
void* operator new( size_t size, unsigned int extra ) throw()
{
//...
}
or if you can count on C++11 support:
void* operator new( size_t size, unsigned int extra) noexcept
{
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With